Best way to detect touch on a GameObject
I see there're a lot of questions regarding touch detection since ever. As Unity is changing constantly, I want to know what is the best solution to detect touches on a 2D Game Object with the latest version of Unity (5.3).
Im making a Candy Crush clone, and I want to use that touches to move the icons (candies, gems, whatever you want).
Answer by rob5300 · Jan 14, 2016 at 11:00 AM
I think the best way to achieve this would be using Raycasting, for this Specifically Physics2D.Raycast()
.
I don't have access to Unity right now, but from memory you should try something like this:
using UnityEngine;
using System.Collections;
public class RaycastTest : MonoBehaviour {
Vector3 touchPosWorld;
//Change me to change the touch phase used.
TouchPhase touchPhase = TouchPhase.Ended;
void Update() {
//We check if we have more than one touch happening.
//We also check if the first touches phase is Ended (that the finger was lifted)
if (Input.touchCount > 0 && Input.GetTouch(0).phase == touchPhase) {
//We transform the touch position into word space from screen space and store it.
touchPosWorld = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
Vector2 touchPosWorld2D = new Vector2(touchPosWorld.x, touchPosWorld.y);
//We now raycast with this information. If we have hit something we can process it.
RaycastHit2D hitInformation = Physics2D.Raycast(touchPosWorld2D, Camera.main.transform.forward);
if (hitInformation.collider != null) {
//We should have hit something with a 2D Physics collider!
GameObject touchedObject = hitInformation.transform.gameObject;
//touchedObject should be the object someone touched.
Debug.Log("Touched " + touchedObject.transform.name);
}
}
}
}
Again please check this works, as i cannot at the current time of writing. You can change touchPhase
to change the TouchPhase
used to detect a touch, link to the doc for this Enum is here. Check the documentation for Input.GetTouch() for more examples and information on how to get and use Touches.
You probably want to modify this to check if a touch begins and ends on the same object, but this is a good starting point for basic functionality.
Hope this helps!
Note: This can be slightly modified to suit for 3D gameobjects. If there are easier ways to achieve this please comment and correct me.
Tried that code and doesn't work :( Nevertheless, I want to know the best way, it doesn't matter if there's code, a link to a tutorial, or just "use raycast and 2d colliders". Right now I can do it using the $$anonymous$$ouse events, as they're mapped to touch. But I don't know if it's the best.
Just changed the code, tested and it worked for me. The object i tested on had a Box Collider 2D on it. You can really do it eathier way, but having a script on each object to allow them to be touchable is not very efficent.
Having One script that can detect many objects with colliders to me is a much better way. Please try this code out now and see if that works, and remember to change touchphase to suit your needs.
EDIT: This only detects when the finger is removed when over an object with a collider, for your purpose you want to check if the finger was initially touched over the object and is being dragged. Just use the different TouchPhases (Began and $$anonymous$$oved) to check this.
Answer by Kross_Demon · Apr 26, 2018 at 08:13 PM
Maybe Try this:
if (Input.touchCount == 1 && Input.GetTouch(0).phase == touchPhase) {
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * 100, Color.yellow, 100f);
if(Physics.Raycast(ray, out hit))
{
Debug.Log(hit.transform.name);
if (hit.collider != null) {
GameObject touchedObject = hit.transform.gameObject;
Debug.Log("Touched " + touchedObject.transform.name);
}
}
}
touchPhase is set to TouchPhase.Began
A combination from @rob5300 post and https://www.youtube.com/watch?v=0sFrDJKwsdM
Answer by elblogdelbeto · Jun 23, 2018 at 01:08 AM
better and easy way, just add box collider and a script with this event to your game object:
OnMouseUpAsButton() { }
Yeah , that's works for me . Sometimes I forget to take a step back and think simpler :) . Thanks
While this is the best answer, the collider should be the one that fits your solution.
Answer by frhilyana118 · Feb 10, 2020 at 09:14 AM
will the debug for raycast touch position response if i use mouse to click on the object during the game view in unity? because I'm trying to test out whether the raycast by touch position is working or not.
@frhilyana118 questions should be on comments, not answers
Answer by prakyath_unity · Nov 27, 2020 at 05:58 AM
#if !UNITY_EDITOR
if( Input.touchCount>0 )
{
foreach( Touch t in Input.touches )
{
Debug.LogError($"current touch {Input.touches}");
Debug.LogError($"touch count is {Input.touchCount}");
Vector3 touchPos = t.position;
if( t.phase==TouchPhase.Began )
{
Ray ray = Camera.main.ScreenPointToRay( touchPos );
RaycastHit2D hit = Physics2D.Raycast( ray.origin , ray.direction );
if( hit.collider!=null && hit.transform==transform )
{
Debug.Log($"Hit: {hit.transform.name}");
myOnMouseDown();
break;
}
}
}
}
#endif
I am using unity visual scripting, and trying to figure out how to translate the hit.transform == "transform" part into visual script, I put quotes on the part in question.
EDIT:
I actually thought I could do a call to a literal transform (none) but really I just had to check if the hit.transform wasn't null. So now it works, thanks for the nice simple architecture for this.