IsPointerOverGameObject is not working on Mobile

Hello guys, I m trying to stop gameobject when send ray at UI/Panel front of ground.
This part of code is working on PC well but in mobile its not working why?

  public void SetTargetPosition()
    {
        Plane plane = new Plane(Vector3.up, transform.position);
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float point = 0f;

        Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit[] hits = Physics.RaycastAll(ray);

        isMoving = false;
        foreach (RaycastHit hit in hits)
        {
            if (EventSystem.current.IsPointerOverGameObject())
                return;

            if (plane.Raycast(ray, out point) && hit.collider.gameObject.tag == "Ground" )
            {
                targetPosition = ray.GetPoint(point);
                isMoving = true;
            }
            break;
        }
       

    }
1 Like

Havent yet build a mobile app, but i’m pretty sure that IsPointerOverGameObject() is a function that makes no sense with touch-input. How would you hover over something with touches? Imagine touches as ā€˜clicked’ mouse inputs.
I believe there are also specific Touch helper objects in Unity.

2 Likes

I’ve used this snippet in the past to get the deed done. It’ll break for multi-touch but it’s easy to fix. I’m pretty sure you can just iterate over all positions without any problem, should you need multitouch support.

private bool IsPointerOverUIObject()
{
    PointerEventData eventData = new PointerEventData(eventSystem);
    eventData.position = Input.mousePosition;
    List<RaycastResult> results = new List<RaycastResult>();
    eventSystem.RaycastAll(eventData, results);
    return results.Count > 0;
}
11 Likes

According to the new unity input module docs here[https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/api/UnityEngine.InputSystem.UI.InputSystemUIInputModule.html], a touch on the screen should he able to alter the value of that method. It unfortunately doesn’t seem to work simply as the docs stated it would.

1 Like

Any updates on this as it’s completely breaking my projects if I can’t mask out UI elements when moving items on the screen on mobile

What a surprise, the Unity docs says it works, but in reality, it doesn’t. I just hope they really do work more on bugs for Unity 2021, because 2020.x is just unusable.

On the other hand, I’ve just tried ADNCG’s approach, and it works. To make it more memory efficient, I recommend storing the I recommend caching the results List, and clearing it before the RaycastAll().

+1 just stumbled upon this too. I definitely think this is a bug, and I wasted several hours trying to solve this until I found ADNCG’s solution.

Here’s the version I came up with that works with New Input system:

private bool IsPointerOverUIObject()
{
    var touchPosition = Touchscreen.current.position.ReadValue();
    var eventData = new PointerEventData(EventSystem.current) {position = touchPosition};
    var results = new List<RaycastResult>();
    EventSystem.current.RaycastAll(eventData, results);
    return results.Count > 0;
}
5 Likes

Has anyone reported this as a bug?

I didn’t, I was able to work around this entirely by using an empty text input as a touch capture region. Would still be good to report it though!

+1 Still don’t work on Android Device .The error make my app crash

In my case actually it was not a bug or issue, if you call it outside of update it can be flakey, only use it in update I found - I was using a bool function to check something in update, so the bool function was running after the tap in update initiated it and it worked most of the time but sometimes that function would run just after the tap so of course the pointer was not over UI.

I would encourage others to do the same and carefully observe when their code is running around the time of the tap - sometimes like me you may just miss the tap on screen and the result will be false.

Same issue! I’ve debugged on screen the result of IsPointerOverGameObject and apparently it only becomes true when dragging the finger over a UI element, but never when tapping/entering. Even if I pass the TouchID as a parameter the issue still persists. On the other hand, it works fine with the mouse on PC, though.

Shame on the staff behind the new Input System who apparently isn’t able to provide a stable package for all platforms, even though it is out of preview!

4 Likes

Not sure if this is related to your problem, but I found that checking IsPointerOverGameObject for mouse OR touch based on the related event was unreliable. But when I started checking BOTH for every type of click then it started working as expected. I suspect that there is something going on with mouse to touch emulation that is messing this up.
-Fred-

I not understud.
Same prolem here with unity 2022.

1 Like

Wow I can’t believe @Fredjack99 's fix of ā€œchecking BOTH for every type of clickā€ worked, but that’s what did it for me!

1 Like

For Android and Editor, it worked fine for me when I used the following:

        bool inTouch;
        if (inTouch = Input.touchCount > 0)
            touch = Input.GetTouch(0);
        if (
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)
            inTouch && touch.phase == TouchPhase.Began && !EventSystem.current.IsPointerOverGameObject(touch.fingerId)
#else
            Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject()
#endif
            )
        {
            //Do something
        }

Note that I need to know that I do not press any buttons on the interface (in Canvas).

2 Likes

Could you please provide more details.

What exactly are you interested in?

Sorry for the delay in replying, I don’t come here often. I’ll keep this page open for some time.

Here is what I put on my UI class, following @ADNCG 's solution. I felt it would be more useful for me to sometimes know if a certain object is ā€œtop-mostā€ in the UI, like having windows on top of windows. Using Unity 6000.0.32f1.

public static bool IsPointerOverUIObject(GameObject uiObject = null)
{
    PointerEventData eventData = new(EventSystem.current) { position = Input.mousePosition };
    List<RaycastResult> results = new();
    EventSystem.current.RaycastAll(eventData, results);
    if (results.Count == 0) return false;
    if (uiObject == null) return results.Count > 0;
    return results[0].gameObject == uiObject;
}

Here is a snippet of the code in practice

if (EventSystem.current.currentSelectedGameObject == gameObject)
{
    if (UI.IsPointerOverUIObject(gameObject)) // ...
}

I just faced the same problem when I was trying to perform a raycast during the Ended phase of my input. It seems that IsPointerOverGameObject() does not work when used during the final states of an input (Ended or Canceled).

To solve this problem I cached and refreshed the result during the Began, Moved and Stationary states of my input and used this cached if needed. I can then acces the information through a dedicated method. Here is my code :

public bool IsMainInputOverUi()
    {
        if (Application.isEditor)
        {
            return EventSystem.current.IsPointerOverGameObject();
        }

        if (Input.touchCount <= 0)
        {
            return false;
        }
        
        var mainTouch = Input.GetTouch(0);
        bool result;

        if (mainTouch.phase == TouchPhase.Ended || mainTouch.phase == TouchPhase.Canceled)
        {
            result = _isOverUi;
        }
        else
        {
            result = EventSystem.current.IsPointerOverGameObject(mainTouch.fingerId);
        }
        
        return result;
    }

Here _isOverUi is my local variable that is refreshed during the Began, Moved and Stationary states.