Search Unity

Am I going about saving my Inventory the right way?

Discussion in 'Scripting' started by SaamBell, Jul 29, 2019.

  1. SaamBell

    SaamBell

    Joined:
    Mar 28, 2014
    Posts:
    128
    Just to quickly explain what my game is, over the last few weeks I've started putting together a little Sim like surivial game taking place on an Island where the player has to gather, craft, and complete missions to further get around the island and make life easier for the Player. I've included a screenshot below to give you a general feel and what the inventory looks like currently!


    Sims_Screenshot.png

    For the inventory system I have followed along with Brackeys RPG inventory System and currently have somewhat of a working system, you can pick up items on the island (the fruit for example), hover over an item to see it's detailed stats and how much of a certain stat it recovers (see the bars in the top left-right corners), as well as drop and consume an item.

    My island is going to take place over multiple scenes, segmenting parts of the island, and the current problem i'm facing is getting my Inventory to actually carry over to a new scene.
    What i've tried to far involves using a very fantastic Unity Asset called Easy Save, using this I have managed to carry over my Player stats to different scenes as this just included saving and loading the slider values, my Inventory however is a whole other story!

    Sims_Inventory.png

    Everytime I pick up an item, a new Item (Scriptable Object) is added to my Items list, which contains the likes of the Name, icon, stat increase amount, ect. This all works perfectly until it comes to saving my Inventory!

    Script for the Inventory
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using TMPro;
    6.  
    7. public class Inventory : MonoBehaviour {
    8.  
    9.     #region Singleton
    10.  
    11.     public GameObject player;
    12.     public static Inventory instance;
    13.  
    14.  
    15.     //Tooltip  Variables
    16.     [SerializeField]
    17.     private GameObject tooltip;
    18.  
    19.     public TextMeshProUGUI tooltipTitle;
    20.     public Image tooltipImage;
    21.  
    22.     public TextMeshProUGUI hungerTooltipValue;
    23.     public TextMeshProUGUI restTooltipValue;
    24.     public TextMeshProUGUI socialTooltipValue;
    25.     public TextMeshProUGUI hygineTooltipValue;
    26.     public TextMeshProUGUI bathroomTooltipValue;
    27.     public TextMeshProUGUI comfortTooltipValue;
    28.  
    29.  
    30.     private void Awake()
    31.     {
    32.  
    33.  
    34.      
    35.         instance = this;
    36.         tooltipTitle.GetComponent<TextMeshProUGUI>();
    37.         tooltipImage.GetComponent<Image>();
    38.  
    39.  
    40.     }
    41.  
    42.     #endregion
    43.  
    44.     public delegate void OnItemChanged();
    45.  
    46.     public OnItemChanged onItemChangedCallBack;
    47.  
    48.     public int space = 20;
    49.  
    50.     public List<Item> items = new List<Item>();
    51.  
    52.     public void Add (Item item)
    53.     {
    54.       //  if (!item.isKeyItem)
    55.       //  {
    56.             if (items.Count >= space)
    57.             {
    58.                 Debug.Log("Now enough space in Inventory!");
    59.                 return;
    60.             }
    61.             items.Add(item);
    62.  
    63.         if (onItemChangedCallBack != null)
    64.             {
    65.             onItemChangedCallBack.Invoke();
    66.             }
    67.       //  }
    68.         return;
    69.      
    70.     }
    71.     public void Remove (Item item)
    72.     {
    73.      
    74.             items.Remove(item);
    75.         if (onItemChangedCallBack != null)
    76.         {
    77.             onItemChangedCallBack.Invoke();
    78.         }
    79.     }
    80.  
    81.     public void ShowToolTip(IDescribable ToolTipitem)
    82.     {
    83.         tooltip.SetActive(true);
    84.         tooltipTitle.text = ToolTipitem.GetTitle();
    85.         tooltipImage.sprite = ToolTipitem.GetSprite();
    86.  
    87.         hungerTooltipValue.text = ToolTipitem.GetHungerToolTip().ToString("+#;-#;0");
    88.         restTooltipValue.text = ToolTipitem.GetRestToolTip().ToString("+#;-#;0");
    89.         socialTooltipValue.text = ToolTipitem.GetSocialToolTip().ToString("+#;-#;0");
    90.         hygineTooltipValue.text = ToolTipitem.GetHygineToolTip().ToString("+#;-#;0");
    91.         bathroomTooltipValue.text = ToolTipitem.GetBathroomToolTip().ToString("+#;-#;0");
    92.         comfortTooltipValue.text = ToolTipitem.GetComfortToolTip().ToString("+#;-#;0");
    93.  
    94.     }
    95.  
    96.     public void HideToolTip()
    97.     {
    98.         tooltip.SetActive(false);
    99.     }
    100.  
    101.  
    102.  
    103.    
    104.  
    105. }

    Inventory Slot Code

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.EventSystems;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using TMPro;
    7.  
    8. public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
    9. {
    10.    
    11.     public TextMeshProUGUI itemText;
    12.     public Image icon;
    13.     Item item;
    14.     public Button removeButton;
    15.     public GameObject dropItemModal;
    16.     public Animator spriteAnim;
    17.     public Button yesButton;
    18.  
    19.  
    20.     public void Start()
    21.     {
    22.      
    23.  
    24.     }
    25.  
    26.     public void AddItem (Item newItem)
    27.     {
    28.        
    29.      
    30.         spriteAnim.Play("SpriteBounce");
    31.         item = newItem;
    32.         icon.sprite = item.icon;
    33.         icon.enabled = true;
    34.         removeButton.interactable = true;
    35.    
    36.      
    37.  
    38.     }
    39.  
    40.     public void ClearSlot()
    41.     {
    42.         item = null;
    43.         icon.sprite = null;
    44.         icon.enabled = false;
    45.         removeButton.interactable = false;
    46.     }
    47.  
    48.     public void onRemoveButton()
    49.     {
    50.  
    51.          Inventory.instance.Remove(item);
    52.  
    53.         #region  
    54.         /*   dropItemModal.SetActive(true);
    55.         yesButton.onClick.AddListener(onYesClick);
    56.            itemText.text = item.name;
    57.  
    58.                   if (item.isKeyItem != false)
    59.                   {
    60.                       yesButtonDisabled.interactable = false;
    61.                       itemText.text = "You Can't Drop a Key Item!";
    62.                   }
    63.                   else
    64.                   {
    65.                       yesButtonDisabled.interactable = true;
    66.                   }
    67.                   */
    68.         #endregion
    69.  
    70.     }
    71.     #region
    72.     /* public void onYesClick()
    73.      {
    74.        //  Inventory.instance.Remove(item);
    75.          dropItemModal.SetActive(false);
    76.      }
    77.  
    78.      public void onNoClick()
    79.      {
    80.          dropItemModal.SetActive(false);
    81.      } */
    82.     #endregion
    83.  
    84.     public void UseItem()
    85.     {
    86.  
    87.         if (item != null)
    88.         {
    89.          
    90.             item.Use();
    91.         }
    92.     }
    93.  
    94.  
    95.  
    96.     public void OnPointerEnter(PointerEventData eventData)
    97.     {
    98.         //Show Tooltip
    99.         if (item != null)
    100.         {
    101.             Debug.Log(item.name + " " + "Is in this slot");
    102.            Inventory.instance.ShowToolTip(item);
    103.         }
    104.  
    105.         else
    106.         {
    107.             Debug.Log("Inventory Slot Empty");
    108.         }
    109.      
    110.     }
    111.  
    112.     public void OnPointerExit(PointerEventData eventData)
    113.     {
    114.         //Hide Tooltip
    115.         Debug.Log("Exit");
    116.         Inventory.instance.HideToolTip();
    117.     }
    118.  
    119.  
    120. }
    121.  
    And finally the saving Script which is attatched to a GameManager Object

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine.SceneManagement;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.EventSystems;
    6. using UnityEngine.UI;
    7. using TMPro;
    8.  
    9. public class SimpleSave : MonoBehaviour
    10. {
    11.  
    12.     public GameObject player;
    13.     public GameObject playerHolder;
    14.     public GameObject inventorySlot;
    15.     public GameObject inventoryIcon;
    16.  
    17.     public GameObject inventoryUI;
    18.     public GameObject canvas;
    19.  
    20.     public GameObject[] inventorySlotArray;
    21.  
    22.     private void Awake()
    23.     {
    24.         Load();
    25.     }
    26.  
    27.     public void Save()
    28.     {
    29.         List<Item> inv = GetComponent<Inventory>().items;
    30.         StatScripts statsRef = player.GetComponent<StatScripts>();
    31.         MenuPause MP = canvas.GetComponent<MenuPause>();
    32.      
    33.      
    34.         Debug.Log("Saved Game");
    35.         ES3.Save<float>("hungerValue", statsRef.currentHunger);
    36.         ES3.Save<float>("restValue", statsRef.currentRest);
    37.         ES3.Save<float>("socialValue", statsRef.currentSocial);
    38.         ES3.Save<float>("hygineValue", statsRef.currentHygine);
    39.         ES3.Save<float>("bathroomValue", statsRef.currentBathroom);
    40.         ES3.Save<float>("comfortValue", statsRef.currentComfort);
    41.  
    42.         ES3.Save<List<Item>>("listArray", GetComponent<Inventory>().items);
    43.  
    44.         foreach (GameObject i in inventorySlotArray)
    45.         {
    46.             ES3.Save<string>("inventoryText" + "text" + i, i.GetComponent<InventorySlot>().itemText.text);
    47.             ES3.Save<Image>("inventoryIcon" + i, i.GetComponent<InventorySlot>().icon);
    48.         }
    49.         MP.Resume();
    50.      }
    51.  
    52.  
    53.  
    54.     public void Load()
    55.     {
    56.         List<Item> inv = GetComponent<Inventory>().items;
    57.         InventoryUI IUI = inventoryUI.GetComponent<InventoryUI>();
    58.         MenuPause MP = canvas.GetComponent<MenuPause>();
    59.  
    60.         //Stats Loading
    61.  
    62.         StatScripts statsRef = player.GetComponent<StatScripts>();
    63.         Debug.Log("Loaded Game");
    64.         statsRef.currentHunger = ES3.Load<float>("hungerValue");
    65.         statsRef.currentRest = ES3.Load<float>("restValue");
    66.         statsRef.currentSocial = ES3.Load<float>("socialValue");
    67.         statsRef.currentHygine = ES3.Load<float>("hygineValue");
    68.         statsRef.currentBathroom = ES3.Load<float>("bathroomValue");
    69.         statsRef.currentComfort = ES3.Load<float>("comfortValue");
    70.  
    71.         GetComponent<Inventory>().items = ES3.Load<List<Item>>("listArray");
    72.         IUI.UpdateUI();
    73.  
    74.  
    75.         foreach (GameObject i in inventorySlotArray)
    76.         {
    77.             i.GetComponent<InventorySlot>().itemText.text = ES3.Load<string>("inventoryText" + "text" + i);
    78.             i.GetComponent<InventorySlot>().icon = ES3.Load<Image>("inventoryIcon" + i);
    79.         }
    80.         MP.Resume();
    81.  
    82.     }
    83.  
    84.     }
    This current Script does work in some way shape or form, but it just doesn't seem like the ideal way to do it. Currently upon changing scene the List will have been saved and loaded again into the new scene, the problem being that sometimes the sprites will be blank due to an object not loading properly when I'm switching scenes, it would seem I can still see an object in my list when this happens, but it will be broken and not contain any of the functioning data that the item should have! Apoligies for the very very long post but any help here would be greatly appreciated as I've been stuck for a while now and would like to be able to continue devloping!!

    Thanks guys!
     
  2. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    You should not be relying on saving/loading data to carry things over between scenes - save that (no pun intended) for data persistence between gameplay sessions

    In your case, you just need to make sure that the Singleton you’re using to keep track of the inventory persists between scenes.

    I’m on mobile, but look into the DontDestroyOnLoad attribute, which will basically carry your existing Singleton between scenes, along with all its data.