0
\$\begingroup\$

I have a use-case where I have an object with a Collider2D and a Kinematic RigidBody2D in order to do Kinematic movement.

However, I also want to be able to select/hover that object with a OnMouseDown/OnMouseEnter/etc, using a larger collider than I would use for the kinematic movement.

My current attempt at a solution is to have Physics-related scripts/rigidbody2d/collider2d as the top level game object, and to have a child object, with a larger collider2D which will respond to OnMouseX events.

enter image description here

enter image description here enter image description here

In order to ignore OnMouseX events on the parent, I'm putting it into its own user_ignore_raycasts layer (I need it as its own layer for the layer collision matrix). I'm also putting the child in its own user_use_raycasts layer.

I'm passing that into a script that sets MainCamera's event mask: enter image description here

using UnityEngine;
 
 
[RequireComponent(typeof(Camera))]
public class CameraEventMasker : MonoBehaviour
{
    [SerializeField]
    private LayerMask cameraEventMask;
 
    // Start is called before the first frame update
    void Awake()
    {
        GetComponent<Camera>().eventMask = cameraEventMask;
    }
}

What I notice is that OnMouseX events on the child will work IF the RigidBody2D on the parent is deleted...however, if the RigidBody2D is there, I won't receive any events. Anyone know why this is the case, and if there are other workarounds or solutions?

\$\endgroup\$
1
\$\begingroup\$

My 3d game objects often would have multiple colliders - one on the parent for selecting/clicking, and others on children for such things as vision (detecting enemies), for detecting range, etc.

For clicking/selecting I use Physics.Raycast.

Similarly this should work for your 2d project:

you write this script in your Update() function.

    if (Input.GetMouseButtonDown(0) || (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began))
    {
        Vector3 origin0 = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        RaycastHit2D hitn = Physics2D.Raycast(new Vector2(origin0.x, origin0.y), Vector2.zero, Mathf.Infinity, layerMask);

        if (hitn.collider != null)
        {
            Debug.Log("I clicked on: " + hitn.transform.name);
        }
    }

This script shoots 2D ray at mouse click (or touch) point and if it detects 2D collider, returns it.

Note the variable layerMask. You can create public variable layerMask and add to it layers which you want to be 'clickable' - other layers will be ignored. Thus you can have a game object with one 'clickable' 2d collider, and in children you can have as much colliders as you want doing other things - just put those children in other layer (or layers).

public LayerMask layerMask;  
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.