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