- Home /
What is the best way to set up an inventory system?
Hey guys,
Recently I've been trying to make an inventory system at the moment I have 5 categories of items inheriting from item class and the following way they have been initialized. First off I was wondering if these was a good way to how all items in the first place as I think it would take up a lot of RAM?? public List allItems = new List();
     [SerializeField] Sprite[] weaponImagesInv;
     [SerializeField] Sprite[] armorImagesInv;
     [SerializeField] Sprite[] aidImagesInv;
     [SerializeField] Sprite[] miscImagesInv;
     [SerializeField] Sprite[] ammoImagesInv;
 
     [SerializeField] Sprite[] weaponImages;
     [SerializeField] Sprite[] armorImages;
     [SerializeField] Sprite[] aidImages;
     [SerializeField] Sprite[] miscImages;
     [SerializeField] Sprite[] ammoImages;
 
     [SerializeField] GameObject[] bulletPrefabs;
 
     void Start () {
         allItems.Add(new Weapon(0.000f, "Fists", weaponImagesInv[0], weaponImages[0], 1, 1, Weapon.WepType.Melee, Weapon.WepSubType.None, 1, 1));
         allItems.Add(new Weapon(0.001f, "Swag Ray", weaponImagesInv[1], weaponImages[1], 1, 1, Weapon.WepType.Ranged, Weapon.WepSubType.AssaultRifle, 1, 0.1f, 1, 1, 10, 1, bulletPrefabs[0]));
 
 
         allItems.Add(new Armor(1.000f, "Helmet for your Head", null, 1, 1, Armor.ArmorType.Head, 0, 1));
         allItems.Add(new Aid(2.000f, "Name of Some Medicine", null, 1, 1, 1, 1));
         allItems.Add(new Misc(3.000f, "Swagger", null, 1, 1500));    
         allItems.Add(new Ammo(4.000f, "Standard", null, 0, 1));
         allItems.Add(new Ammo(4.001f, "MoreDamage!", null, 0, 5));
     }
Secondly when I try and access the these items I get referred to the item created by the previous way instead of the item in the inventory, this is a result of instances I'm pretty sure but I'm not sure how to fix this issue.
     public List<Item> itemInv = new List<Item>();
 public InitialiseItems allInv;
 [SerializeField] GameManager gm;
 float weight = 0;
 public void AddItem(Item i){
         if(itemInv.Contains(i))
             itemInv[itemInv.IndexOf(i)].quantity += i.quantity;
         else{
             itemInv.Add(i);
         }
         gm.DisplayNotification(i.itemName + " was added");
     }
     
     public void RemoveItem(Item i){
         if(itemInv.Contains(i)){            
             if(i.quantity < itemInv[itemInv.IndexOf(i)].quantity){
                 itemInv[itemInv.IndexOf(i)].quantity -= i.quantity;
             }
             else{
                 itemInv.Remove(i);
             }
             gm.DisplayNotification(i.itemName + " was removed");
         }
     }
