Reputation: 29
I'm creating a simple RPG 3D game in unity. I am pretty much beginner at coding. I've created a ScriptableObject class called Item so that i can simply create a new item and pass them properties from Inspector. Then I've created List to store items in characters Inventory. I've managed to make a code that adds the object to the list once they are picked up. The next step was an inventory UI - I've created 60 buttons that resemble slots in inventory and a pop out menu that shows up after pressing on them. The menu contains two buttons - Use and Remove. I'm creating Listeners for Use and Remove buttons once the menu is opened and if any of these is pressed i call method Use or Remove. I am storing information about the chosen inventory slot in an object of Item class.
Now the problem is - whenever i click multiple times on different items in inventory, even though i'm constantly trying to reset chosen object to null, somehow information about chosen item stacks. Once i press Use or Remove - each item that I've clicked is going to be affected.
Unity console is showing me (via Debug.Log) that I've entered a method with one object set, but when the method goes further - it's being done multiple times for each item clicked before. I am confused.
Code for ScriptableObject Item
using UnityEngine;
using UnityEngine.UI;
[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
new public string name = "New Item";
public Sprite icon = null;
public Image itemImage;
public bool isDefaultItem = false;
[TextArea(3, 10)]
public string ItemInfo;
public GameObject Prefab;
public Animator chestObtain;
public virtual void Use()
{
// Use the item
Debug.Log("Using " + name);
}
}
Code for Inventory (items storing)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public int space = 30;
#region Singleton
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;
public static Inventory instance;
private void Awake()
{
if (instance != null)
{
Debug.LogWarning("More than one instance of Inventory found!");
instance = this;
}
}
#endregion
public List<Item> items = new List<Item>();
public bool Add (Item item)
{
if (!item.isDefaultItem)
{
if (items.Count >= space)
{
Debug.Log("Not enough space");
return false;
}
items.Add(item);
if (onItemChangedCallback != null)
{
onItemChangedCallback.Invoke();
}
}
return true;
}
public void Remove(Item item)
{
Debug.Log("Removing " + item);
items.Remove(item);
if (onItemChangedCallback != null)
{
onItemChangedCallback.Invoke();
}
}
public void RemoveAt(int i)
{
if (i <= items.Count)
{
Debug.Log("Removing " + items[i]);
Debug.Log("List: " + items);
//items.RemoveAt(i);
if (onItemChangedCallback != null)
{
onItemChangedCallback.Invoke();
}
}
}
}
Code for Inventory methods
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class InventoryItemInfo : MonoBehaviour
{
public GameObject ItemInfoTab;
public bool ItemInfoTabIsOpen = false;
public Button OpenTab;
public Text Title;
public Text UseButtonText;
public Text RemoveButtonText;
public Text ItemInfo;
public int SlotID;
public Image ItemImage;
public Item test;
public Button RemoveButton;
public Button UseButton;
Inventory inventory;
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
ItemInfoTabIsOpen = false;
}
}
public void OpenTabPressed()
{
Debug.Log("test object after opening a tab: " + test);
test = null;
Debug.Log("test object after opening a tab and reseting: " + test);
UseButton.onClick.RemoveListener(OnUseButton);
RemoveButton.onClick.RemoveListener(OnRemoveButton);
if (ItemInfoTab.activeInHierarchy)
{
ItemInfoTabIsOpen = false;
}
int itemsCount = GameObject.Find("GameManager").GetComponent<Inventory>().items.Count;
if (test == null)
{
if (itemsCount > SlotID)
{
if (ItemInfoTabIsOpen == false)
{
ItemInfoTab.SetActive(true);
ItemInfoTabIsOpen = true;
}
test = GameObject.Find("GameManager").GetComponent<Inventory>().items[SlotID];
UseButton.onClick.AddListener(OnUseButton);
RemoveButton.onClick.AddListener(OnRemoveButton);
Debug.Log("SlotID: " + SlotID);
Debug.Log("Clicked item: " + test);
Title.text = test.name;
ItemInfo.text = test.ItemInfo;
ItemImage.sprite = test.icon;
}
else
{
Debug.Log("Emtpy inventory slot");
}
}
else
{
test = null;
Debug.Log("Test object set to null");
}
}
public void OnUseButton()
{
Debug.Log("test object to use: " + test);
test.Use();
test = null;
Debug.Log("test object after using: " + test);
}
public void OnRemoveButton()
{
ItemInfoTab.SetActive(false);
ItemInfoTabIsOpen = false;
Debug.Log("test object to remove: " + test);
FindObjectOfType<Inventory>().Remove(test);
test = null;
}
}
Last note - I've put all of these "test = null"; to try to overcome the issue but it didn't work.
I've just noticed in inspector that once i click on item and it's assigned to the slot in inventory - it's only getting empty after calling Use or Remove method - never in any other conditions (and it should after clicking onto other item).
Screenshot for empty slot https://prnt.sc/rezehc Screenshot for occupied slot Screenshot2
Idea - does this mean i am only resetting a "object variable" in script and not on actual item slot? If yes - how to set it back to null? I've got over 60 item slots that look like this -> Hierarchy Each action button contains the same script (look previous screenshots).
Upvotes: 0
Views: 888
Reputation: 20249
When you call RemoveListener
, you have to call with a reference to the method of the instance it was called with before. Basically, you'd have to get a reference to the previous InventoryItemInfo
then call:
UseButton.onClick.RemoveListener(previousInventoryItemInfo.OnUseButton);
RemoveButton.onClick.RemoveListener(previousInventoryItemInfo.OnRemoveButton);
Well, you don't seem to have a reference to that easily available. I'd recommend simply using RemoveAllListeners
:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class InventoryItemInfo : MonoBehaviour
{
public GameObject ItemInfoTab;
public bool ItemInfoTabIsOpen = false;
public Button OpenTab;
public Text Title;
public Text UseButtonText;
public Text RemoveButtonText;
public Text ItemInfo;
public int SlotID;
public Image ItemImage;
public Item test;
public Button RemoveButton;
public Button UseButton;
Inventory inventory;
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
ItemInfoTabIsOpen = false;
}
}
public void OpenTabPressed()
{
Debug.Log("test object after opening a tab: " + test);
test = null;
Debug.Log("test object after opening a tab and reseting: " + test);
UseButton.onClick.RemoveAllListeners();
RemoveButton.onClick.RemoveAllListeners();
if (ItemInfoTab.activeInHierarchy)
{
ItemInfoTabIsOpen = false;
}
int itemsCount = GameObject.Find("GameManager").GetComponent<Inventory>().items.Count;
if (test == null)
{
if (itemsCount > SlotID)
{
if (ItemInfoTabIsOpen == false)
{
ItemInfoTab.SetActive(true);
ItemInfoTabIsOpen = true;
}
test = GameObject.Find("GameManager").GetComponent<Inventory>().items[SlotID];
UseButton.onClick.AddListener(OnUseButton);
RemoveButton.onClick.AddListener(OnRemoveButton);
Debug.Log("SlotID: " + SlotID);
Debug.Log("Clicked item: " + test);
Title.text = test.name;
ItemInfo.text = test.ItemInfo;
ItemImage.sprite = test.icon;
}
else
{
Debug.Log("Emtpy inventory slot");
}
}
else
{
test = null;
Debug.Log("Test object set to null");
}
}
public void OnUseButton()
{
Debug.Log("test object to use: " + test);
test.Use();
test = null;
Debug.Log("test object after using: " + test);
}
public void OnRemoveButton()
{
ItemInfoTab.SetActive(false);
ItemInfoTabIsOpen = false;
Debug.Log("test object to remove: " + test);
FindObjectOfType<Inventory>().Remove(test);
test = null;
}
}
Upvotes: 3