- Home /
How to save multiple instances of the same class
How would I go about saving my game?
I´d like to point out I´m pretty new to Unity and coding in general, so I may not be familiar with all the terms. I´m not looking for you to code my game, but rather point me to the right direction.
I´m making a game where the player is a shopkeeper. The game is going to be an idle game, where you naturally need to save your progress. There is 75 different items and 200 different customers. All the items and customers are created in the inspector. There is an item-script, which I attach to all the items (hammer, axe, sword etc). In the script there is a class that contains values like quantity of said item in the shop and current price of the item. Those values are modified by the player via UI buttons in-game. The items differ from each other by the values I assign to them via the inspector. Those values are the likes of damage of the item and the base value of “need” the item puts out.
The customers don´t need to be created in the inspector, since they all are alike. They just have random values (personalities) and needs for the items. The personalities are created randomly at the start of the game. But when you start the game the second time, the personalities are loaded from a file (the personalities may change a little based on your actions). Same goes for the needs. I know it´s going to be a lot of work, but I´m planning to make the need system values like needHammer, needAxe, needSword etc. This also makes it so that I don´t have to refer to other classes, since I understand that makes saving a wee bit harder. So every customer has a customer-script with a class that holds the personality values and the need values. Nothing needs to be assigned in the inspector.
The game is going to be saved locally on the phone/pc. I don´t want to use playerprefs, even I know not to use that. I have looked into binary serialization, XML serialization and some different saving assets, but I´m not sure which way to go. I´ve read something about XML being able to support lists of classes, which might be good for this situation?
I have also gone through a lot of questions here related to this question but most of the answers just go "Look into Binary formatting", totally overlooking the fact that this would make potentially hundreds of save files. So one more thing is that I would prefer that saving the game could make as little files as possible. I think I would know how to do this using binary serialization, but to my understanding my method would create 75 save files for items and another 200 files for the customers. That is less than ideal.
As I said, I´m pretty new to making games, but trust me, this game is not going to be as complicated as it might seem.
Thanks a lot in advance.
No sure why binary serialisation would "make potentially hundreds of save files" (why can't you just serialise to the same file?) but for me it's not the way to go anyway because I'd want my file format to be easily human read/writable so I could create/edit save games (for testing). If you use a binary format then you're going to end up needing to create a tool for that, but it comes for free if you use a text format. One solution you didn't mention is using json - which would give you this (and in a less bloated way than xml). Look into UnityEngine.JsonUtility
I was strongly under the impression that if I have many instances of the same class and I save them in the same file, there would be trouble when loading as the load script couldn't tell to which instance of the class it should give the values. $$anonymous$$eaning hammer would get the values of a sword or there would be a critical error.
And I'm thinking I like my save data so that one can't just modify it at least not as a text file.
But anyway thank you for the reply and I will definitely look into json.
So how do you think you'd be able to load data from multiple files and assign it to (or use it to create) specific instances? You need to save some meta information somewhere, don't you?
Answer by StewVanB · May 03, 2019 at 06:33 PM
I think you should look into Json serialization. I also advise you to look into how you are storing your data. Games leverage all sorts of different technologies when tackling these challenges. You should be asking yourself a few questions:
What data is important and unique?
Can my data be reconstructed from more basic values?
Does my save system need to be portable between games?
Will I store my user's saved games online or locally to their device?
Do I want to support multiple saved files?
How do I save files for multiple users?
What does a frame state of my game look like?
Does my game have a natural state where a save makes sense?
Obviously this list could go on for a bit, but this is how you should be thinking about the task.
For some extra info on a couple of the above points. Data reconstruction is an important skill to understand and master. An example could be how you store a sword item:
// SowrdData
public class SwordData {
string name;
int cost;
string imagePath;
float damage;
float durability;
public SwordData(){
}
}
// SwordData as a json:
{
"name":"Excalibur",
"cost":5000,
"imagePath":"UI\Swords\Excalibur",
"damage":1200.0,
"durability":12
}
// You can save space by constructing the image path from name when the item is loaded
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
}
// If your names and images are not 1 to 1 you can go the imageId route and store the id in the data
{
"name":"Excalibur",
"cost":5000,
"imageId":1002,
"damage":1200.0,
"durability":12
}
//by not storing the image path you save 19 x 4 bytes = 76 bytes
//Cases like this is why most games use local databases to store item stats and tie them to integers or fixed length ids.
//You can also save an entire inventory of swords in one string via json it would look sorta like this:
"shop_inventory":[
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
},
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
},
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
},
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
},
{
"name":"Excalibur",
"cost":5000,
"damage":1200.0,
"durability":12
}]
But yeah, look into Json, it is an easy beginner way to store data. If you search for "Json .Net" in the asset store the package by ParentElement, LLC is very good and easy to use:
// convert the array of swords into json then write it to a file
string outData = JsonConvert.Serialize(shopInventory);
File.Write(outData);
// Then you would read the string from the file into "shopData" and then convert it back into shopInventory
Sword[] shopInventory = JsonConvert.Deserialize<Sword[]>(shopData);
Sorry that the formatting is so bad, I am at work and was drawn to answer this question. Good luck to you and if you want to bounce ideas off me you can message me directly.
Answer by Rugbug_Redfern · May 03, 2019 at 09:43 PM
Here's a link to a great tutorial I used to add data saving to my games: https://www.raywenderlich.com/418-how-to-save-and-load-a-game-in-unity
You don't need to create hundreds of save files with a Binary Formatter. What I did was I had lists of classes (List, List), which I would use a Binary Formatter to save to a single file.
Answer by rohmomollero · May 06, 2019 at 06:25 PM
Thanks a lot for the answers guys! I looked into JSON and it definitely looks like it would be easiest, since I can just dump my data there. StewVanB thanks for the thorough answer but it seems like I may have explained this wrong. I have actually changed this shopkeeping thing from swords and such to basic shop items like apples and oranges. This might also help you understand that this game is more about the numbers than the attributes of the items.
Answers to your questions StewVanB: all instances of Item and Customer will have important and unique values. All values are either strings, floats or ints. I´m planning on a local idle game, so there is going to be just one local save file used by one player. At minimum the game would save the needed data when the game is closed.
So I´ll start this over a little and I´ll copy the code I have tried. I have an Item prefab. I have put two Items to the scene and named them Apple and Orange. The Item Prefab has scripts called Item, ItemData and Buttons.
For now the Item scripts goes like this. It is going to have a lot more in the future. I will assign the itemData in the inspector.
public class Item : MonoBehaviour
{
public ItemData itemData;
string dataPath;
private void Start()
{
itemData = GetComponent<ItemData>();
dataPath = Path.Combine(Application.persistentDataPath, "ItemData.txt");
Debug.Log(Application.persistentDataPath);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.S))
SaveItemData(itemData, dataPath);
if (Input.GetKeyDown(KeyCode.L))
LoadItemData(dataPath);
}
static void SaveItemData (ItemData data, string path)
{
string jsonString = JsonUtility.ToJson(data);
using (StreamWriter streamWriter = File.CreateText(path))
{
streamWriter.Write(jsonString);
}
}
void LoadItemData (string path)
{
using (StreamReader streamReader = File.OpenText(path))
{
string jsonString = streamReader.ReadToEnd();
JsonUtility.FromJsonOverwrite(jsonString, itemData);
}
}
And the ItemData scripts goes like this. ItemData will also have a lot more values in the future. These are just for testing to see if it will work and I will build on that:
public class ItemData : MonoBehaviour
{
public int shopAmount;
public float currentPrice;
}
I will then put Apple in the Apple Gameobject´s ItemData in the inspector. And same thing for Orange.
There are UI elements; Buttons, that you press so you can buy more Apples to the store or rise the asking price of said Apple. Im not going to copy the Buttons script here, but it is going to modify ItemData and the Gameobject Apple is going to be put in the Buttons-scripts ItemData in the inspector.
This goes just great, I modify the values with the buttons in-game, so that Apple has quantity of 10 and price of 10. Orange has quantity of 20 and price of 20. Then I save the game and rise the values for Apple to 15/15 and Orange to 25/25. I press Load and boom. Apple and Orange both have values of 10/10. The ItemData.txt has just one string that goes like this: {"shopAmount":10,"currentPrice":10}
And I was hoping for two strings, to each it´s own.
Rugbug_Redfern I think the Binary formatter list solution would work but it would make me do a LOT of work. I understood it so that there has to be lists for every value. But since my Customers will have about 80 values, it would be a lot easier to just dump it all to a Json string, if that would be possible. Furthermore I think I don´t need the info to be non-readable. If I can do it like this in Json, I will.
So the question is: is my whole design critically flawed? Is saving doable like this?
Cool, I was just using the swords as an example since you had mentioned hammer/axes/swords. What it looks like is happening is that your SaveItemData function is overwriting the previous writes. Each item is saving its data to the same file. you could write a bigger class to control writing to the file so that everything stays neat but this will get very cumbersome very quickly.
What I recommend you do is write a SaveShop function that iterates over your shops items and gets their data and then writes all the data as one write.
public class ShopData {
public Item[] shopItems;
public ShopData(){
}
public void SaveShop(){
string shopData = JsonConvert.Serialize(this);
using(StreamWriter sw = File.CreateText(path)){
sw.Write(shopData);
}
}
}
public class Item(){
public int count;
public float cost;
public Item(){
}
}
//Json would look like this
{
"shopItems":[{
"name":"Orange",
"count":20,
"price":1.5
},
{
"name":"Apple",
"count":10,
"price":1.25
},
{
"name":"Banana",
"count":40,
"price":0.60
}]
}
Thanks a lot! Sorry it has taken me so long to answer. $$anonymous$$y job and the kids keep me real busy and I try to squeeze in some time for this hobby as well from time to time.
So I got JSON.net and it seems like it would be nice. But for the life of me I don´t understand what you mean. I already decided I would design my code again from scratch but then I decided what the hell, I´ll ask again and try to understand.
First of all, I don´t really understand those public Shopdata() and public Item() parts. You mean I´m supposed to put something in those functions right? I guess this just goes to show how new to this I am.
Well anyway what I´ve tried now is this: I have a Controller-gameobject with a script named Saver. The code in the script goes like this:
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class Saver : $$anonymous$$onoBehaviour {
string dataPath;
public ItemData[] items;
void Update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.S))
{
SaveShop();
}
}
public void SaveShop()
{
dataPath = Path.Combine(Application.persistentDataPath, "ItemData.txt");
foreach (ItemData itemData in items)
{
string shopData = JsonConvert.SerializeObject(itemData);
using (StreamWriter sw = File.CreateText(dataPath))
{
sw.Write(shopData);
}
}
}
In the inspector I set the size of the "items" -array to 2. Then I put the ItemData of Apple and Orange to the array in the inspector.
I was really hopeful this would work, iterating and all, but when saving I get an error message saying "JsonSerializationException: Self referencing loop detected for property 'gameObject' with type 'UnityEngine.GameObject'. Path 'gameObject'."
Can you give this one more go StewVanB? Is this at all doable like this, fiddling around with the inspector and expecting it would give birth to a nice JSON-file?
Your answer
![](https://koobas.hobune.stream/wayback/20220612200636im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Having multiple save files 1 Answer
[SOLVED] Save System with Serialize multiple objects 2 Answers
multiple classes? 1 Answer
How can I save a gameobject's mesh? 1 Answer
How to save a picture on Android device? 0 Answers