Click Manager for selection

Hi,

I’m trying to make a selection by click system which can Mixe UI and no UI element.
the first problem I solved was to know when a gameObject is “unclicked” by clicking somewhere else.

I did it this way.

1 - A Click Manager script which centralized the click input detection.

{
    public delegate void RightClickDelegate();
    public RightClickDelegate OnRightClick;

    public delegate void LeftClickDelegate();
    public LeftClickDelegate OnLeftClick;
    private void Update()
    {
        //click gauche
       
        if (Input.GetMouseButton(0))
        {  
            OnLeftClick?.Invoke();
        }
        //click droit
        if (Input.GetMouseButton(1))
        {
            OnRightClick?.Invoke();
        }
    }
}

Then a ClickMe script attached to gameObject than can be click.

public class ClickOnMe : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    [SerializeField] bool isUI = false;

    [SerializeField] public List<MonoBehaviour> RightClickScripts;
    public delegate void OnRightClickDelegate(bool trigger);
    public OnRightClickDelegate ListenThisOnRightClick;
   
    [SerializeField] public List<MonoBehaviour> LeftClickScripts;
    public delegate void OnLeftClickDelegate(bool trigger);
    public OnLeftClickDelegate ListenThisOnLeftClick;

    [SerializeField] public List<MonoBehaviour> OnMouseOverScripts;
    public delegate void OnMouseEnterDelegate();
    public OnMouseEnterDelegate ListenThisOnMouseEnter;

    public delegate void OnMouseExitDelegate();
    public OnMouseExitDelegate ListenThisOnMouseExit;

    bool RightClick = false;
    bool LeftClick = false;

    bool MouseOver = false;

    private ClickManager clickManager;
    private void OnEnable()
    {
        clickManager = FindObjectOfType<ClickManager>();
        if (clickManager != null)
        {
            clickManager.OnRightClick += RightClickMethode;
            clickManager.OnLeftClick += LeftClickMethode;
        }
    }

    private void OnDisable()
    {
        if (clickManager != null)
        {
            clickManager.OnRightClick -= RightClickMethode;
            clickManager.OnLeftClick -= LeftClickMethode;
        }
    }
   
    public void RightClickMethode()
    {
        if (MouseOver)
        {           
            EnableRightClickScripts(true);
            RightClick = true;
            Debug.Log("click on me : " + this.name + " right click");  
        }
        else
        {
            EnableRightClickScripts(false);
            RightClick = false;
        }

        if (!isUI)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity, this.gameObject.layer))
            {
                if (hit.transform == this.gameObject.transform)
                {
                    EnableRightClickScripts(true);
                    RightClick = true;
                    Debug.Log("click on me : " + this.name + " Right click");
                }
                else
                {
                    EnableRightClickScripts(false);
                    RightClick = false;
                }

            }
        }
        ListenThisOnRightClick?.Invoke(RightClick);
    }

    public void LeftClickMethode()
    {
        if (MouseOver)
        {
            EnableLeftClickScripts(true);
            LeftClick = true;
            Debug.Log("click on me : " + this.name + " left click");
        }
        else
        {
            EnableLeftClickScripts(false);
            LeftClick = false;
        }
        if (!isUI)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Debug.DrawRay(ray.origin, ray.direction * 100, Color.green, 2f);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity,this.gameObject.layer))
            {
                if (hit.transform == this.gameObject.transform)
                {
                    EnableLeftClickScripts(true);
                    LeftClick = true;
                    Debug.Log("click on me : " + this.name + " left click");
                }
                else
                {
                    EnableLeftClickScripts(false);
                    LeftClick = false;
                }
               
            }
        }
        ListenThisOnLeftClick?.Invoke(LeftClick);
    }
   
    public void EnableRightClickScripts(bool trigger)
    {
        foreach (MonoBehaviour script in RightClickScripts)
        {
            script.enabled = trigger;
        }
    }

    public void EnableLeftClickScripts(bool trigger)
    {
        foreach (MonoBehaviour script in LeftClickScripts)
        {
            script.enabled = trigger;
        }
    }
   

    public void OnPointerEnter(PointerEventData data)
    {
        MouseOver = true;
        Debug.Log(this.transform.name);
        Debug.Log("Mouse Enter");
        foreach (MonoBehaviour script in OnMouseOverScripts)
        {
            script.enabled = true;
        }
        ListenThisOnMouseEnter?.Invoke();
    }

    public void OnPointerExit(PointerEventData data)
    {
        MouseOver = false;
        Debug.Log(this.transform.name);
        Debug.Log("Mouse Exit");

        foreach (MonoBehaviour script in OnMouseOverScripts)
        {
            bool MustBeDesable = true;
            if (LeftClick)
            {
                foreach (MonoBehaviour script2 in LeftClickScripts)
                {
                    if (script == script2)
                    {
                        MustBeDesable = false;
                        break;
                    }
                }
            }
            if(RightClick)
            {
                foreach (MonoBehaviour script3 in RightClickScripts)
                {
                    if (script == script3)
                    {
                        MustBeDesable = false;
                        break;
                    }
                }
            }
           
            if (MustBeDesable)
            {
                script.enabled = false;
            }
        }
        ListenThisOnMouseExit?.Invoke();
    }
}

