Using New Input System with UI Components

Hi All,

I am trying to use the new input manager on my UI / Inventory to handle multiple control schemes later down the track. At this point on time, I am only focusing on Keyboard and mouse input.

After some research, it looks like the way to achieve using the new input manager with my inventory UI is to use the Input System UI Input Module.
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/UISupport.html#pointer-type-input

However, I can’t work out how to integrate this into my inventory UI. What I want to be able to do is to register Right-Click and Left-Click on my inventory slots with the new input manager and call different methods like AddItem or MoveItem.

Note: I understand it is possible to do to this IPointerClickHandler interface and OnPointerClick but I am hoping to add controller support later and the new input system is amazing with the support it offers of all different input types so I am hoping to future proof my code with this system

Currently, my inventory is set up where there are 36 Slots sitting inside an array / List.
Each slot is a prefab that has the Input System UI Input Module attached with the default setup

Each slot has a script attached called SlotScriptV2, where I make a reference to the Input System UI Input Module with the below code:

public class SlotScriptV2 : MonoBehaviour
{
[SerializeField] InputSystemUIInputModule UI;

private void Start()
{
UI = GetComponent<InputSystemUIInputModule>();
}
}

Once the reference is complete, I tried to call the right-click through the Update Method with a simple debug.log to hopefully return which slot was click:

private void Update()
{
if(UI.rightClick)
{
Debug.Log("Click on " + this.name); //this.name will return the slot that is clicked on
}
}

Unfoutantly this did not work, and the Console just returned 999+ messages since UI.rightClick was always returning true for every slot.

Is someone able to offer to advise on what I am doing wrong and what I need to change to get this working?
If you have any code examples I could follow, that would be extremely helpful.

I have provided my full inventory code below for full transparency:

InventoryScript

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryScriptV2 : MonoBehaviour
{

    //Singleton Pattern prevents mutiple instances of the class. In this case the inventory
    #region Singleton

    public static InventoryScriptV2 instance;

    private void Awake()
    {
        if (instance != null) //If the instance is not null, that means an instance of the inventory is active
        {
            Debug.LogWarning("More then once instance of the inventory has been found");
            return;
        }
        instance = this;
    }

    #endregion


    //Variables
    //This is for Debugging
    [SerializeField]
    public List<Item> _items = new List<Item>(); //This create a a list against the inventory GameObject that will accept the scripable object "Item"
    public List<SlotScriptV2> _slots = new List<SlotScriptV2>(); //This is a list of all slots in the inventory. The slots are linked to this list via the unity inspector


    //Properties


    //Unity Methods


    //Methods

    /// <summary>
    /// Add an Item to the Inventory. Takes a parameter of "item"
    /// This might have to become a bool at a later date just incase i am adding items picked up off the ground
    /// </summary>
    /// <param name="item"></param>
    public void AddItemToInventory(Item item)
    {
        //Add to stack
        if (item.MyStackSize > 0)
        {
            if (PlaceInStackSlot(item) == true) //If placeInStack returns true, return from the method
            {
                return;
            }
        }

        //If can't add to stack, add to empty slot
        PlaceInEmptySlot(item);
    }

    //Remove Items
    public void RemoveItemFromInventory(Item item)
    {
        _items.Remove(item); //Remove is a build in function of the List Type. It will remove whatever Object is specified as long as the Object Type matches the list type
    }

    //Move Items


    //This method is called if the AddItemToInventory Method determines that an item needs to be added to a new empty slot.
    private bool PlaceInEmptySlot(Item item)
    {
        //Check each slot, to determine if an item can be added
        foreach (SlotScriptV2 slot in _slots)
        {
            Debug.Log("Debug " + slot.name); //Remove This later
            Debug.Log("Debug IsEmpty: " + slot.isEmpty); //Remove this later
            if (slot.isEmpty == true) //isEmpty is located on SlotScriptV2. If isEmpty is true, proceed to add the item to the slot
            {
                slot.AddItemToSlot(item); //If the slot is empty, add the item and return true if the item was added
                return true;
            }
        }

        return false; //If the above paths do not return a true, the we return false. In this case, after each slot is checked, if no slots return true, we return fasle as we could not add an Item
    }

    //This method is called if the AddItemToInventory Method determines that an item can be stacked  on to an exisiting slot. Return's True if the item was added to a existing slot successfully
    private bool PlaceInStackSlot(Item item)
    {
        foreach (SlotScriptV2 slot in _slots) //Check each slot in the inventory
        {
            if (slot.AddItemToStack(item)) //If AddItemToStack returns true, return from this method reporting TRUE
            {
                return true; //Return True if the item was added to Stack
            }
        }

        return false; //Return false if item was not added to stack
    }

}

SlotScriptV2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem.UI;
using UnityEngine.UI;

public class SlotScriptV2 : MonoBehaviour
{
    //Future Anthony, If your method/Variable is using a get/set, it is a property. If you declare a public bool <Name> {} with no get or set, it is a method.
    //Local Variables to this script will be prefixed with an underscore. EG _item
    //Properties to this script will be prefixed as with "my" eg myItem

