Reputation: 45
I have created an inventory system in Unity using C#. I currently have a simple stack system in my inventory where if an item is greater than the stack it stops adding it to the current inventory slot. But I was wondering how can I set it so it will add an instance of the same item to a different slot once the other slot is full?
Here's my code if you guys need me to share anymore classes let me know, any help would be greatly appreciated.
/**
* Controller class used to handle the logic and functionality of the
inventory system
**/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InventoryController : MonoBehaviour
{
Inventory inv;
ItemDatabase database;
public int maxSize = 3;
private void Awake()
{
database = GetComponent<ItemDatabase>();
inv = GetComponent<Inventory>();
inv.slotAmount = 25;
inv.background = GameObject.Find("SlotBackgroundPanel");
inv.slotPanel = inv.background.transform.Find("SlotPanel").gameObject;
for (int i = 0; i < inv.slotAmount; i++)
{
inv.items.Add(new InventoryModel());
inv.slots.Add(Instantiate(inv.inventorySlot));
inv.slots[i].GetComponent<ItemSlot>().id = i;
inv.slots[i].transform.SetParent(inv.slotPanel.transform);
}
}
public void AddItem(int id)
{
InventoryModel itemToAdd = database.FetchItemByID(id);
if (itemToAdd.Stackable && CheckItemInInventory(itemToAdd))
{
for (int i = 0; i < inv.items.Count; i++)
{
if (inv.items[i].ID == id)
{
ItemData data = inv.slots[i].transform.GetChild(0).GetComponent<ItemData>();
data.amount++;
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
break;
}
}
}
else
{
for (int i = 0; i < inv.items.Count; i++)
{
if (inv.items[i].ID == -1)
{
inv.items[i] = itemToAdd;
GameObject itemObj = Instantiate(inv.inventoryItem);
itemObj.GetComponent<ItemData>().inventoryModel = itemToAdd;
itemObj.GetComponent<ItemData>().amount = 1;
itemObj.GetComponent<ItemData>().slot = i;
itemObj.transform.SetParent(inv.slots[i].transform);
itemObj.transform.position = Vector2.zero;
itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
itemObj.name = itemToAdd.Title;
break;
}
}
}
}
public void RemoveItem(int id)
{
InventoryModel itemToRemove = database.FetchItemByID(id);
if (itemToRemove.Stackable && CheckItemInInventory(itemToRemove))
{
for (int j = 0; j < inv.items.Count; j++)
{
if (inv.items[j].ID == id)
{
ItemData data = inv.slots[j].transform.GetChild(0).GetComponent<ItemData>();
data.amount--;
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
if (data.amount == 0)
{
Destroy(inv.slots[j].transform.GetChild(0).gameObject);
inv.items[j] = new InventoryModel();
break;
}
if (data.amount == 1)
{
inv.slots[j].transform.GetChild(0).transform.GetChild(0).GetComponent<Text>().text = "";
break;
}
break;
}
}
}
else
{
for (int i = 0; i < inv.items.Count; i++)
{
if (inv.items[i].Title == null && inv.items[i].ID == id)
{
Destroy(inv.slots[i].transform.GetChild(0).gameObject); inv.items[i] = new InventoryModel();
break;
}
}
}
}
public void FullItem(int id)
{
InventoryModel itemIsFull = database.FetchItemByID(id);
if (itemIsFull.Stackable && CheckItemInInventory(itemIsFull))
{
for (int y = 0; y < inv.items.Count; y++)
{
if (inv.items[y].ID == id)
{
ItemData data = inv.slots[y].transform.GetChild(0).GetComponent<ItemData>();
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
if (data.amount >= maxSize)
{
inv.slots[y].transform.GetChild(0).transform.GetChild(0).GetComponent<Text>().text = "3";
data.amount = 3;
Debug.Log(data.amount);
break;
}
}
}
}
}
public bool CheckItemInInventory(InventoryModel inventoryModel)
{
for (int i = 0; i < inv.items.Count; i++)
if (inv.items[i].Title == inventoryModel.Title)
return true;
return false;
}
}
Class used for View
using System.Collections;
/**
* View class, used to handle the User Interface
**/
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public GameObject background;
public GameObject slotPanel;
InventoryController inventoryController;
public GameObject inventorySlot;
public GameObject inventoryItem;
public int slotAmount;
public enum type { diamond = 0, iron = 1, gold = 2, fuel = 3 };
public List<InventoryModel> items = new List<InventoryModel>();
public List<GameObject> slots = new List<GameObject>();
private void Start()
{
inventoryController = GetComponent<InventoryController>();
inventoryController.AddItem((int)type.diamond);
inventoryController.AddItem((int)type.diamond);
inventoryController.AddItem((int)type.diamond);
inventoryController.AddItem((int)type.diamond);
inventoryController.AddItem((int)type.gold);
inventoryController.AddItem((int)type.fuel);
inventoryController.FullItem((int)type.diamond);
}
}
Class used for Model
/**
* Model class used to handle and store variables
**/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryModel
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool Stackable { get; set; }
public string Slug { get; set; }
public Sprite Sprite { get; set; }
public InventoryModel(int id, string title, string description,
bool stackable, string slug)
{
this.ID = id;
this.Title = title;
this.Description = description;
this.Stackable = stackable;
this.Slug = slug;
this.Sprite = Resources.Load<Sprite>("Sprites/Items/" + slug);
}
public InventoryModel()
{
this.ID = -1;
}
}
Json File
[
{
"id" : 0,
"title" : "Diamond",
"value" : 5,
"stats":{
"defence": 9,
"power" : 8,
"weight" : 5
},
"description": "Mined Diamond is stronger than metal",
"stackable" : true,
"rarity" : 10,
"slug": "Diamond"
},
{
"id" : 1,
"title" : "Iron",
"value" : 2,
"stats":{
"defence" : 5,
"power" : 6,
"weight" : 7
},
"description" : "Mined Iron is stronger than bronze",
"stackable" : false,
"rarity" : 6,
"slug" : "Metal"
},
{
"id" : 2,
"title" : "Gold",
"value" : 2,
"stats":{
"defence" : 0,
"power" : 0,
"weight" : 0
},
"description" : "Gold is valuable",
"stackable" : false,
"rarity" : 10,
"slug" : "Gold"
},
{
"id" : 3,
"title" : "Fuel2",
"value" : 2,
"stats":{
"defence" : 0,
"power" : 0,
"weight" : 0
},
"description" : "Fuel is needed for ship engines",
"stackable" : true,
"rarity" : 2,
"slug" : "Fuel2"
}
]
Upvotes: 0
Views: 2586
Reputation: 219
Ah, I remember this problem when I was making my inventory system. I made a similar one to Minecraft, slot based, drag and drop.. etc. Anywho lost the source code wah.
I was really, really bored so I decided to copy your code and add a function to check if the item's amount is less than a maximum stack size. Take a look:
InventoryModel itemToAdd = database.FetchItemByID(id);
// First check if the item is in the inventory
// This check can be discarded. See below...
// You might be able to use this check in some form of anti-cheat system, so I've left it there.
if (CheckItemInInventory(itemToAdd))
{
// Iterate through the inventory and check items against their ID/Name
for (int i = 0; i < inv.items.Count; i++)
{
// If the item in the slot has the same ID as the item we want to add...
if (inv.items[i].ID == id)
{
// Check if the item is actually stackable and the slot is not full
// I.E the stack size (amount) is less than the max stack size.
// You'll need to add a new variable to your InventoryModel class
// int maxStackSize
if (inv.items[i].amount < inv.items[i].maxStackSize && itemToAdd.Stackable)
{
ItemData data = inv.slots[i].transform.GetChild(0).GetComponent<ItemData>();
data.amount++;
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
break;
}
// If not, then we skip adding a new item because this slot is already occupied and it's stack size is full
}
else if (inv.items[i].id == -1)
{
// If we encounter an empty slot, add a new item.
inv.items[i] = itemToAdd;
GameObject itemObj = Instantiate(inv.inventoryItem);
itemObj.GetComponent<ItemData>().inventoryModel = itemToAdd;
itemObj.GetComponent<ItemData>().amount = 1;
itemObj.GetComponent<ItemData>().slot = i;
itemObj.transform.SetParent(inv.slots[i].transform);
itemObj.transform.position = Vector2.zero;
itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
itemObj.name = itemToAdd.Title;
}
}
// If the code's execution reaches this point, then we are essentially skipping action on the slot.
// This means that we were not able to find an item that matched the ID OR the stack size was full...
// So we keep scanning the other slots next in line...
}
else
{
// do something if the player tried to add an item but it does not exist in their inventory
// or something doesn't quite add up... Good for anti-cheat systems.
}
As you can see, I've made some adjustments and some optimizations to your code, including removing some redundant checks. You were checking the player's inventory twice. Once to verify if they had the item, and then again to add the item to the inventory. You can do both operations in one swoop.
I should also mention that I wrote the code in visual studio, so it should be good for copy-paste. Enjoy!
Upvotes: 1