It work fine for UI Element but fo GameObject like monster in the scene it doesn’t work.

First problem the raycast doesn’t Hit my monster.
In the scene we can clearly see that the line is passing thru the monster.
PS: in the image not anymore because of the time to me to click on pause


When I check the hit it seem to hit nothing :

Second question, what could be a good may to check if the mouse is over for non UI elements?
Don’t want to Raycast at every frame and don’t know if OnPointerEnter / Exit wiil work on non UI elements :/.

For the monster there is a lot of component attached. There is alot of script, a animator, a RigidBody and a character Controller.
I also tryed to add different colldier with trigger check or not and nothing worked :frowning:

Thanks for your help, it seems I’m stuck for now.

I can see in your screenshot that you’re using gameObject.layer as the layermask for your raycast.
This is incorrect.
A layermask is a bit-shifted mask, whereas gameObject.layer is an integer layer.

you’re probably looking for 1 << gameObject.layer

Hooo yes it solve my problem thank you sooooo much :).
Just need to find a good way for MouseOver, could use some Idea :slight_smile:

If I add a canvas to the gameObject The OnPointerEnter / Exit are called, but it doesnt seem to be a good way to go…

For UI, you can get it from the EventSystem.
For GameObjects, you’ll just have to do a raycast every frame.

I finaly do it this way, on the clickManager I cast a ray at evry frame.
If I hit something with my onclickscript I call for enter or exit.

public class ClickManager : MonoBehaviour
{
    public delegate void RightClickDelegate();
    public RightClickDelegate OnRightClick;

    public delegate void LeftClickDelegate();
    public LeftClickDelegate OnLeftClick;

    private GameObject lastHit = null;
    private void Update()
    {
        //click gauche
       
        if (Input.GetMouseButton(0))
        {  
            OnLeftClick?.Invoke();
        }
        //click droit
        if (Input.GetMouseButton(1))
        {
            OnRightClick?.Invoke();
        }

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, Mathf.Infinity))
        {
            if (hit.transform.gameObject != lastHit)
            {
                if (lastHit != null)
                {
                    try
                    {
                        lastHit.GetComponent<ClickOnMe>().MouseExit();
                    }
                    catch
                    {
                        Debug.Log("New hit not interactible");
                    }
                   
                }
                lastHit = hit.transform.gameObject;
                lastHit.GetComponent<ClickOnMe>().MouseEnter();
            }
        }
        else
        {
            if (lastHit != null)
            {
                try
                {
                    lastHit.GetComponent<ClickOnMe>().MouseExit();
                }
                catch
                {
                    Debug.Log("no New Hit");
                }
                lastHit = null;
            }
        }
    }
}

Topic is close Thanks for your help FrankvHoof