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:
the EventSystem that runs the UI
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: