(source: ibin.co)
I have a BoxCollider2D component and a script attached to the black and red boxes. Each script with some things to happen in a OnMouseDown() function. The problem is if I click on the part of the orange box that overlaps the black one, the OnMouseDown() of the black box will be called but I want only the orange box function to be called.
How do you achieve this?
I don't think OnMouseDown is a great approach here. You can use 2D RayCast to only get the top most collider. You are going to have to account for sorting layer and sorting order on your own with this approach.
The trick to checking a single point in 2D is to not give the raycast direction as shown below with:
Physics2D.Raycast(touchPostion, Vector2.zero);
Here is an example I threw together that doesn't account for using sorting layers, just sorting order.
using UnityEngine;
public class RayCastMultiple : MonoBehaviour
{
//Current active camera
public Camera MainCamera;
// Use this for initialization
void Start ()
{
if(MainCamera == null)
Debug.LogError("No MainCamera");
}
// Update is called once per frame
void FixedUpdate ()
{
if(Input.GetMouseButtonDown(0))
{
var mouseSelection = CheckForObjectUnderMouse();
if(mouseSelection == null)
Debug.Log("nothing selected by mouse");
else
Debug.Log(mouseSelection.gameObject);
}
}
private GameObject CheckForObjectUnderMouse()
{
Vector2 touchPostion = MainCamera.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D[] allCollidersAtTouchPosition = Physics2D.RaycastAll(touchPostion, Vector2.zero);
SpriteRenderer closest = null; //Cache closest sprite reneder so we can assess sorting order
foreach(RaycastHit2D hit in allCollidersAtTouchPosition)
{
if(closest == null) // if there is no closest assigned, this must be the closest
{
closest = hit.collider.gameObject.GetComponent<SpriteRenderer>();
continue;
}
var hitSprite = hit.collider.gameObject.GetComponent<SpriteRenderer>();
if(hitSprite == null)
continue; //If the object has no sprite go on to the next hitobject
if(hitSprite.sortingOrder > closest.sortingOrder)
closest = hitSprite;
}
return closest != null ? closest.gameObject : null;
}
}
This is pretty much just a duplicate of my answer here: Game Dev Question