I have an AddItem method, this method takes items and adds them to the list.
public void AddItem(string itemName1, int amount)
{
Item existingItem = inventory.Find(item => item.itemName == itemName1);
Debug.Log("existing item: "+ existingItem);
if (existingItem != null)
{
existingItem.itemAmount += amount;
}
else
{
Item newItem = new Item();
newItem.itemName = itemName1;
newItem.itemAmount = amount;
inventory.Add(newItem);
itemInInventoryCounter++;
}
}
And I have an OnTriggerEnter2D method, which takes the objects that the player collides with, and sends them to the AddItem method with appropriate parameters.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Item"))
{
Item collisionItem = collision.gameObject.GetComponent<Item>();
string itemName = collisionItem.itemName;
int itemAmount = collisionItem.itemAmount;
if (inventory.itemInInventoryCounter < inventory.maxItemInInvetory)
{
inventory.RefreshInventoryItems(itemName, itemAmount);
inventory.AddItem(itemName, itemAmount);
Destroy(collision.gameObject);
}
else
{
Debug.Log("envanter dolu");
}
}
}
The issue is that even if the item already exists, it always appears as empty. In other words, it never increases its amount; it always adds it as a new item.
I checked the list, and items are being added to the list. I did it as follows.
private void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
inventory.ShowInventory();
}
}
public void ShowInventory()
{
foreach (Item item in inventory)
{
Debug.Log(item.itemName + ": " + item.itemAmount);
}
}
Upon further examination, I've noticed that the items are not being added to the list properly. Although items are being added, they appear as "None(item)" in the Unity window. What does this signify? If they haven't been added, why I can see them on console window.
[System.Serializable]
public class Item : MonoBehaviour
{
public string itemName;
public int itemAmount;
public SpriteRenderer itemSprite;
public List<Sprite> inventory = new List<Sprite>();
public SpriteDatas spriteDatas;
public TextMeshPro itemAmountText;
private void Start()
{
itemAmountText.SetText(itemAmount.ToString());
itemSprite.sprite = GetSprite(itemName);
}
public Sprite GetSprite(string itemName)
{
switch (itemName)
{
default:
case "Sword": return spriteDatas.spritesList[0];
case "HealthPotion": return spriteDatas.spritesList[1];
case "ManaPotion": return spriteDatas.spritesList[2];
case "Coin": return spriteDatas.spritesList[3];
case "MedKit": return spriteDatas.spritesList[4];
}
}
}
public void RefreshInventoryItems(string itemName, int itemAmount)
{
if (itemInInventoryCounter <= maxItemInInvetory)
{
float itemsSlotCellSize = 110f;
RectTransform itemSlotRectTransform = Instantiate(itemSlotTemplate, itemSlotContainer).GetComponent<RectTransform>();
itemSlotRectTransform.gameObject.SetActive(true);
itemSlotRectTransform.anchoredPosition = new Vector2(x * itemsSlotCellSize, y * itemsSlotCellSize);
Image image = itemSlotRectTransform.Find("SlotItemPicture").GetComponent<Image>();
image.sprite = item.GetSprite(itemName);
TextMeshProUGUI uiText = itemSlotRectTransform.Find("amountText").GetComponent<TextMeshProUGUI>();
uiText.SetText(itemAmount.ToString());
x++;
if (x > 3)
{
x = 0;
y--;
}
}
}
public class Inventory : MonoBehaviour
{
public Item item;
public List<Item> inventory = new List<Item>();
public Transform itemSlotTemplate;
public Transform itemSlotContainer;
int x = 0;
int y = 0;
public int maxItemInInvetory;
public int itemInInventoryCounter = 0;
private void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
RemoveItem("Coin",76);
}
}
private void Start()
{
maxItemInInvetory = 3;
}
public void AddItem(string itemName1, int amount)
{
Item existingItem = inventory.Find(item => item.itemName == itemName1);
Debug.Log("existing item: "+ existingItem);
if (existingItem != null)
{
existingItem.itemAmount += amount;
}
else
{
Item newItem = new Item();
newItem.itemName = itemName1;
newItem.itemAmount = amount;
inventory.Add(newItem);
Debug.Log("burada");
itemInInventoryCounter++;
}
}
public void RemoveItem(string itemName, int amount)
{
//burada sağ tıkladığımız nesneye göre envanterden çıkartıp dünyada spawnlayacak.
Item existingItem = inventory.Find(item => item.itemName == itemName);
if (existingItem != null)
{
existingItem.itemAmount -= amount;
if (existingItem.itemAmount <= 0)
{
inventory.Remove(existingItem);
itemInInventoryCounter--;
}
}
}
public void RefreshInventoryItems(string itemName, int itemAmount)
{
if (itemInInventoryCounter <= maxItemInInvetory)
{
float itemsSlotCellSize = 110f;
RectTransform itemSlotRectTransform = Instantiate(itemSlotTemplate, itemSlotContainer).GetComponent<RectTransform>();
itemSlotRectTransform.gameObject.SetActive(true);
itemSlotRectTransform.anchoredPosition = new Vector2(x * itemsSlotCellSize, y * itemsSlotCellSize);
Image image = itemSlotRectTransform.Find("SlotItemPicture").GetComponent<Image>();
image.sprite = item.GetSprite(itemName);
TextMeshProUGUI uiText = itemSlotRectTransform.Find("amountText").GetComponent<TextMeshProUGUI>();
uiText.SetText(itemAmount.ToString());
x++;
if (x > 3)
{
x = 0;
y--;
}
}
}
public void ShowInventory()
{
foreach (Item item in inventory)
{
Debug.Log(item.itemName + ": " + item.itemAmount);
}
}
}
I think I see the issue(s) now!
From this line
Item collisionItem = collision.gameObject.GetComponent<Item>();
we can see that Item
is a MonoBehaviour
!
You can not create instances of a MonoBehaviour
using new
! - Well you can, bu it will be an invalid broken instance!
=> What you should do instead is use a different type for the item definition itself and for the component you can interact with.
I would probably
go with a ScriptableObject
for the item definitions - here you can reference all textures, define the name (e.g. name of the SO itself), etc.
For the component you collide with reference that ScriptableObject
so that
OnTriggerEnter2D
so it can either use it as key directly or its namepublic int Amount
for how many of that item to addThen finally in your inventory
you do neither store the component nor the ScriptableObject
item definitions but instead rather have a dedicated plain Serializable
type that only holds an amount and the underlying ScripableObject
reference (in order to use it as the lookup key)
The inventory could even be a Dictionary
You first call RefreshInventoryItems
which UI-wise always instantiate a new slot regardless of whether you already have such an item!
After that you do the AddItem
which does the check whether to add a new item or increase the counter
=> You rather want to do this in the opposite order and call the RefreshInventoryItems
after you either added a new item (=> spawn a new UI) or increased the amount (=> only update existing UI)
And finally as mentioned a minor one but the check for
if (inventory.itemInInventoryCounter < inventory.maxItemInInvetory)
would prevent you from collecting any of the already known item types as soon as all slots are occupied.
=> I think you only want to check for the maxItemInInvetory
when adding a new unknown item type. So that you can only have a certain maximum amount of different item types but can still keep collecting additional ones of those
Unless of course your intention is actually the above mentioned behavior in which case you can ignore this point ;)