Dealing with multiple mouse states?

I am working on a project and it’s becoming more complicated than I know how to handle. Or at least it seems that way to my inexperienced mind.

I have 3rd person camera controller that allows the player to rotate the player side to side while holding the right mouse button and mouselook while holding down the left mouse button. When it is in that rotation/mouselook mode, I turn the cursor off (to make it look nicer without the mouse cursor jittering in the center of the screen).

But, there are elements in the game that I want the player to interact with using the mouse. UI hotbars, interactable world objects, NPCs, etc.

So I wrote a mouseover script that disables the mouse rotation/mouselook when the pointer is over the ability hotbar. That works fine, so I thought about extending that to the other objects that the player might interact with, but then I realized that just because the mouse pointer is hovering over an NPC, the player may still want to turn or mouselook, so I don’t want it disabled in those cases.

How do other people handle this their games? Am I on the right track, but just haven’t gone far enough? Or is there a better way that I am not thinking of?

Thanks :slight_smile:

I would definitely consolidate all of your input into one place, rather than having various scripts handle different logic, but wrap the actual logic into a state machine (with enter, exit and update calls) so it’s neatly compartmentalized.

class MouseLookState : IMouseState
{
    public void Enter() { hide the mouse cursor }
    public void Exit() { show the mouse cursor }
    public void Update()
    {
        if mouse up { stateMachine.ChangeState(new MouseIdleState()); }
        else { rotate the camera }

        // no logic for highlighting NPCs and what not
    }
}

class MouseIdleState : IMouseState
{
   public void Update()
   {
      if mouse over ui == false
      {
         if mouse down { stateMachine.ChangeState(new MouseLookState(); }
         else { mousing over npcs logic }
      }
   }
}

Thanks GroZZleR.

I have all my inputs together, but they are within the player movement controller, which isn’t really where I want them I’m thinking.

I’ll try splitting them out and looking into a state machine.

I think part of this is your choice on how you want it to be.
For me, I like that over the UI disables my movement + my camera movement, but over other in-game (stuff), it does not. This way, a player can still interact with non-UI items, but they could also just be moving themselves or the camera and it doesn’t matter.

Right, and that’s what I want too. I’m just trying to figure out how to make it work.

Does anyone have an example or a tutorial of how to set something like this up?

with an event system in the game/scene, you can do: if(EventSystem.current.IsPointerOverGameObject())
However, if you have other game objects you can click, then it’s a little more complicated, because you have to find the object and see if it’s on the UI layer (I think…)
I subclassed the Event System (I think?) and tested this, and it worked… sorry I don’t have the exact details atm. But inside there , there is protected member I think that has the current game object (pointer is over).

I don’t know if this is going to help anyone but I came up with a different solution. First, you define a Rect where you control mouse positions:

public Rect movableRect;

void Awake()
{
    movableRect = new Rect(0, 0, Screen.width, Screen.height);
}

public void ResetMovableSpace()
{
    movableRect.xMin = 0;
    movableRect.yMin = 0;
}

public void IncreaseMovableSpace(InventoryUI inventoryUI)
{
    Rect ib = inventoryUI.GetInventoryBounds();
    if (inventoryUI.GetAlignment() == "Right")
    {
        movableRect.xMax += ib.width;
    }
    else
    {
        movableRect.xMin -= ib.width;
    }
}

public void DecreaseMovableSpace(InventoryUI inventoryUI)
{
    Rect ib = inventoryUI.GetInventoryBounds();
    if (inventoryUI.GetAlignment() == "Right")
    {
        movableRect.xMax -= ib.width;
    }
    else
    {
        movableRect.xMin += ib.width;
    }
}

With that, you can change what happens using the PlayerController:

void Update()
{
    if (Input.GetKeyDown(KeyCode.I))
    {
        // Check if inventory is open
        if (InventoryManager.instance.inventoryState == InventoryManager.State.Open)
        {
            MouseManager.instance.IncreaseMovableSpace(inventoryUI);
            InventoryManager.instance.inventoryState = InventoryManager.State.Closed;
        } else if (InventoryManager.instance.inventoryState == InventoryManager.State.Closed)
        {
            MouseManager.instance.DecreaseMovableSpace(inventoryUI);
            InventoryManager.instance.inventoryState = InventoryManager.State.Open;
        }
    }

    if (MouseManager.instance.movableRect.Contains(Input.mousePosition))
    {
        MoveOrPickItem();
    }
}

You can use the same logic with an NPC inventory, set the position inside the canvas and use alignment.