How to block raycast while closing UI?

Hi all,

I will try to simplify my problem here, and I hope I can explain it.

I have a sprite that has a hit box in my scene. I use Raycast2D to detect if that sprite is clicked. If so, I spawn an UI and add it to the screen.

In my code, there’s a condition to check if any UI is spawned already in order to prevent a player from opening another UI. This code works with no problem unless I put a sprite, which has a hit box, right under the close button. When I click the close button, the UI closes and then the raycast detects the sprite.

I think, the order in Unity is like this: UI events first and then Update functions.

I wonder if anyone come across with this issue and find any solution. The first thing came to my mind is that delaying the raycast by 1 frame, but that requires to setup a Coroutine, which doesn’t look right.

Here’s the simplified version of the code:

    [SerializeField] private Camera cam;

    private void Update()
    {
        // UIManager is a singleton and 'IsThereAnyUI' function checks if there's any child object (UI) under a specific gameobject
        if (!Input.GetMouseButtonDown(0) || UIManager.Singleton.IsThereAnyUI())
            return;

        Vector3 origin = cam.ScreenToWorldPoint(Input.mousePosition);
        RaycastHit2D hit = Physics2D.Raycast(origin, cam.transform.forward, Mathf.Infinity);

        hit.transform?.GetComponent<Interactable>()?.OnClick();
    }

That may be it, but the underlying issue is that you have two unrelated systems for gathering intention and processing intention:

  1. the EventSystem that runs the UI
  2. your check of GetMouseButtonDown()

Since it isn’t really possible to guarantee order, another approach is to implement a cooldown timer in your UIManager.

What I mean by this is that as long as you have a UI visible, return true for your IsThereAnyUI() call, as you do now.

When there is UI present, also set an internal (to UIManager) float that is a cooldown timer. (perhaps 0.10f seconds?)

You already have that as a singleton so in UIManager’s Update() just subtract Time.deltaTime from the cooldown timer, and as long as it’s not zero, ALSO use that as a condition to return true to IsThereAnyU().

Was actually just writing about this in a cooldown thread today:

https://discussions.unity.com/t/824570/2

1 Like

Actually even a boolean value should be enough. I think, what I need is only one frame delay. I’ll try that.