[Help] I don't know how to create a stacking system for my inventory!
I want to create something to stack my items, but I don't know how. I want to have a maximum of how much it can stack and than use a new inventoryslot. This is my code:
Scriptable Item code:
using UnityEngine;
[CreateAssetMenu(fileName = "new item", menuName = "Inventory/Item")]
public class Item : ScriptableObject {
new public string name = "new item";
public Sprite icon = null;
public GameObject objectToDrop;
public string description;
public int maxStackSize;
public bool isStackable;
}
The InventorySlot script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Collections;
using TMPro;
public class InventorySlot : MonoBehaviour {
public Image icon, icon2;
public Button removeButton;
public Transform player;
public GameObject uiDescription, sellItem, nextStage;
public TextMeshProUGUI textDescription, itemNameText;
private Item item;
private void Start()
{
icon.enabled = false;
textDescription = textDescription.GetComponent<TextMeshProUGUI>();
itemNameText = itemNameText.GetComponent<TextMeshProUGUI>();
}
private void Update()
{
if (icon.sprite != null)
{
icon.enabled = true;
}
else {
icon.enabled = false;
}
}
public void AddItem(Item newItem) {
item = newItem;
icon.sprite = item.icon;
icon.enabled = true;
removeButton.GetComponent<Image>().enabled = true;
}
public void ClearSlot() {
icon.sprite = null;
icon.enabled = false;
removeButton.GetComponent<Image>().enabled = false;
}
public void OnRemoveButton() {
PlayerInventory.instance.Remove(item);
Instantiate(item.objectToDrop, player.transform.position, Quaternion.identity);
uiDescription.SetActive(false);
item = null;
}
public void UIOpenButton() {
if (item != null) {
uiDescription.SetActive(!uiDescription.activeSelf);
icon2.sprite = item.icon;
textDescription.text = item.description;
itemNameText.text = item.name;
}
}
}
The PlayerInventory script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInventory : MonoBehaviour {
public GameObject inventory, escapeMenu, playerUIStats, playerSelflookInventory;
public int inventorySpace;
public List<Item> items = new List<Item>();
public bool inventoryAcces;
private bool inventoryClose;
#region Singleton
public static PlayerInventory instance;
private void Awake()
{
if (instance != null) {
Debug.LogWarning("More then one inventory");
return;
}
instance = this;
}
#endregion
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallBack;
private void Start()
{
inventoryAcces = true;
}
// Update is called once per frame
void Update () {
KeyInput();
Inventory();
}
#region Inventory- &EscapeClose/Open
public bool Add(Item item) {
if (items.Count >= inventorySpace) {
Debug.Log("not enough space to pickup");
return false;
}
items.Add(item);
if (onItemChangedCallBack != null)
{
onItemChangedCallBack.Invoke();
}
return true;
}
public void Remove(Item item) {
items.Remove(item);
if (onItemChangedCallBack != null)
{
onItemChangedCallBack.Invoke();
}
}
}
(I have deleted some code in the PlayerInventory script about opening and closing the inventory, because I think it isn't needed for this problem. If you need to see it please say it).
The inventoryUI updating script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryUI : MonoBehaviour {
public Transform itemsParent;
private PlayerInventory inventory;
private InventorySlot[] slots;
void Start () {
inventory = PlayerInventory.instance;
inventory.onItemChangedCallBack += UpdateUI;
slots = itemsParent.GetComponentsInChildren<InventorySlot>();
}
private void UpdateUI()
{
for (int i = 0; i < slots.Length; i++)
{
if (i < inventory.items.Count)
{
slots[i].AddItem(inventory.items[i]);
}
else
{
slots[i].ClearSlot();
}
}
}
}
If someone knows how to create the stacking system please let me know. I'm struggeling with it for almost a week now.
(I also have a bug with dropping a item and then pick it up, but when I pick it up it changed to a different item. I think I can do that by my own, but I have found the bug just a hour ago. It's not my main question, but if you know what is causing that bug please let me know).
Thanks for helping.
I see that you have a List member. I assume this contains all the different kinds of items that are stored in inventory. What I do NOT see is storage for how $$anonymous$$ANY items are in each inventory slot.
$$anonymous$$g. if you had ANOTHER List member. This one could store how many items of that each kind, are in each slot. I do see the definition for the ITE$$anonymous$$ class, and see $$anonymous$$AX values, but NOT "current inventory" quantity values stored in there. (This is what I would do, store the count of items, and the kind item referenced, in a single list- you might need to create a new class for this.)
I don’t have a list of different items only a list of all items in the inventory, the probleem I have is that I want to acces the list of all items and when a item is added to see if a item of the same name is already in the inventory. If that’s the case I want to not add it in a different slot, but in the slot where the item of the same name is stored. But if the max stack size is reached to use a new slot. Do you know how to achieve that?
Well, for starters, you're gonna have to add a way to count how many items are in a slot's stack.
Answer by Glurth · Aug 16, 2018 at 03:35 PM
Here is an uncompiled/untested (may contain errors) example. I only filled in code for the AddItem function and will leave the RemoveItem, and a couple other potentially useful functions, for you to complete. But I think the AddItem function example should give you an idea on how to do those.
class InventorySlot
{
public string nameOfTypeOfItemStored;
public int inventoryCount = 0;
}
class Inventory
{
public const int numberOfInventorySlots=20;
public const int maxInventoryCountPerSlot = 100; // max 100 per slot
public InventorySlot[] allInventorySlots = new InventorySlot[numberOfInventorySlots]; ///creates 20 slots in each inventory
//this function returns the number of items successfully stored in inventory. If not equal to the parameter quantity- the function failed to store all them.
public int AddItem(string itemName, int quantity = 1)
{
int originalQuantity = quantity;
for (int i = 0; i < numberOfInventorySlots; i++)
{
if (allInventorySlots[i] != null) //is there anything in this inventory slot?
{
if (allInventorySlots[i].nameOfTypeOfItemStored == itemName)
{
int freeSpace = maxInventoryCountPerSlot - allInventorySlots[i].inventoryCount;
if (freeSpace > quantity)
{
allInventorySlots[i].inventoryCount += quantity;
return originalQuantity; // all items stored- done
}
else// not enough free space in this slot to store all of the quantity
{
quantity = quantity - freespace;
allInventorySlots[i].inventoryCount += freespace;
//now we continue looping with the unstored portion in "quantity"
}
}
}
}// end for loop
//if we reach here, we have not yet stored the full quanity of items, and will need to create a new slot
for (int i = 0; i < numberOfInventorySlots; i++)
{
if (allInventorySlots[i] == null || allInventorySlots[i].inventoryCount==0)
{
allInventorySlots[i] = new InventorySlot();
allInventorySlots[i].nameOfTypeOfItemStored = itemName;
if (quantity <= maxInventoryCountPerSlot)
{
allInventorySlots[i].inventoryCount = quantity;
return originalQuantity;
}
else
{
allInventorySlots[i].inventoryCount = maxInventoryCountPerSlot;
quantity -= maxInventoryCountPerSlot;
}
}
}
//if we reach here, we have not yet stored the full quanity of items, and there are not enough slots to do so
return originalQuantity - quantity;
}
public int RemoveItems(string itemName, int quantity = 1)
{...}
public int[] SlotsContainingItem(string itemName)
{...}
public int TotalNumberOfItemsInInventory(string itemName)
{...}
}
I will try your code too to see if it workes better then the code I have created.
Answer by FernandoHC · Aug 16, 2018 at 03:48 PM
Done this before, but with database instead. The first thing you want is to have a stack/list/array somewhere, lets say you can have it in the UI item itself.
List<Item> stack
Second thing you want to have are methods to add, remove and access the item from that stack, what I do is always interact with them from the top down. Since I do multiple selection within the stack, not only I fetch the last one, but a range from it.
Finally you want you want yo have a numeric display on your InventorySlot class which will simply display the item.count value, updated whenever add/remove are called.
Answer by berndunity · Aug 16, 2018 at 08:05 PM
I got the stacking system working only thing that doesn’t work is that the itemcount per stack does not move with the item if it’s set to a new itemslot. If you know how to do that please let me know. There is a UpdateUI script which handles the place items are stored in there item slot and which place a item in a new itemslot if a item is dropped. I think I have to write the code for moving itemscount with their item should be added there, I only don’t know how.
On each inventoryslot I have a itemcount, so how would you do this?Would you create itemcounter if there is a item placed and how would you relatie that item count to the object? Because there is not a item or object added to the inventory it only set a sprits to a sprite renderer.
Your answer
Follow this Question
Related Questions
Index was out of range. error 1 Answer
Retrieving values from list of Scriptable Objects 1 Answer
Comparing distance of vector 3's on a dynamic growing list 0 Answers
Foreach freezing computer 1 Answer
Foreach skipping game objects. 1 Answer