Search Unity

Using new Input System with UI Toolkit

Discussion in 'Input System' started by johaga, Dec 22, 2020.

  1. johaga

    johaga

    Joined:
    Oct 10, 2019
    Posts:
    10
    I have a very simple scenario - I have an on screen button that is over some aspect of the in game world - i.e. the ground.

    I have a character that I can direct to move to anywhere on the ground, or I can click on the on screen button. Just imagine like any tactical game you've ever seen (randomly pulled from google)



    Somewhere between UI and Input System, I need to be able to click a button and have it NOT click the ground underneath it.

    Now, over in the UI threads, they've got some crazy thing about making a giant screen which intercepts clicks? But of course, that doesn't really work with the Input System.

    So I've no idea who's in charge of what, but it seems like this is actually an Input thing. I want an Action Map that is UI specific, and when it's used by the UITK Event System, it doesn't allow the triggering of any other action maps.

    Otherwise I'll have to send all of my action maps through some kind of weird filter and using the Input System will become a big pain.
     
    cherub8128 and Plaximo like this.
  2. btschumy

    btschumy

    Joined:
    Jul 31, 2019
    Posts:
    93
    I have this same question. When I click a button, I get the button pressed event, but the code that is doing hit testing in the scene is also responding in Update().
     
  3. btschumy

    btschumy

    Joined:
    Jul 31, 2019
    Posts:
    93
    I don't know if this is the correct solution or not, but it does work. All my buttons are in a toolbar. I get the RectTransform.rect of the toolbar and exclude hit testing if the mouse position is in the rect.
     
  4. dylannorth

    dylannorth

    Joined:
    Dec 26, 2015
    Posts:
    9
    I use

    Code (CSharp):
    1. EventSystem.current.IsPointerOverGameObject()
    to check against any player raycasts that may intercept with UI objects, the GameObject in "IsPointerOverGameObject" refers to a canvas gameobject, not a world gameobject
     
    peter_the_coder likes this.
  5. btschumy

    btschumy

    Joined:
    Jul 31, 2019
    Posts:
    93
    Ah, that is much cleaner. Thanks.
     
  6. johaga

    johaga

    Joined:
    Oct 10, 2019
    Posts:
    10
    "EventSystem.current.IsPointerOverGameObject()" doesn't work with the UI Toolkit. EventSystem.current is returns null. EventSystem.current is the Unity.UI.EventSystem. The UI Toolkit though uses UnityEngine.UIElements.EventSystem which is a completely different Event System.

    And without that, I'm unsure how to raycast to detect if the mouse is over the Toolkit. I think the "Graphic Raycaster" is key here, but I dunno quite how yet.
     
  7. johaga

    johaga

    Joined:
    Oct 10, 2019
    Posts:
    10
    Oh, "Graphic Raycaster" is also incompatible with the UI Toolkit.

    Turns out a workaround is to create a script that has this in the Awake/Start somewhere:
    Code (CSharp):
    1.  
    2. var visualElement = rootDocument.rootVisualElement.Q<VisualElement>("rootVisual");
    3. visualElement.RegisterCallback<MouseOverEvent>((evt) =>
    4.         {
    5.             OverUI = evt.target != visualElement;
    6.         });
    7.  
    Where "rootVisual" is a root element in your main UI that contains the controls. Then I have "OverUI" set as a static variable.

    Ugly as sin, but it'll get the job done until the UI team + Input team can talk to each other about how to prevent Input from flowing past the UI.
     
    rezuma and wolf123450 like this.
  8. rangolee302

    rangolee302

    Joined:
    Feb 1, 2018
    Posts:
    22
    You saved my day, I search everywhere and here is a simple solution
    How did I never think about this?
     
  9. SlowpokeFarm

    SlowpokeFarm

    Joined:
    May 6, 2018
    Posts:
    24
    Too bad it doesn't work with touch input. Tried to change it to Pointer events but no luck either
     
  10. konsti1994

    konsti1994

    Joined:
    Nov 29, 2020
    Posts:
    5
    Has anyone found a solution for touch input?
     
  11. Steffen-ttc

    Steffen-ttc

    Joined:
    May 27, 2017
    Posts:
    22
    Any news regarding a touch solution?

    Edit:
    It should work with IsPointerOverGameObject(). Make sure your root visual element has its picking-mode set to ignore, else it always returns true.
     
    Last edited: Apr 23, 2022
  12. wethings

    wethings

    Joined:
    Aug 26, 2018
    Posts:
    28
  13. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    You need to have 2 things for it to work.
    1- The Blocking Canvas has to contain a "Graphic Raycaster" component.
    2- The Blocking Image has to have "Raycast Target" activated.

    The object will only react to touch or click if it has both components, having Raycast target activated makes the "Graphic Raycaster" check it for interaction. They will only work together.

    Also make that the Blocking Image is in front of the thing you want to block, when not transparent it should visually block the things behind it.

    @johaga this will fix your problem only using UI elements
    @konsti1994 @Steffen-ttc @SlowpokeFarm I can confirm I am using this with Touch (Android)

    Edit: I answered the wrong question. look at my comment down bellow for the right info
     
    Last edited: Nov 28, 2022
  14. PixelPerphect

    PixelPerphect

    Joined:
    Oct 9, 2022
    Posts:
    1
    Resurrecting an old thread forgive me. Do you have an example project so I can see this better by chance? Trying to grasp how it should look but having some issues.
     
    Niter88 likes this.
  15. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    Improving your skills is always forgiven lol.

    Example, to fade all there is behind a popup, you could just add a image called background and set it's alpha to half.
    Or even on a complete transparent image, you couldn't click the image behind it, because you're clicking on the "background" object.

    STEP BY STEP
    Select your current Canvas
    Right click it > UI > Image
    It will add an white image
    put it on the front of the UI element you want to block (hierarchy and position)
    confirm that you can't click through it, it blocks your vision and click to the object behind it
    change this image to a color, like {0, 0, 0, 150} just click i'ts color and put this on the sliders for RGBA
    yur done, just rescale and position it to block clicks, if you mess up, check my latest comment.

    or maybe you want this https://docs.unity3d.com/Manual/UIE-Click-Events.html
    if you tell me more about the problem I could try to help you
     
    iceasson likes this.
  16. willhelmet

    willhelmet

    Joined:
    Oct 22, 2022
    Posts:
    2
    I solved this by creating a 2D square, added a collider to it then placed is a child to the button in the UI hierarchy.
     
  17. iceasson

    iceasson

    Joined:
    Mar 7, 2022
    Posts:
    16
    Hey niter88 im trying your fix but im still able to click through my canvas

    My canvas has a graphic raycaster and the background image has raycast target ticked on

    i also tried changing the canvas sort orders but it didnt help either
     

    Attached Files:

    Niter88 likes this.
  18. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    Sorry, I answered the wrong problem on my first comment (actually).
    What you guys want is to only raycast for the 3D objects if you hadn't clicked on an UI element.

    You are currently always raycasting for 3D objects when you detect a click/touch

    info:

    https://answers.unity.com/questions/1095047/detect-mouse-events-for-ui-canvas.html

    https://stackoverflow.com/questions/41391708/how-to-detect-click-touch-events-on-ui-and-gameobjects
     
    iceasson likes this.
  19. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    Actually you can use that answer to solve this problem. Instead of using the update to check if the player has clicked the screen, you will use the blocking object. Just add a Onclick event on it, you will know when you click it, can't be more straightforward than that.
    You use the OnClick event to call your logic, put it behind everything else, when it triggers it means that the part you clicked is not covered by any other UI element
     
  20. iceasson

    iceasson

    Joined:
    Mar 7, 2022
    Posts:
    16


    Would you happen to know if this is also present in the new UI toolkit?
     
    Niter88 likes this.
  21. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    no