Search Unity

What's he usual method of divorcing world and UI clicks?

Discussion in 'Scripting' started by Nanako, Apr 20, 2015.

  1. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    I'm making the first thing i've ever done that's somewhat similar to an RTS, in that there are units which you can select by clicking them, and give them orders.

    Internally, i have this work by doing a raycast from the camera through the screen point clicked until it hits something, and i check if that something is a selectable unit based on the tag attached to it.

    I've also implemented the other common RTS behaviour, in that left-clicking on a place which doesn't contain a selectable unit (ie, a random patch of ground) causes you to deselect all currently selected things. This is working fairly well

    Right now i'm getting more into UI design, and i'm running into a problem. The raycasting doesn't seem to detect UI objects, and passes right through them obliviously. This usually results in a click being detected against empty ground, and thus in deselecting. This is bad

    I want clicks on UI objects to be a special case, to be discarded or ignored by the selection code. I could probably do this easily if the raycast were to hit them, i could check the layer they're on. All my UI objects are on a canvas and the UI layer.

    But it doesn't detect them, so what do i do?
     
  2. Gigiwoo

    Gigiwoo

    Joined:
    Mar 16, 2011
    Posts:
    2,981
    Wrong forum, so I will move it. And, one way to do this is to put a layer UNDER your UI that has a special tag on it (like UI_BLOCKING_LAYER). Then, when you cast your ray, if it also hits this layer, you can throw it out. Another way would be to use Viewport like behaviors. And, I think there is probably a way to take the ray and cast it into the UI, checking to see if it hit anything in the Canvas (though, in honesty, I haven't solved that yet).

    Gigi
     
    theANMATOR2b and Nanako like this.
  3. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    how exactly could i put a layer under the UI ?
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    If you're using legacy UI then you need to check the position of the mouse cursor to see if it's inside any Rect defined by your GUI code.

    The same method can be used to swap out mouse cursors so you get your pointer while hovering over UI elements even if you have units selected.
     
  5. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    Since i literally just started getting into UI systems,. i have no idea what is and isn't legacy. But i'm using UI objects placed onto a canvas object. is that the new system?
     
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I don't have personal experience with this issue, but there's a pinned FAQ thread in the Unity UI forum that includes this answer, which seems relevant:

     
    Ryiah, Gigiwoo and theANMATOR2b like this.
  7. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Nope - that's the new UI system. @Antistone has the correct approach.
     
    Nanako likes this.
  8. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    There is an alternative method, which I prefer. That is to turn over all of the ray casting to the Event System, and let it deal with blocking automatically. This video I did a while back may be helpful. It describes multiple ways to block clicks on a UI element, choose the one that works for you.

     
    Gigiwoo, Nanako and theANMATOR2b like this.
  9. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    Well i got antistone's method working, and it seems to do well. However i notice ha one of my UI elements is blocking clicks that i don't want to. This particular element is just text, with no background/panel/buton underneath. I may have a look at the other options in that video.
     
  10. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047

    Ok watched the video, i have some qiuestions;

    he approach of putting a script inside whatever i want o click seems messy to me, i don't do that. For selecting units in my game, i have a centralised input script detect clicks, and it passes the message to another centralised selectionManager script which does the raycasting and detects whether or not a unit was hit.

    Can either of the latter two methods be implemented into this setup?

    what exactly are the advantages between all threee methods?


    and is there any way to make UI elements selectively not-block clicks
     
  11. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Something's not quite right when I have to sit through my own tutorial to remember what I was talking about. :confused:

    If you want to use a centralised selection manager the two later methods will not work. The EventSystem is its own centralised selection manager. You could pull apart the event system and incorporate it into your selection script, the component is open source. But I'm not sure that's the best thing in your case. The first method is probably the best if you already have a central input manager

    Method 1: Simple to implement, but if you are using a lot of OnMouseXXX it can be a pain to maintain bool checks everywhere. Not a big deal for a centralised input manager.

    Method 2: Simple to implement. Can be done entirely in the inspector. Forces all input to go through the EventSystem.

    Method 3: Essentially identical to method 2, but in script instead of in the inspector. Gives the finest control over the input system. Also forces input to use the EventSystem

    This is the easy part. Add a canvas group and manipulate the blocks raycast property.
     
    Gigiwoo and Nanako like this.
  12. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    huh? I'm lost

    Do you mean these options?



    Switching between None/Nothing and All/Everything doesn't seem to have any effect on clicks, or on the return value of EventSystem.current.IsPointerOverGameObject()
     
  13. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    he means using a canvas group.
    You put this on a gameobject and any child of it you can set to no block raycasts, and not be interactable
     
    Gigiwoo, Kiwasi and Nanako like this.
  14. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    aha, that is nice, thank you;. It took me a while to find that, in the layout section
     
  15. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Yeah, some of the split between layout and UI is counter intuitive. Just be aware you will use layout a lot as you build your UI.
     
  16. Gigiwoo

    Gigiwoo

    Joined:
    Mar 16, 2011
    Posts:
    2,981
    Great thread with great advice. Kudos to all the contributors!
    Gigi
     
  17. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    Aaah.

    This solution just randomly broke. I was poking around in the canvas looking for a certain type of components, i think added a few things, maybe removed something.

    Now eventsystem.current is null, and the check for if its over a gameobject returns a null reference error.

    what could i have done to break it ;-;
     
  18. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Did you delete the EventSystem GameObject? It gets created automatically when you create a UI element (if it doesn't exist).
     
  19. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    i don't remember seeing any such thing or deleting it, i only added and removed components.

    In any case i fixed the issue by closing the editor without saving, and reloading my last save. Lost a little work of course ;-;

    still it'd be nice to figure out what i did so that i can avoid it.
     
  20. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    There should be a GameObject called EventSystem. Delete that. Problem caused. :)