Klemikaze
Klemikaze

Reputation: 378

Unity UI Toolkit click through to underlying GameObject

I'm trying to have UI Toolkit made layouts over my game scene in Unity. The UI covers entire screen (I want to display modal dialogs in center) and roughly bottom 20% of screen contains some buttons.

On the buttons, I have clicked actions that work fine, but once the button is clicked, the event 'falls through' to underlying GameObject, triggering another 'in-game' (unlike in-ui) action.

How do I prevent propagation of clicks into UIToolkit ui to underlying scene filled with GameObjects?

I tried almost everything I found and read in docs and forums but with no luck. I tried differentiating layers (I've put GameUI scene object containing the UIDocument into UI layer and World scene object containing my gameObjects into custom World layer), but the raycast hit still says that the target object is GameObject of 'in-scene' type, not VisualElement of Panel or something like this.

Upvotes: 0

Views: 1124

Answers (2)

Roger Crawfis
Roger Crawfis

Reputation: 1

FYI. I used a camera viewport to limit the main camera rendering to a portion of the window. I think that would also solve your problem if your bars are opaque and completely covers the bar areas. Avoids the coupling of the UI code and the raycasting (can remove the if clause and variable).

Upvotes: 0

Klemikaze
Klemikaze

Reputation: 378

This is the solution:

https://forum.unity.com/threads/ui-toolkit-and-raycast-block.1034938/#post-8218593

The thing is: I wanted to build primarily for handheld/touchscreen devices, thus MouseEnterEvent and MouseLeaveEvent didn't actually made much sense to me, but, BUT... The MouseEnterEvent triggered on VisualElement is not triggered when pointer hovers over UI, but when poiinter clicks inside the ui -> Gives focus to it, the same with mouse leave, you need to click/tap outside the VisualElement and I believe there is confision about terminology, as this seems more like "ElementWasGivenFocusEvent" rather than MouseEnter/Leave.

The complete solution now looks something like this:

bool inBar = false;
void Start() {
topBarContainer =  rootUiVisualElement.Q("TopBar");
bottomBarContainer =  rootUiVisualElement.Q("BottomBar");

topBarContainer.RegisterCallback<MouseEnterEvent>((evt) =>
{
    Debug.Log("Mouse Enter TOP");

    if (evt.target == topBarContainer)
    {
        inBar = true;
    }
});

topBarContainer.RegisterCallback<MouseLeaveEvent>((evt) =>
{
    Debug.Log("Mouse Leave TOP");
    if (evt.target == topBarContainer)
    {
        inBar = false;
    }
}); }
//analogically for bottom bar

void Update() {
if (!inBar)
{

    Ray ray = mainCamera.ScreenPointToRay(position);
    if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider)
    {
        //do something useful
    }
} }

Upvotes: 0

Related Questions