I’ve run into some problems when updating my project to Unity 2020.3.25f1. The update has made some changes to the input system which affects the way I am checking if the mouse click was performed over UI or not.
public class ClickHandler : MonoBehaviour
{
private Controls controls;
private void Awake()
{
//Get the new control system and set the controls needed for this script
controls = new Controls();
controls.Player.MouseClick.performed += _ => OnMouseClicked();
}
private void OnEnable() => controls.Enable();
private void OnDisable() => controls.Disable();
public void OnMouseClicked()
{
//ignore if UI was clicked.
if (UIManager.Instance.IsMouseOverUI())
{
return;
}}
In UIManager script:
public bool IsMouseOverUI()
{
return EventSystem.current.IsPointerOverGameObject();
}
With the new version I now recieve the following warning:
Calling IsPointerOverGameObject() from within event processing (such as from InputAction callbacks) will not work as expected; it will query UI state from the last frame
I understand that I can solve this by moving the IsPointerOverGameObject() into Unity Update() function, which guarantees the logic to run each frame. I fail to understand how to make this work with the new eventsystem, where I check inputs through events rather than an update polling-approach.
What is a good way to use the new input system and check if UI was pressed or not?
Honestly, i don’t know the answer, but i would personally try to use EventSystem.current.currentSelectedGameObject != null instead, maybe, with some adjustments, it will magically work. Hope you get better answers.
This is a pretty old topic, but it’s still high in search results. Basically there are two ways.
The simplest by far is to just store IsPointerOverGameObject() every frame
public class GameInputManager: MonoBehaviour
{
public static bool IsPointerOverUI { get; private set;}
public void Update()
{
// Setting the flag here, as querying it during the event callback is creates warning
// It does mean that this flag will still be one frame late, but there's no easy fix
IsPointerOverUI =
EventSystem.current.NP()?.IsPointerOverGameObject() ?? false;
}
}
The second solution is to add a component to all your root canvases that detects hovers:
public class UIHoverDetector : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
private static HashSet<UIHoverDetector> ActiveHover = new HashSet<UIHoverDetector>();
public static bool IsPointerOverGameObject
{
get
{
foreach (var hover in ActiveHover)
{
if (hover != null && hover.isActiveAndEnabled)
return true;
}
return false;
}
}
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
{
ActiveHover.Add(this);
}
void IPointerEnterHandler.OnPointerExit(PointerEventData eventData)
{
ActiveHover.Remove(this);
}
void OnDisable()
{
ActiveHover.Remove(this);
}
}