    //Variables
    [SerializeField] private ObservableStack<Item> _items = new ObservableStack<Item>(); //ObservableStack is an event that keeps track of each stack on a slot
    [SerializeField] private Image _icon; //This is the image that sits on the slot
    [SerializeField] private Text _stackSizeText; //This is mapped in the UI against the slot prefab
    [SerializeField] InputSystemUIInputModule UI;

    //Properties
    //This getter property will allow other classes and methods to access the "items" on the Obserablestack _items via the variable known as slotItems
    public ObservableStack<Item> slotItems
    {
        get
        {
            return _items;
        }

    }

    //This getter property will return true if the _item stack on a slot is 0. This means the slot is empty. If it returns false, the slot is not empty.
    public bool isEmpty
    {
        get
        {
            return slotItems.Count == 0; //If the count is 0, this means the slot is empty becasue there are no items in the stack on the slot. this will return true
        }
    }

    //This getter property is called when we want to check (Peek) at the current item on the slot. We check the item on the slot and pass it to the property "MyItem" which we can then do extra logic
    //such as checking the Items properties/metadata such as its name and max stack size (located in item.cs)
    public Item MyItem
    {
        get
        {
            if (!isEmpty) //If this slot is not empty. Return the item in the slot. If there is no item, return NULL
            {
                return slotItems.Peek();
            }

            return null;
        }
    }

    public int slotItemCount
    {
        get
        {
            return slotItems.Count;
        }
    }


    private void Start()
    {
        UI = GetComponent<InputSystemUIInputModule>();
    }

    private void Update()
    {

        if(UI.rightClick)
        {
            Debug.Log("Click on " + this.name);
        }

    }

    //Add Item to Slot
    //This will return true when an item has been added to the slot
    public bool AddItemToSlot(Item item)
    {
        slotItems.Push(item); //This adds the item to the stack _items
        _icon.sprite = item.MyIcon; //This sets the icon on the slot equal to the icon from scriptable object Item
        _icon.color = Color.white; //set the icon UI image to white when an item has been added (This is to remove the alpha that hides the image allowing the image allocated in the previous line to display)
        updateStackCount(); //Update the Text UI Element on the slot to represent the number of items on the slot
        item.MyInventorySlot = this; //This is how an item knows what slot it is on.
        return true;
    }


    //This function will try to stack the item on the slot currently being interacted with. If it adds the item to the stack, it returns true. If it can't stack, it returns false
    public bool AddItemToStack(Item item)
    {
        //First Check, if the slot is not empty. We are only interested in in stacking on non-empty slots (if isEmpty returns false, the slot is empty)
        //Second Check, we are checking the item we are trying to add to the slot against the item already on the slot (MyItem Property contains all teh information about the item on the slot) 
        //Third Check, Check the count of items on the stack against how many items of the same type can be stacked. This is determined myStackSize on the Item.cs (myStackSize is a property created from _StackSize)
        if (isEmpty == false && item.name == MyItem.name && slotItems.Count < MyItem.MyStackSize)
        {
            slotItems.Push(item);
            item.MyInventorySlot = this; //This tells the current slot what item is on it
            updateStackCount(); //Update the Text UI Element on the slot to represent the number of items on the slot
            return true; //When returned true, means we can stack the item
        }

        return false; //When returned false, means we can't stack the item
    }

    //Use Items
    public void UseItem(Item item)
    {
        item.UseItem();
    }

    //Move Item From Slot
    public void MoveItem(Item item)
    {
        Debug.Log("Moving " + item.name);
    }


    public void updateStackCount()
    {
        if(slotItemCount >= 1)
        {
            _stackSizeText.text = slotItemCount.ToString(); //Set the text UI Element on the Slot equal to the count if Item in the stack on the slot
            _stackSizeText.color = Color.white; //If the colour of the text is hidden due to alpha being set to none  or not white, set it to white so it is now visiable
            _icon.color = Color.white; //If the colour of the Icon is hidden due to alpha being set to none or not white, set it to white so it is now visiable
        }
        else if (slotItemCount <= 0)
        {
            _stackSizeText.color = new Color(0, 0, 0, 0); //This sets the text on the slot to have no colour and no alpha which makes it invisible. Items with a stacksize of 0 do not need a stacksize since there is no item on the slot
            _icon.color = new Color(0, 0, 0, 0); //This sets the text on the slot to have no colour and no alpha which makes it invisible. Items with a stacksize of 0 do not need a stacksize since there is no item on the slot
        }
    }
}

Please Note: I am a self-taught programmer, so my code is mostly trial and error and following youtube tutorials so I apologize if it is difficult to read or follow

Thanks for the help in advance
MegaTdog

I share many of your sentiments here Mega. Hopefully you got this section back on track with the new system, or perhaps you are still fighting the good fight with those lovely IPointerDowns and such.

On the surface the new input system seems much more intuitive and straight forward. Alas, no more tracking down event data just to move an item to holster or inventory.

I have the new system working with most of my funloop, why are these UI buttons a complete ass beating to get working.

Let me know if you would like another set of eyes on it. And if its something else… hey I’m happy to lend some support. Hit me up.

Tooma