Block Raycast with UI

Stormi

Member
I am currently using ScreenPointToRay and Physics.Raycast to have the destination for my players NavmeshAgent determined when clicking somewhere and getting a valid hit as a result. Unfortunately these Raycasts go through the Inventory UI and thus the player keeps moving around when clicking something in the Inventory UI.

I tried to see if the attached Graphic Raycaster component can do this, but whatever I set as settings in there, the issue remains. So I just wanted to ask, if there is any option in UIS to prevent this before I add something to my own methods to make an open UI ignore those raycasts?
 
I would highly recommend you disable all player inputs while the menus are opened.

You can listen to an event for when a panel/menu is opened/closed to know when to enable/disable player input (including click to move)

You could use the c_GameObject_OnPanelOpenClose_PanelEventData or the c_GameObject_OnGameplayPanelSelected_Bool event depending on what better suits your needs.

Check this page if you aren't sure how events work https://opsive.com/support/documentation/ultimate-inventory-system/events/
 
Unfortunately I seem to struggle a bit too much with this after all. I checked the documentation but there still is something that I do not get fully (which for sure is my lack of experience here as there are plenty of good comments everywhere).

What I did so far is create a new script and attach it to the Gameplay Panel in the scene which felt like the most reasonable thing to do. The script itself looks like this:

C#:
using UnityEngine;
using Opsive.UltimateInventorySystem.Core;
using Opsive.Shared.Events;

namespace RPG.Control
{
    public class UIControl : MonoBehaviour
    {
        void Start()
        {
            EventHandler.RegisterEvent<bool>(gameObject, EventNames.c_GameObject_OnGameplayPanelSelected_Bool, HandleUIControl);
        }

        void Update()
        {
            // test event execution only in order to see if HandleUIControl is executed properly
            EventHandler.ExecuteEvent<bool>(gameObject, EventNames.c_GameObject_OnGameplayPanelSelected_Bool, true);
        }

        private void HandleUIControl(bool panelStatus)
        {
            Debug.Log(panelStatus);
        }

        private void OnDestroy()
        {
            EventHandler.UnregisterEvent<bool>(gameObject, EventNames.c_GameObject_OnGameplayPanelSelected_Bool, HandleUIControl);
        }
    }
}

Now, doing it this way I get the value "True" written in the console for every update, just as expected. But the "ExecuteEvent" in Update was only for test purposes because I didn't get any feedback otherwise. So my question now is:

Do I have to add "ExecuteEvent" somewhere manually (for example wherever the panel is opened/closed) or is my entire setup done incorrectly? Personally I was expecting the "RegisterEvent" to be enough in order for "HandleUIControl" to write something in the console, but right now when using either button to open inventory or equipment in my scene, nothing happens. Which might be because neither of them affects the gameplay panel status but if so, I am not entirely sure what to do about it.
 
The reason you are not getting the built-in event to trigger your function is because the target is different.

the first parameter (where you put 'gameobject') should actually be the panel owner, meaning your player game object.
I understand it wasn't obvious, I'll update the comment in the EventNames files.

Just to give an example this should work (not tested):

Code:
var panelOwnerGameObject = InventorySystemManager.GetInventoryIdentifier(1).Inventory.gameobject;
EventHandler.RegisterEvent<bool>(panelOwnerGameObject, EventNames.c_GameObject_OnGameplayPanelSelected_Bool, HandleUIControl);
 
In hindsight that actually makes sense and was probably something I could have thought of myself, sorry for that. Changing the target to the panelOwnerGameObject does notice the events now. The only thing I find weird is the following:

- Having nothing open EventNames.c_GameObject_OnGameplayPanelSelected_Bool returns TRUE and when either Inventory or Equipment are openend it returns FALSE. Shouldn't this be the other way around?

- Opening and Closing inventory on it's own follows the same True and False pattern from above. The same goes for Equipment on it's own. There is a possibility though to somehow mess up the event feedback. Ignoring here whether or not nothing openend should be TRUE or FALSE it obviously at least should always be the same all the time. It isn't though:

This way it seems ok:
  1. Open Inventory => Returns False
  2. Open Equipment => Returns Nothing
  3. Close Equipment => Returns False
  4. Close Inventory => Returns True
This way the end result should be the same but something changes:
  1. Open Inventory => Returns False
  2. Open Equipment => Returns Nothing
  3. Close Inventory => Returns True (Which shouldn't be the case as there still is a panel open now)
  4. Close Equipment => Returns False AND automatically re-opens the Inventory
It can be done the other way around as well (meaning opening equipment first and then inventory) and the result is the same issue but the panels are switched in regards to how they are affected. So it doesn't seem to be the panel itself but the event registration. Maybe because opening a second panel does not get registered.

I am opening and closing both panels with individual buttons using DisplayPanel.SmartToggle.

Trying to debug it I also came across a weird behavior that fixes the above issue:
  1. Open Panel A => Returns False
  2. Open Panel B => Returns Nothing
  3. Close Panel A => Returns True (Which shouldn't be the case as there still is a panel open now)
  4. Hover over Panel B with the mouse cursor (no clicking or anything, just hover) => Returns False
  5. Close Panel B => Returns True correctly now

Any ideas here? I'm not sure if thats related to my project anymore or if this is something within the UIS and how it handles the events.
 
That's how we designed panels.
The smart close, will open the panel that was used to open that panel.

start with Gameplay Panel
Open Panel A => previous panel is gameplay panel
Open Panel B => previous panel is Panel A
Close Panel A => this will open the previous panel of Panel A meaning gameplay panel (not the last panel that was opened before the current one).
Hover over Panel B is the same as opening it if you have set it as a selectable panel => the previous panel of B is now set to gameplay panel.
Close Panel B => open gameplay panel.

The reason we chose to do it this way is to allow nested panels to work as well as floating panels.

This the default on how smart open/close work.
If you want to have more control you can pass in the parameters of the previous panel when opening the panel.
You could even set the previous panel manually panel.SetPreviousPanel(DisplayPanel previousPanel).
You could do that just before closing the panel if that is what you want, or when opening the other panel.

It really depends on everyone use case.

My advice to you would be to create a custom smart open/close panel component, which opens and closes panels exactly the way you want. You should be able to get all the information you need in the DisplayPanelManager component
 
Just wanted to get back here and say thanks for the suggestions. I was able to get the desired outcome with a custom script and the use of SetPreviousPanel(). So now I can use my referenced hotkeys (currently I = inventory, K = abilities, E = equipment) to open these individual panels via SmartToggle() without the issue of having it re-open unwanted panels again due to the default setup you described.
 
Top