Refresh EventSystem so IsPointerOverGameObject() returns the correct result after deleting a button

Hello everyone.

I have a problem with EventSystem, and was hoping I could get some help. It seems trivial, but I can’t figure out the right way to ask uncle Google for help.

tldr; version:
How do you tell the EventSystem or UnityEngine to re-check if its cursor is actually over an UI element without moving the mouse, when the one it was over before was destroyed, so IsPointerOverGameObject() returns a correct value?

//================================================================

long version:

I’m making an UI for picking up ground items.

Basically, I have an UI Button for each item that lies on that particular tile. When I click that Button, it has to disappear from the UI, because henceforth, it’s in players inventory, and not on the ground., So I Destroy() all buttons on that particular Canvas, and Instantiate() them again without the button representing the picked up item. Everything is working fine, except for one thing:

My movement also depends on mouse clicks. I click a tile, and the character goes to that tile. To prevent triggering movement when clicking the UI, I use something like this:

public void ClickedBlock(Block block){
if (!EventSystem.current.IsPointerOverGameObject ()) {
Debug.Log("Clicked block " + block.ToString());
} else {
Debug.Log(“OVER UI ELEM”);
}
}

This works fine, with the exception of when I delete and re - Instantiate() the buttons, and one of them ends up right underneath the cursor. If I then click it without moving the mouse first, the IsPointerOverGameObject() returns false, and player character starts moving towards the underlying tile, instead of picking up the sword/axe/glove/armor/used handkerchief/whatever.

I was trying to find a way to tell EventSystem to refresh itself without needing to move the mouse, but with no luck. So my question is this: how do you tell the EventSystem or UnityEngine to re-check if its cursor is actually over an UI element, when the one it was over before was destroyed?

bump

Anyone?

I have a hackish solution figured out, but I’d like to do it properly. Also it would come in handy for the future…

Just use a IPointerClickHandler scripts for both the UI (rather just Button for UI) and the Tiles. The event system will only call the click logic on the first object the cursor hits, no need to use IsPointerOverGameObject.

You may try to implement your own InputModule based on the existing modules. You can find the source of the modules here.

I’d start by copying the StandaloneInputModule and PointerInputModule to a CustomInputModule and CustomPointerModule (where CustomInputModule inherits from CustomPointerModule). From there, you can place them on a scene and debug them to see why your case doesn’t work (you can find IsPointerOverGameObject in the PointerInputModule).

I solved most of my problems with the event system by tweaking the existing implementation(and there were many problems since current implementation has its quirks and nuances).

just use EventSystem.current.currentInputModule.Process();
when UI is activated on same position as cursor is, IPointerEnterHandler is not processed. So you have to do it manually.

To make even more clear your answer:

EventSystem.current.currentInputModule.Process();
if (EventSystem.current.IsPointerOverGameObject())
{
       Debug.Log("mouse is over gui");
}
1 Like