I’m making a 2D strategy game. The map has clickable items and is scrollable. I have a UI element in one of the corners. It has a panel and several Buttons on that panel.
Buttons are working when I click on them but the problem is that if a clickable item on the map is under the UI, it is selected as well because the Input System’s event gets triggered as well. How can I make the Button absorb the action?
I’ve searcehd for 4 hours in this topic but couldn’t find a proper solution.
Hi there, one possible way to deal with this is to switch from using the Input System’s event callbacks to using the polling API. In your Update method, or where ever you want to poll for input you can use the
Thanks for the idea! In the meantime I ended up using the menu Canvas’ GraphicRaycaster.RaycastAll(position) method. If it finds any object that means a menu item is in the way. But I need to check this everywhere (and exit if a menu item is in the way) where I do input handling that could cause problems when clicking on the menu.
What do you think about GraphicRaycaster.RaycastAll()? Is it lightweight enough to be used with clicks and maybe pointer movement checks? To be honest a method which just returns true if any item on the canvas is in the way - would be enough but I couldn’t find one.
So the IsPointerOverGameObject method internally is also using the results of calls to RaycastAll, so you can absolutely use GraphicRaycaster.RaycastAll in your own code and that will work, but it would be more efficient to just reuse the work that has already been done. Two things to note if you are using input action callbacks:
the IsPointerOverGameObject method might be returning results from the previous frame if the input system UI module hasn’t been updated yet, so it’s best not to use it from callbacks
callbacks for pointer positions can be called many times per frame, and in those cases the cost of doing GraphicRaycaster.RaycastAll will quickly add up.
Are you using canvas? or UI toolkit?
I have the same problem, and IsPointerOverGameObject always return false with UI toolkit in my case
Is there something like IsPointerOverGameObject for UI toolkit?
I’m using Canvas so I can’t help you with that, sorry. I guess you already know this page but in case not, this is a feature comparison between UI toolkit and the old UI:
Apologies for necroing this thread somewhat but I found a different approach that might appeal to some people (or might be horrible and I’d love to learn why if so).
I had two main reasons for looking for an alternative solution:
I prefer the callback method for input handling, and
I don’t like adding singleton dependencies to game logic (i.e. I don’t want to require an EventSystem in every scene, even if in practice all my non-dev scenes will likely have an EventSystem).
The way I met those goals was by, in a separate component, simply disabling the input map when the pointer was over an EventSystem gameobject:
public class UIInputDucker : MonoBehaviour
{
[SerializeField] private PlayerInput Input;
private bool _isDucking;
private void Update()
{
switch (_isDucking)
{
case false when EventSystem.current.IsPointerOverGameObject():
Input.currentActionMap.Disable();
_isDucking = true;
break;
case true when !EventSystem.current.IsPointerOverGameObject():
Input.currentActionMap.Enable();
_isDucking = false;
break;
}
}
}
This is less performant since enabling and disabling action maps is not as cheap as just returning out of the handler, but I think the frame-by-frame performance impact should be minimal compared to adopting the input polling approach and only checking EventSystem.current.IsPointerOverGameObject() when an input occurs. From my amateur framework spelunking it seems like both input polling and the pointer-over-game-object check are simple lookups of state that is computed at the start of each frame.
Anyway, I hope this either 1. helps someone else with the same code organization goals as me, or 2. becomes a learning experience for me when someone tells me why this is a terrible idea.