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

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?

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

2 Likes

how exactly could i put a layer under the UI ?

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.

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?

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:

3 Likes

Nope - that’s the new UI system. @Antistone has the correct approach.

1 Like

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.

3 Likes

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.

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

Something’s not quite right when I have to sit through my own tutorial to remember what I was talking about. :face_with_spiral_eyes:

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.

2 Likes

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()

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

3 Likes

aha, that is nice, thank you;. It took me a while to find that, in the layout section

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.

Great thread with great advice. Kudos to all the contributors!
Gigi

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 ;-;

Did you delete the EventSystem GameObject? It gets created automatically when you create a UI element (if it doesn’t exist).

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.

There should be a GameObject called EventSystem. Delete that. Problem caused. :slight_smile: