Hello everyone. If I have UI, I need somehow to filter the clicks, when they were over UI element, or when they were over some other object. So what are my options if I want to do this?
I am doing this in a job and I have an idea of doing it by using a ComponentLookup.HasComponent, so I just check if the raycasted entity has some tag, which UI cannot contain. But this way seems to me not so effective (because of using ComponentLookup) and not so flexible, as it could be.
So maybe I don't see something and there is another way of filtering
#Filtering UI clicks
1 messages · Page 1 of 1 (latest)
why not just simply read value? if (!comp.IsClicked) return;
The thing is to stop something which is called OnClick of some object (not UI), when we click UI.
So for example if I click on some button I do not want my unit behind that button to be selected
don't use callbacks at all
And I want my SelectionSystem to be BurstCompiled, so I cannot check MyButton.IsClicked there, because it is a managedComponent
then store it as unmanaged
can all your buttons be hardcoded as fields?
or you need a generic version?
What do you mean by "hardocoded as fields"? To copy the bool value of IsPressedThisFrame in some unmanaged data component?
by hardcoded as fields I mean, can you make it so all your buttons are stored in just one type?
for example
struct MyGameplayUI { public Button pauseButton; public Button menuButton; }
Button is a class, how can I put it in the unmanaged component?
you won't
public struct Button { public bool isClicked; }
Well, okey, let's suppose I put all my buttons, sliders or another interactive components in such struct. But then 2 questions:
- How can I track clicks on some non interactive UI things? For example some panels, where the buttons are fitted? Creating additional fields in the struct for them as well?
- How to fill this fields, if we should not use events like OnClick or smth like that? Moreover non-interactive panels do not have even such thing, so how to track a click on them?
you can use OnClick events, no problem with that
it's just that you write values to your temporary data structure
and then read it from system's OnUpdate
If you're just looking to block clicks going through UI you should be able to use something in here https://forum.unity.com/threads/how-to-detect-if-mouse-is-over-ui.1025533/
basically, goal is: make it so your UI input is as simple as Input API (old input system)
just like Input.GetKeyDown(KeyCode.R)
for example MyUIInput.IsPauseButtonPressed()
and simply store it in some singleton struct
then you can even skip scheduling jobs if relevant button is not pressed
by early returning in other system updates
here example how I implemented burst compatible input with both: old input and new input system
https://github.com/bustedbunny/RTSDemo/blob/master/Assets/TankEntitiesMultiplayer/NetCodeInput/Data/LocalClientInput.cs
you literally just can do same with UI input
where instead of _controls you'll have your UI manager reference
I don't think that creating additional raycast in monobehaviour world is a good idea. Maybe I didn't understand the idea of usage of that solution
ugui is quite literally doing raycasts for clicks though 😅
Won't it create some stalls, when monobehaviour is trying to modify that struct?
what struct?
where all data about clicks on UI is stored and which is read by my system
you make sure that mono behaviour writes to it's own copy
and then system simply copies it to entity data
oh, I got it
that system must run as soon as possible
before any jobs are scheduled
so it won't do any syncs
that would make your input overhead is nearly 0
allthough.. makes no difference when it runs
your input will be stored on singleton which is only read by main thread (systems)
while passed to jobs as copy
The only moment I am still not sure is the next one:
For example I have a SelectingUnitSystem which works on a single leftButton click. So every I click, I will have to check ALL bool-s of UI data (to check that no button, slider, or non-interactible panel was clicked). And the same I will have to do simultaneously before all commands, that work on the leftButton. I don't think there will be a lot of them, but still it doesn't look like an accurate solution. Because if I add any UI component, I will have to add it to many places in code, which doesn't look very convinient..
Also I still don't understand a little, how can I track if non-interactible panel (which doesn't have an event OnClick) was clicked...
huh?
why do you need to read anything but bool leftClick field?
Well, to understand if it was clicked on the UI and if so, I will not schedule the Job for selecting unit
ah, you mean this
why not just have additional field bool cursorOverUI
and each time cursor is over it
just set it
and then you only need to check leftClick && !cursorOverUI
So can I fill that field by just getting a EventSystem.current.IsPointerOverGameObject() value each frame? Or it will be too heavy for every-frame operation?
I think so
I personally never used ugui, and that method never worked for me in UI Toolkit 😅
Which variant do you mean? :)
I didn't understand a little
should be fine
if you want to optimize it - you can always do additional checks later
for starting - don't think you'll be able to even find it in profiler
because it will be too fast and I will not notice it?