Saving Inventory Between Scenes (Scriptable Objects)
Posted: Wed Apr 12, 2023 11:28 pm
Hello,
I've mastered saving serializable things like ints and strings using the method in this Pixel Crushers tutorial:
https://pixelcrushers.com/phpbb/viewtop ... f=9&t=4763
I've been stuck for a few days on saving my inventory though. I'm trying to use this method from the tutorial:
The problem is on this line:
This is my version:
I get this error:
foreach statement cannot operate on variables of type 'ItemSO' because 'ItemSO' does not contain a public instance or extension definition for 'GetEnumerator'
I tried adding a public Enumerator method to my ItemSO but then it requires more to be implemented, and I have no idea what to implement, I can't find it online, and I don't even know if that's the solution anyways.
Before I switch to the Opsive Ultimate Inventory, I want to ask here because it took a couple of weeks to set this up.
Below are the InventorySO and ItemSO scripts. I feel like pulling the item names should be simple, but I can't get past this error. Thanks for any help!
My InventorySO script:
My ItemSO script:
I've mastered saving serializable things like ints and strings using the method in this Pixel Crushers tutorial:
https://pixelcrushers.com/phpbb/viewtop ... f=9&t=4763
I've been stuck for a few days on saving my inventory though. I'm trying to use this method from the tutorial:
Code: Select all
public class InventorySaveData
{
public int money;
public List<string> itemNames;
}
public override string RecordData()
{
var inventory = GetComponent<Inventory>(); // Example -- get your inventory system script.
var saveData = new InventorySaveData();
saveData.money = inventory.money;
saveData.itemNames = new List<string>();
foreach (var item in inventory.item)
{
saveData.itemNames.Add(item.name);
}
return SaveSystem.Serialize(saveData); // Return serialized data.
}
Code: Select all
foreach (var item in inventory.item)
Code: Select all
public string RecordData()
{
var inventory = GetComponent<InventorySO>(); // Example -- get your inventory system script.
var saveData = new InventorySaveData();
saveData.itemNames = new List<string>();
foreach (var item in inventory.item)
{
saveData.itemNames.Add(item.name);
}
return SaveSystem.Serialize(saveData);
}
foreach statement cannot operate on variables of type 'ItemSO' because 'ItemSO' does not contain a public instance or extension definition for 'GetEnumerator'
I tried adding a public Enumerator method to my ItemSO but then it requires more to be implemented, and I have no idea what to implement, I can't find it online, and I don't even know if that's the solution anyways.
Before I switch to the Opsive Ultimate Inventory, I want to ask here because it took a couple of weeks to set this up.
Below are the InventorySO and ItemSO scripts. I feel like pulling the item names should be simple, but I can't get past this error. Thanks for any help!
My InventorySO script:
Code: Select all
namespace Inventory.Model
{
[CreateAssetMenu]
public class InventorySO : ScriptableObject
{
public ItemSO item;
[SerializeField]
public List<InventoryItem> inventoryItems;
[field: SerializeField]
public int Size { get; private set; } = 30;
public event Action<Dictionary<int, InventoryItem>> OnInventoryUpdated;
public void Initialize()
{
inventoryItems = new List<InventoryItem>();
for (int i = 0; i < Size; i++)
{
inventoryItems.Add(InventoryItem.GetEmptyItem());
}
}
public int AddItem(ItemSO item, int quantity)
{
if(item.IsStackable == false)
{
for (int i = 0; i < inventoryItems.Count; i++)
{
while(quantity > 0 && IsInventoryFull() == false)
{
quantity -= AddItemToFirstFreeSlot(item, 1);
}
InformAboutChange();
return quantity;
}
}
quantity = AddStackableItem(item, quantity);
InformAboutChange();
return quantity;
}
private int AddItemToFirstFreeSlot(ItemSO item, int quantity
, List<ItemParameter> itemState = null)
{
InventoryItem newItem = new InventoryItem
{
item = item,
quantity = quantity,
itemState =
new List<ItemParameter>(itemState == null ? item.DefaultParametersList : itemState)
};
for (int i = 0; i < inventoryItems.Count; i++)
{
if (inventoryItems[i].IsEmpty)
{
inventoryItems[i] = newItem;
return quantity;
}
}
return 0;
}
private bool IsInventoryFull()
=> inventoryItems.Where(item => item.IsEmpty).Any() == false;
private int AddStackableItem(ItemSO item, int quantity)
{
for (int i = 0; i < inventoryItems.Count; i++)
{
if (inventoryItems[i].IsEmpty)
continue;
if(inventoryItems[i].item.ID == item.ID)
{
int amountPossibleToTake =
inventoryItems[i].item.MaxStackSize - inventoryItems[i].quantity;
if (quantity > amountPossibleToTake)
{
inventoryItems[i] = inventoryItems[i]
.ChangeQuantity(inventoryItems[i].item.MaxStackSize);
quantity -= amountPossibleToTake;
}
else
{
inventoryItems[i] = inventoryItems[i]
.ChangeQuantity(inventoryItems[i].quantity + quantity);
InformAboutChange();
return 0;
}
}
}
while(quantity > 0 && IsInventoryFull() == false)
{
int newQuantity = Mathf.Clamp(quantity, 0, item.MaxStackSize);
quantity -= newQuantity;
AddItemToFirstFreeSlot(item, newQuantity);
}
return quantity;
}
public int AddItem(ItemSO item, int quantity, List<ItemParameter> itemState = null)
{
if(item.IsStackable == false)
{
for (int i = 0; i < inventoryItems.Count; i++)
{
while(quantity > 0 && IsInventoryFull() == false)
{
quantity -= AddItemToFirstFreeSlot(item, 1, itemState);
}
InformAboutChange();
return quantity;
}
}
quantity = AddStackableItem(item, quantity);
InformAboutChange();
return quantity;
}
public void RemoveItem(int itemIndex, int amount)
{
if (inventoryItems.Count > itemIndex)
{
if (inventoryItems[itemIndex].IsEmpty)
return;
int reminder = inventoryItems[itemIndex].quantity - amount;
if (reminder <= 0)
inventoryItems[itemIndex] = InventoryItem.GetEmptyItem();
else
inventoryItems[itemIndex] = inventoryItems[itemIndex]
.ChangeQuantity(reminder);
InformAboutChange();
}
}
public void AddItem(InventoryItem item)
{
AddItem(item.item, item.quantity);
}
public Dictionary<int, InventoryItem> GetCurrentInventoryState()
{
Dictionary<int, InventoryItem> returnValue =
new Dictionary<int, InventoryItem>();
for (int i = 0; i < inventoryItems.Count; i++)
{
if (inventoryItems[i].IsEmpty)
continue;
returnValue[i] = inventoryItems[i];
}
return returnValue;
}
public InventoryItem GetItemAt(int itemIndex)
{
return inventoryItems[itemIndex];
}
public void SwapItems(int itemIndex_1, int itemIndex_2)
{
InventoryItem item1 = inventoryItems[itemIndex_1];
inventoryItems[itemIndex_1] = inventoryItems[itemIndex_2];
inventoryItems[itemIndex_2] = item1;
InformAboutChange();
}
private void InformAboutChange()
{
OnInventoryUpdated?.Invoke(GetCurrentInventoryState());
}
}
[Serializable]
public struct InventoryItem
{
//public int ID;
public int quantity;
public ItemSO item;
public List<ItemParameter> itemState;
public bool IsEmpty => item == null;
public InventoryItem ChangeQuantity(int newQuantity)
{
return new InventoryItem
{
item = this.item,
quantity = newQuantity,
itemState = new List<ItemParameter>(this.itemState)
};
}
public static InventoryItem GetEmptyItem()
=> new InventoryItem
{
item = null,
quantity = 0,
itemState = new List<ItemParameter>()
};
}
}
Code: Select all
namespace Inventory.Model
{
public abstract class ItemSO : ScriptableObject
{
[field: SerializeField]
public bool IsStackable { get; set; }
public int ID => GetInstanceID();
[field: SerializeField]
public int MaxStackSize { get; set; } = 1;
[field: SerializeField]
public string Name { get; set; }
[field: SerializeField]
[field: TextArea]
public string Description { get; set; }
[field: SerializeField]
public Sprite ItemImage { get; set; }
[field: SerializeField]
public List<ItemParameter> DefaultParametersList { get; set; }
}
[Serializable]
public struct ItemParameter : IEquatable<ItemParameter>
{
public ItemParameterSO itemParameter;
public float value;
public bool Equals(ItemParameter other)
{
return other.itemParameter == itemParameter;
}
}
}