Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. We're looking for your feedback on the platforms you use and how you use them. Let us know!
    Dismiss Notice
  4. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  6. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  7. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  8. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Touch Press pass through all UI elements

Discussion in 'Unity UI & TextMesh Pro' started by charles_cloudcade, Oct 8, 2014.

  1. charles_cloudcade

    charles_cloudcade

    Joined:
    Oct 8, 2014
    Posts:
    2
    I'm having this issue with IsPointerOverGameObject(). Whenever I use it to know if my mouse click is over a GameObject it works fine, but if I want to know if my touch press is over a GameObject it doesn't work.

    This works fine
    Code (CSharp):
    1.  
    2. private void OnMouseDown()
    3. {
    4.    if(UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
    5.    {
    6.          //Do stuff
    7.    }
    8. }
    9.  
    This always return false
    Code (CSharp):
    1.  
    2. private void OnMouseDown()
    3. {
    4.    foreach (Touch touch in touches)
    5.    {
    6.        if(UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(touch.fingerId))
    7.        {
    8.             //Do stuff
    9.             break;
    10.        }
    11.    }
    12. }
    13.  
     
    Last edited: Oct 8, 2014
  2. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,044
    This is working in our test cases, please raise a bug if you think you have found an issue.
     
  3. charles_cloudcade

    charles_cloudcade

    Joined:
    Oct 8, 2014
    Posts:
    2
    I've raised a bug. It isn't working on any touch device I've tried.
     
  4. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    I have the same issue. I use this to block input when user taps on UI:
    Code (CSharp):
    1. if(EventSystem.current.IsPointerOverGameObject())
    2.             return;
    On PC with mouse it works fine, but on Android it doen`t. Unity beta 20.

    P.S. Where is link to this bug on issure tracker? I want to vote for it.
     
  5. gregorypierce

    gregorypierce

    Joined:
    Jan 21, 2008
    Posts:
    377
    Same here. I thought maybe it just wasn't fully implemented on mobile yet. Let me just say, it makes creating a joystick a very very FUN experience.
     
  6. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    This bug holds release of my game :(
     
  7. Grenk

    Grenk

    Joined:
    Oct 12, 2014
    Posts:
    2
    I was experiencing a similar problem. The source of the problem is that looking at the raw touches, as returned by Input.touches, will include touches that have just ended or been cancelled. The fingerId field of these Touch objects will always return false when passed to IsPointerOverGameObject. My solution was to only look at active touches, like so:

    Code (CSharp):
    1. bool inputIsActive = (currentTouch.phase != TouchPhase.Ended &&
    2.                       currentTouch.phase != TouchPhase.Canceled);
    Once you know the touch is a valid kind of touch event that can be used to detect UI hits, you can then use

    Code (CSharp):
    1. currentEventSystem.IsPointerOverGameObject(currentTouch.fingerId);
    The same function without parameters does seem to always return false, so it can't be used for touch input at the moment.
     
  8. lianaqiang

    lianaqiang

    Joined:
    Apr 24, 2013
    Posts:
    10
    Issues here is exactly what i want to to, i will give it a try. Is there any other way to handle it?
     
  9. Grenk

    Grenk

    Joined:
    Oct 12, 2014
    Posts:
    2
    I actually did come across another method that will let you essentially force mouse behavior in the EventSystem.
    1. Make sure the system is simulating mouse touches:
      Code (CSharp):
      1. Input.simulateMouseWithTouches = true;
    2. On your EventSystem component, remove the TouchInputModule
    3. On the StandaloneInputModule for the same EventSystem, set Allow Activation On Mobile to true.

    I believe this may actually be the intended functionality for the TouchInputModule class. The parameterless method could provide misleading information if it ever returned true in a situation where there may possibly be more than one touch on the screen simultaneously. For example, a game that has the player interact with UI elements and the world via touch would essentially block all input to the world with one finger while another finger was touching a UI element, if the developer relied on the parameterless method and the method returned true if *any* touches were over a UI, even if some aren't. There world be the opposite problem of the touches going through the UI if it returned true only if *all* touches were over an element. What should really happen is the parameterless method should throw a "not supported" type exception or log an error to let the developer know why they need to change something.
     
    Jean-Fabre and ekow like this.
  10. gregorypierce

    gregorypierce

    Joined:
    Jan 21, 2008
    Posts:
    377
    Whoa, you're going to release something on a very early beta version of Unity?
     
  11. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    Yes, it is pretty stable already :) I`m on 4.6 since beta 9. However, my release is free open-source, not so risky as commertial. In fact this problem with touches was the only one I stuck with.
     
  12. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    I have testet both solutions in my project on Android Tabled and neither of them works. What am I doing wrong?
    Clicks still do pass UI on Android and dont pass it on PC.
     
  13. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    I`ve performed more tests. This is what I see:
    1. Solution with simulateMouseWithTouches works with bugs. First touch to UI on Android still goes through.
    2. Solution like this does not work on Android at all:
    Code (CSharp):
    1. public void OnMouseDown()
    2.     {
    3.         if(EventSystem.current.IsPointerOverGameObject())
    4.             return;
    5.  
    6.         foreach(Touch t in Input.touches)
    7.         {
    8.  
    9.             if(EventSystem.current.IsPointerOverGameObject(t.fingerId))
    10.                 return;
    11.         }
    12.          
    13.         curPanDistance = 0;
    14.         lastMousePos = Input.mousePosition;
    15.         mouseDown = true;
    16.  
    17.     }
    I have uploaded my game to Google Play with my very own hack, blocking touches in critical secions:
    Code (CSharp):
    1. if(Input.mousePosition.x>Screen.width-316)
    2.             return;
    But I still want to find proper solution. Sources of game.
     
  14. PentagramPro

    PentagramPro

    Joined:
    Apr 5, 2014
    Posts:
    23
    Today I`ve received an answer from Unity development team. Here is how to deal with this issue:

    Hi,

    So the issue you are seeing is related to how OnMouseDown works. What happens is this gets executed BEFORE the calls to the EventSystem so at the time of the press the system thinks it is not over anything.

    There is an easy way to fix this though. Replace your Tap Script with this:
    Code (CSharp):
    1.  
    2. using UnityEngine.EventSystems;
    3.  
    4. public class TapController : BaseController, IPointerClickHandler, IDragHandler {
    5.  
    6.         public delegate void TapEvent();
    7.         public event TapEvent OnTap;
    8.  
    9.         public void OnPointerClick(PointerEve
    10. ntData eventData)
    11.         {
    12.                 OnTap();
    13.         }
    14.  
    15.         public void OnDrag(PointerEventData eventData)
    16.         {
    17.                 M.Scroll(-eventData.delta);
    18.         }
    19. }

    And add a Physics 2D Raycaster to the MainCamera and things should work as you expect. What this does is make the TapController use the new event system in 4.6 instead of using the old event system.

    -Tim C
     
  15. atti

    atti

    Joined:
    Feb 22, 2011
    Posts:
    73
    thanks for the very useful hints.
    i deal with the problem like this now and it works on iOS:
    Code (CSharp):
    1.  
    2. bool isPointerOverGameObject = false;
    3.  
    4. if(EventSystem.current.currentInputModule is TouchInputModule) {
    5.    for(int i=0; i<Input.touchCount; i++) {
    6.      Touch touch = Input.touches[i];
    7.      if( touch.phase != TouchPhase.Canceled && touch.phase != TouchPhase.Ended) {
    8.        if(EventSystem.current.IsPointerOverGameObject( Input.touches[i].fingerId )) {
    9.          isPointerOverGameObject = true;
    10.          break;
    11.        }
    12.      }
    13.    }
    14. } else {
    15.    isPointerOverGameObject = EventSystem.current.IsPointerOverGameObject();
    16. }
    17.  
     
  16. Typhox

    Typhox

    Joined:
    Dec 29, 2013
    Posts:
    18
    It doesn't work for me, when I add atti's code on Update() , the bool isPointerOverGameObject never becomes true, even if the button calls the associated function ...
     
  17. blamejane

    blamejane

    Joined:
    Jul 8, 2013
    Posts:
    161
    Can anyone tell me what the "TapController" is? According to the message from the Unity developer we need to replace our "TapController" with the code. I can't find TapController Anywhere.
     
  18. MaLlorente

    MaLlorente

    Joined:
    May 27, 2013
    Posts:
    5
    Hi Guys, in case some have faced the same problem,
    Code (CSharp):
    1. EventSystem.current.IsPointerOverGameObject
    is not working for
    Code (CSharp):
    1. TouchPhase.Ended
    so you need to center on
    Code (CSharp):
    1. TouchPhase.Began
    The code should look like this:
    Code (CSharp):
    1.  
    2. if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
    3.         {
    4.             // Check if finger is over a UI element
    5.             if(EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
    6.             {
    7.                 Debug.Log("Touched the UI");
    8.             }
    9.         }    
    10.  
    As you can check on the manual : http://docs.unity3d.com/ScriptReference/EventSystems.EventSystem.IsPointerOverGameObject.html
     
  19. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    117
    Sorry for necroposting, but if anyone finds this I'd like to share. I noticed that I got a "touched the ui" at first, then if I held the finger just for another frame, and the UI moved in the background, it ended up detecting me touching the background. So I skipped the TouchPhase part entirely, and this code works for me:

    Code (CSharp):
    1. if (Input.touchCount > 0        {
    2.             // Check if finger is over a UI element
    3.             if(EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
    4.             {
    5.                 Debug.Log("Touched the UI");
    6.             }
    7.         }  
    However if you expect multiple touches, use Atti's code instead, and still remove the TouchPhase part.

    Thanks again, I love Unity :D
     
  20. grimmy

    grimmy

    Joined:
    Feb 2, 2009
    Posts:
    389
    Absolutely ridiculous. Unity can't perform a single UI tap on Android without problems. And why on earth doesn't the blocks raycasts option on the UI element just block the raycast.

    Why do we have to do any of the above solutions? This is VERY basic stuff that any engine should not have issues with. 3 hours trying to find a solution for this so far today. Big joke.

    Is there even a case where a game would want the player to have the environment behind the UI tapped at the same time as the UI? Why is this default behavior?
     
    Last edited: Mar 29, 2018
    Ruslank100 and KrakenUpJP like this.
  21. kopi1996

    kopi1996

    Joined:
    Dec 14, 2017
    Posts:
    1
    var pointer = new PointerEventData(EventSystem.current) {position = Input.mousePosition};
    var raycastResults = new List<RaycastResult>();
    EventSystem.current.RaycastAll(pointer, raycastResults);
    if (raycastResults.Any())
    {
    return;
    }
     
  22. KrakenUpJP

    KrakenUpJP

    Joined:
    Apr 22, 2018
    Posts:
    9
    I'm bumping this because these are my exact feelings right now. Why doesn't block raycast, actually block the raycast? I've been searching and trying all of the recommendations suggested in dozens of threads to no avail. My game object still gets clicked through the canvas that's clearly laying over it. I have canvas group with block raycast checked on every possible canvas above the game object. I'm at my wits end with it and about to say screw it, enjoy the weird feeling of "why did my score go up" when you clicked the button in the achievement popup.
     
  23. knickerbocker

    knickerbocker

    Joined:
    May 8, 2014
    Posts:
    28
    cant believe this is still an issue, this was an issue in 2014 and the pointer over game object function worked, and now it does not!
     
  24. knickerbocker

    knickerbocker

    Joined:
    May 8, 2014
    Posts:
    28
    This function i modified from an above post worked
    The parameter is Input.getTouch(0).position:


    Code (CSharp):
    1. bool CheckPointer(Vector2 pos) {
    2.         var pointer = new PointerEventData(EventSystem.current) { position = pos };
    3.         var raycastResults = new List<RaycastResult>();
    4.         EventSystem.current.RaycastAll(pointer, raycastResults);
    5.         if (raycastResults.Count>0)
    6.         {
    7.             var ui = raycastResults.Find((obj) => obj.gameObject.layer == 5);
    8.             if (ui.gameObject!=null)
    9.             {
    10.                 Debug.Log("touching UI");
    11.                 return true;
    12.             }
    13.             Debug.Log("not touching UI");
    14.             return false;
    15.  
    16.         }
    17.  
    18.         return false;
    19.     }