Just getting started on a new mobile based project and have a screen with 16 cards on it, each instantiated from a prefab “Card”, they all have 2D box collider on them as well and a script.
The script is very simple and I just want to detect a touch collision and print out the name of the card for now, the problem is if I touch one of the cards all 16 of them fire and report back their names. I have tried a few different scripts that I found using RaycastHit2D, the latest one I tried was:
void Update () {
for (int i = 0; i < Input.touchCount; ++i) {
if (Input.GetTouch(i).phase == TouchPhase.Began) {
touchPosWorld = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
Vector2 touchPosWorld2D = new Vector2(touchPosWorld.x, touchPosWorld.y);
RaycastHit2D hitInformation = Physics2D.Raycast(touchPosWorld2D, Camera.main.transform.forward);
if (hitInformation.collider != null) {
GameObject touchedObject = hitInformation.transform.gameObject;
Debug.Log("Touched " + touchedObject.transform.name);
}
}
}
}
I can’t figure out why this is firing on all 16 objects and not just the one that is being touched, any help would be appreciated.
Well, it’s a common mistake.
If you attach this script to several objects, they’ll all fire the same raycast. No matter if they’re the ones being tapped on or not.
You could avoid that by testing whether or not the behaviour instance belongs to the object that has been tapped on, but that’s a dirty way.
You should rather cast the ray once in something like an InputManager and track the object that has been tapped on, invoke an event on it e.g. OnTap(…). This is not only a cleaner way, it additionally avoids unnecessary raycasts.
It also allows to add several InputModules, which can be prioritized, activated/deactivated on a per-platform basis and all that stuff.
Another solution would be to use Unity’s event system, which you have to set up to work with 2D/3D physics objects. It’s a neat way to decouple your code as well.