0
\$\begingroup\$

I've been writing a system where, if a raycast hits a 2D gameObject, a UnityEvent is fired and the Shot() method is executed. It works fine if the amount of listeners receiving the callback is equal to one, in this situation it destroys only clicked GameObject (which is what I need). As soon as you add another callback (AudioSource, Playing Particles), it destroys all GameObjects, which I don't want to be destroyed.

Class with Event:

public class ItemRaycastHit :  MonoBehaviour
{
    [SerializeField] private UnityEvent _shot;
    void Update()
    {
        if(Input.GetMouseButtonDown(0)) 
        {
            Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); 
            RaycastHit2D hit = Physics2D.Raycast(mousePos, Vector2.zero); 
            if (hit.collider.TryGetComponent<ClickableObject>(out ClickableObject clickable)) 
            {
                _shot?.Invoke();
            }
        }
    }
}

public class ClickableObject : MonoBehaviour
{
    public void Shot()
    {
        Destroy(gameObject);
    }
}

Image of the clickable object in inspector

Inspector screenshot

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I notice that nowhere in this code do you tell the shot event which object you clicked. Did you mean to call Shot() only on the variable clickable representing the one object you clicked (ie clickable.Shot()), rather than on every clickable object subscribed to the _shot event? \$\endgroup\$
    – DMGregory
    Jul 20 at 23:54
  • \$\begingroup\$ Yes I need to call Shot() only on the clickable variable \$\endgroup\$
    – koogel
    Jul 21 at 5:14
0
\$\begingroup\$

That is how it works. I'm not sure why you want to do this? You have a collider there, so just use the OnMouseDown event manager instead of the Update. See the example on the Unity manual: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html

\$\endgroup\$
0
\$\begingroup\$

It looks like you wanted to write this:

public class ItemRaycastHit :  MonoBehaviour
{
    [SerializeField] private UnityEvent _shot;

    void Update()
    {
        if(Input.GetMouseButtonDown(0)) 
        {
            Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); 
            Collider2D hit = Physics2D.OverlapPoint(mousePos); 
            if (hit != null 
            && hit.TryGetComponent<ClickableObject>(out ClickableObject clickable)) 
            {
                // Invoke the Shot method on *only* 
                // the one ClickableObject that we clicked on.
                clickable.Shot();

                // Use our event to notify anything *that is NOT*
                // a ClickableObject that might want to also respond.
                _shot?.Invoke();
            }
        }
    }
}

You can now remove your ClickableObjects from the list of listeners for the _shot event. We'll call their Shot() method directly when they're clicked. You can use the event to inform any third party that is not this script AND is not the object that was clicked.

I also changed your raycast code to an OverlapPoint check, since that expresses the intention more clearly than a raycast with no direction.

\$\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.