Search code examples
c#inputcollision-detectionunity-game-engine

Detecting input collision on overlapping 2D objects in Unity


I'm developing an app that has many balls that float around but do not collide with each other. This means they overlap a lot. I've got it so if you click/touch the balls, they are destroyed. However, if one ball is behind another, this one is not destroyed until the one in front is cleared.

enter image description here

The above diagram shows what I'm looking for, if the user clicks/touches at position x, then destroy all the objects, not just the most forward of them. Any help much appreciated.

Here's my input script:

 using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TouchInput : MonoBehaviour {

    public LayerMask touchInputMask;
    private List<GameObject> touchList = new List<GameObject> ();
    private GameObject[] touchesOld;
    private RaycastHit2D hit;

    void Update () {


#if UNITY_EDITOR

        if (Input.GetMouseButton(0) || Input.GetMouseButtonDown(0) || Input.GetMouseButtonUp(0)) {

            touchesOld = new GameObject[touchList.Count];
            touchList.CopyTo (touchesOld);
            touchList.Clear ();


            hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, touchInputMask);
            //Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);

            if (hit) {

                GameObject recipient = hit.transform.gameObject;
                touchList.Add (recipient);

                if (Input.GetMouseButtonDown(0)) {
                    recipient.SendMessage ("OnTouchDown",hit.point,SendMessageOptions.DontRequireReceiver);

                }
                if (Input.GetMouseButtonUp(0)) {
                    recipient.SendMessage ("OnTouchUp",hit.point,SendMessageOptions.DontRequireReceiver);

                }
                if (Input.GetMouseButton(0)) {
                    recipient.SendMessage ("OnTouchStay",hit.point,SendMessageOptions.DontRequireReceiver);

                }

            }

            foreach (GameObject g in touchesOld) {
                if (!touchList.Contains (g)) {
                    if(g!=null) {
                        g.SendMessage ("OnTouchExit", hit.point, SendMessageOptions.DontRequireReceiver);
                    }

                }
            }

        }

#endif

        if (Input.touchCount > 0) {

            touchesOld = new GameObject[touchList.Count];
            touchList.CopyTo (touchesOld);
            touchList.Clear ();

            foreach (Touch touch in Input.touches) {

                hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, touchInputMask);

                if (hit) {

                    GameObject recipient = hit.transform.gameObject;
                    touchList.Add (recipient);

                    if (touch.phase == TouchPhase.Began) {
                        recipient.SendMessage ("OnTouchDown",hit.point,SendMessageOptions.DontRequireReceiver);

                    }
                    if (touch.phase == TouchPhase.Ended) {
                        recipient.SendMessage ("OnTouchUp",hit.point,SendMessageOptions.DontRequireReceiver);

                    }
                    if (touch.phase == TouchPhase.Stationary) {
                        recipient.SendMessage ("OnTouchStay",hit.point,SendMessageOptions.DontRequireReceiver);

                    }
                    if (touch.phase == TouchPhase.Canceled) {
                        recipient.SendMessage ("OnTouchExit",hit.point,SendMessageOptions.DontRequireReceiver);

                    }

                }

            }

            foreach (GameObject g in touchesOld) {
                if (!touchList.Contains (g)) {
                    if (g != null) {
                        g.SendMessage ("OnTouchExit", hit.point, SendMessageOptions.DontRequireReceiver);
                    }

                }
            }

        }

    }
}

And on the ball I simply have a:

    void OnTouchDown() {

    KillBall ();
}

void OnTouchStay() {

    KillBall ();

}

Solution

  • Answer provided by @Savlon, so thanks for that :)

    private RaycastHit2D[] hits;
    

    ...

    hits = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, touchInputMask);
    
            foreach(RaycastHit2D hit in hits) {
    
                GameObject recipient = hit.transform.gameObject;
                touchList.Add (recipient);
    
                if (Input.GetMouseButtonDown(0)) {
                    recipient.SendMessage ("OnTouchDown",hit.point,SendMessageOptions.DontRequireReceiver);
    
                }
                if (Input.GetMouseButtonUp(0)) {
                    recipient.SendMessage ("OnTouchUp",hit.point,SendMessageOptions.DontRequireReceiver);
    
                }
                if (Input.GetMouseButton(0)) {
                    recipient.SendMessage ("OnTouch",hit.point,SendMessageOptions.DontRequireReceiver);
    
                }
    
    
            }