I've already created the inventory and everything works fine. Now I should implement the saving and loading of the inventory (on file). However, I find myself stuck on how to proceed. I was thinking of creating an Inventory Data script to get serializable data and then save it. I'm not using scriptable object. Would you have any advice for me? Below is the inventory code.
public class Inventory2 : MonoBehaviour
{
public bool inventoryEnabled;
public GameObject inventory, slotHolder;
private Transform[] slot;
public int level;
void Start()
{
level = SceneManager.GetActiveScene().buildIndex;
GetAllSlots();
}
void Update()
{
if (Input.GetAxis("Inventory") != 0)
{
inventoryEnabled = !inventoryEnabled;
}
if(inventoryEnabled)
{
inventory.SetActive(true);
}
else
{
inventory.SetActive(false);
}
}
public void OnTriggerEnter(Collider other)
{
if (other.tag == "Clues")
{
AddClue(other.GetComponent<Clue2>());
}
}
public void AddClue(Clue2 clue)
{
Text description = clue.GetComponent<Text>();
for (int i = 0; i < 2; i++)
{
if(slot[i].GetComponent<Slot2>().empty == true && clue.pickedUp == false)
{
slot[i].GetComponent<Slot2>().clue = clue;
slot[i].GetComponent<Slot2>().descriptionFinal = description;
slot[i].GetComponent<Slot2>().empty = false;
clue.GetComponent<Clue2>().pickedUp = true;
}
}
}
public void GetAllSlots()
{
slot = new Transform[Clue2.objects];
for(int i = 0; i < Clue2.objects; i++)
{
slot[i] = slotHolder.transform.GetChild(i);
slot[i].GetComponent<Slot2>().empty = true;
}
}
}
public class Slot2 : MonoBehaviour
{
public Clue2 clue;
public bool empty;
public Text descriptionFirst, descriptionFinal;
void Awake()
{
}
void Update()
{
if (clue)
{
this.GetComponentInChildren<Text>().text = descriptionFinal.text;
}
else
{
this.GetComponentInChildren<Text>().text = descriptionFirst.text;
empty = true;
}
}
}
public class Clue2 : MonoBehaviour
{
public static int objects = 0;
public static int objectsCollected = 0;
public Text description;
public bool pickedUp;
public GameObject cluePopUpPanel, canvasCluesPanel;
public Canvas canvasHUD;
public static bool activeClue = false;
void Awake()
{
objects++;
}
void Update()
{
if (canvasCluesPanel.gameObject.activeSelf == true && Input.GetAxis("PickUp") != 0)
{
activeClue = true;
cluePopUpPanel.gameObject.GetComponent<UnityEngine.UI.Text>().text = description.text;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
if (canvasCluesPanel.gameObject.activeSelf == false)
{
canvasCluesPanel.gameObject.SetActive(true);
}
}
}
private void OnTriggerStay(Collider other)
{
if (other.tag == "Player" && activeClue == true)
{
cluePopUpPanel.gameObject.SetActive(true);
cluePopUpPanel.GetComponentInChildren<Text>().text = this.GetComponent<Text>().text;
canvasCluesPanel.gameObject.SetActive(false);
}
if (other.tag == "Player" && activeClue == false)
{
cluePopUpPanel.gameObject.SetActive(false);
canvasCluesPanel.gameObject.SetActive(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == "Player" && activeClue == true)
{
cluePopUpPanel.gameObject.SetActive(false);
canvasCluesPanel.gameObject.SetActive(false);
activeClue = false;
if(objectsCollected < objects)
{
objectsCollected++;
}
}
else
{
cluePopUpPanel.gameObject.SetActive(false);
canvasCluesPanel.gameObject.SetActive(false);
activeClue = false;
}
canvasHUD.gameObject.SetActive(true);
}
}
A good tutorial can be found here.
As a good practice Store the data you want to save in a class. Create the SlotData, like so. So try converting them like so. This class must have the attribute System.Serializable.
One example could be this
[System.Serializable]
public class SlotData
{
public bool containsItem = false;
public string Description;
//other possible elements
public int amount;
}
The InventoryData will be just an array of SlotData.
[System.Serializable]
public class InventoryData
{
public SlotData[] inventorySlots;
}
Somewhere in your code you update the Inventory. You must setup this data, probably from the monobehaviour. Basically you add all the info you want in your class.
public void PrepareToSave()
{
//setup the inventory
var yourInventory = new InventoryData();
//fill all the slots, you must also calculate their amount
yourInventory.inventorySlots = new SlotData[CalculateYourAmount];
//fill all the slots here
for (int i= 0; i < CalculateYourAmount; i++)
{
//fill all the slots
yourInventory.inventorySlots[i] = CreateTheSlot();
}
//this go to the next step
SaveYourInventory(yourInventory);
}
As you asked you may use BinaryFormatter and FileStream.
private void SaveYourInventory(InventoryData yourInventory)
{
var savePath = Application.persistentDataPath + "/inventory.dat";
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(savePath);
bf.Serialize(file, yourInventory);
file.Close();
}
Then you can just load the inventory like this.
public void LoadYourInventory()
{
var savePath = Application.persistentDataPath + "/inventory.dat";
if (File.Exists(savePath))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(savePath, FileMode.Open);
InventoryData yourInventory = (InventoryData) bf.Deserialize(file);
file.Close();
//do what you want with the inventory
...
}
}
You can also find a Save Manager system here.
And if you want to go more advanced you can use this optimized formatter (or save it for the future if you get back to the save/load business).