Answer by Cherno · Sep 13, 2015 at 10:30 AM
Use this code to copy values between two instances.
     using System;
     using System.Reflection;//for copying objects
     using System.Linq;//for string[].Contains()
     using UnityEngine;//for print
     
     public class CopyData {
         
         /// <summary>
         /// Copies the data of one object to another. The target object gets properties of the first. 
         /// Any matching properties (by name) are written to the target.
         /// </summary>
         /// <param name="source">The source object to copy from</param>
         /// <param name="target">The target object to copy to</param>
         public static void CopyObjectData(object source, object target)
         {
             CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
         }
         
         /// <summary>
         /// Copies the data of one object to another. The target object gets properties of the first. 
         /// Any matching properties (by name) are written to the target.
         /// </summary>
         /// <param name="source">The source object to copy from</param>
         /// <param name="target">The target object to copy to</param>
         /// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
         /// <param name="memberAccess">Reflection binding access</param>
         public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)
         {
             string[] excluded = null;
             if (!string.IsNullOrEmpty(excludedProperties))
             {
                 excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             }
             
             MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
     
             foreach (MemberInfo Field in miT)
             {
                 string name = Field.Name;
                 
                 // Skip over excluded properties
                 if (string.IsNullOrEmpty(excludedProperties) == false
                     && excluded.Contains(name))
                 {
                     continue;
                 }
                 
                 
                 if (Field.MemberType == MemberTypes.Field)
                 {
                     FieldInfo sourcefield = source.GetType().GetField(name);
                     if (sourcefield == null) { continue; }
                     
                     object SourceValue = sourcefield.GetValue(source);
                     ((FieldInfo)Field).SetValue(target, SourceValue);
                 }
     
                 else if (Field.MemberType == MemberTypes.Property)
                 {
                     PropertyInfo piTarget = Field as PropertyInfo;
                     PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess);
                     if (sourceField == null) { continue; }
                     
                     if (piTarget.CanWrite && sourceField.CanRead)
                     {
                         object targetValue = piTarget.GetValue(target, null);
                         object sourceValue = sourceField.GetValue(source, null);
                         
                         if (sourceValue == null) { continue; }
                         
                         if (sourceField.PropertyType.IsArray
                             && piTarget.PropertyType.IsArray
                             && sourceValue != null ) 
                         {
                             CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue);
                         }
                         else
                         {
                             CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue);
                         }
                     }
                 }
     
             }
         }
         
         private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue)
         {
             //instantiate target if needed
             if (targetValue == null
                 && piTarget.PropertyType.IsValueType == false
                 && piTarget.PropertyType != typeof(string))
             {
                 if (piTarget.PropertyType.IsArray)
                 {
                     targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
                 }
                 else
                 {
                     targetValue = Activator.CreateInstance(piTarget.PropertyType);
                 }
             }
             
             if (piTarget.PropertyType.IsValueType == false
                 && piTarget.PropertyType != typeof(string))
             {
                 CopyObjectData(sourceValue, targetValue, "", memberAccess);
                 piTarget.SetValue(target, targetValue, null);
             }
             else
             {
                 if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)
                 {
                     object tempSourceValue = sourceField.GetValue(source, null);
                     piTarget.SetValue(target, tempSourceValue, null);
                 }
                 else
                 {
                     CopyObjectData(piTarget, target, "", memberAccess);
                 }
             }
         }
         
         private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue)
         {
             int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);
             Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);
             Array array = (Array)sourceField.GetValue(source, null);
             
             for (int i = 0; i < array.Length; i++)
             {
                 object o = array.GetValue(i);
                 object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
                 CopyObjectData(o, tempTarget, "", memberAccess);
                 targetArray.SetValue(tempTarget, i);
             }
             piTarget.SetValue(target, targetArray, null);
         }
     }
 
Use it like this:
 Item newItem = new Item();
 CopyData.CopyObjectData(ItemTemplate, newItem);
It doesn't work D: won't even copy the itemName which is a string
Post your code then. You would do it like this:
  public void AddItem(Item i){
          if(itemInv.Contains(i))
              itemInv[itemInv.IndexOf(i)].quantity += i.quantity;
          else{
             Item newItem = new Item();
             CopyData.CopyObjectData(i, newItem);
              itemInv.Add(newItem);
          }
          gm.DisplayNotification(i.itemName + " was added");
      }
 public void AddItem(Item i){
     if(itemInv.Contains(i))
         itemInv[itemInv.IndexOf(i)].quantity += i.quantity;
     else{
         Item newItem = new Item();
         CopyData.CopyObjectData(i, newItem);
         itemInv.Add(newItem);
     }
     if(this.transform.tag == "Player")
         gm.DisplayNotification(i.itemName + " was added");
 }
 public class Item {
     public enum Type{
         Weapon,
         Armor,
         Aid,
         $$anonymous$$isc,
         Ammo
     }
 
     public string itemName;
     public Type type;
     public Sprite invImage;
     public Sprite image;
     public float weight;
     public float value;
     public float id;
     public int quantity;
 
     public Item (){
         this.itemName = "";
         this.type = Type.$$anonymous$$isc;
         this.invImage = null;
         this.image = null;
         this.weight = 0;
         this.value = 0;
         this.id = 0;
         this.quantity = 0;
     }
 }
that's how i did it but when i try and use the newly copied object it says its values are null which is weird since its string should be "" before going into the copyData
Hint: Don't use enums or any classes named "Type", as this is used by System and can (and will) lead to problems. Name it "ItemType" or something like this ins$$anonymous$$d. Also, don't name variables "type" for the same reason.
It probably doesn't have anything to do with the issues you are having, though. All I can say is that the CopyData script works and is reliable, I have used is many times in the past.
Okay, thanks man I'll try and figure it out :)
do you think it has something to do with it being a Weapon that inherits from Item?
Possibly, I don't know. I never use class inheritance, I ins$$anonymous$$d keep it all in one class with sub-classes as required.
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                