The question is answered, right answer was accepted
How to save multiple scenes' data
I want to create small project (it's basically project to test and learn how serialization and saving work). Project will have scenes for three battle arenas (they won't be identical), shop, main hub, etc. and things like character progression through upgrade system and customization.
And I want to save that data as one file.
Battle arenas will save which enemies were killed and additional stuff like collected collectibles. Shop will store actuall items available to buy.
Can you explain this like to person who don't program on daily basic and ain't familiar with advanced C# concepts.
Answer by mitchmeyer1 · Jan 23, 2018 at 03:07 PM
Assuming this is single player and you just want to save on the device you can use PlayerPrefs.
This will save data locally to the device, you can set data, then read it back later. Here is an example of a few things you could do.
Of course you have to put them in the right places. I might start with a script in your first scene that sets all the keys to the default values:
FIRST SCENE INITIALIZATION MONOBEHAVIOR
void Awake()
{
if (!PlayerPrefs.HasKey("DefaultsSet")){
PlayerPrefs.SetString("DefaultsSet","True");
//Player Specific Values
PlayerPrefs.SetString("Player:Name","Jerry");
PlayerPrefs.SetInt("Player:Coins",0);
PlayerPrefs.SetInt("Player:ProgressLevel",0);
PlayerPrefs.SetInt("Player:EquippedGunId",0);
PlayerPrefs.SetInt("Player:EquippedHelmetId",0);
//Shop Values (
PlayerPrefs.SetString("Shop:Purchased:Gun0","True");
PlayerPrefs.SetString("Shop:Purchased:Gun1","False");
PlayerPrefs.SetString("Shop:Purchased:Gun2","False");
PlayerPrefs.SetString("Shop:Purchased:Helmet0","True");
PlayerPrefs.SetString("Shop:Purchased:Helmet1","False");
PlayerPrefs.SetString("Shop:Purchased:Helmet2","False");
}
}
Then in your shop, you can show Gun2 the store like this:
SHOP INITIALIZATION MONOBEHAVIOR
int gunCosts = [0,30,100];
int helmetCosts = [0,30,100];
void Start()
{
if (PlayerPrefs.GetString("Shop:Purchased:Gun1") == "True"){
//This gun is unlocked and equip-able, so you can change its sprite to the 'unlocked sprite'
//You also can add a click-listener to go to the function EquipGun(1)
//Which would do PlayerPrefs.SetInt("Player:EquippedGunId",1);
} else if (PlayerPrefs.GetInt("Player:Coins") > gunCosts[1]) {
//This gun is not unlocked, but can be because you have over gun[1] coins
//Here you could add change the sprite to make the button look 'unlock-able' or 'purchasable'
//You also can add a click-listener to go to the function PurchaseGun(1)
} else {
//This gun is not unlocked and you do not even have enough money to do so
// Here you can change the sprite of the button to be like a 'locked' button, and have
// A Click listener that just tells the user they don't have the cash to buy it
}
}
void PurchaseItem(int gunId) {
//Remove coins from player
PlayerPrefs.SetInt("Player:Coins", PlayerPrefs.GetInt("Player:Coins") - gunCosts[gunId] );
//Unlock gun
PlayerPrefs.SetString("Shop:Purchased:Gun"+gunId.ToString(),"True");
//Equip gun
PlayerPrefs.SetInt("Player:EquippedGunId",gunId);
}
That was my sloppy 10 min attempt. Hope there are no typos and that points you in the right direction!
I don't want to use Playerprefs. I somewhat understand how serialization through Json or Binary Serialization work. I made one project with serialization that saves number and string to Json file.
I mostly don't know how to put every info in one class.
Create a monobehavior called like "GlobalData" or something
Then put that behavior on an object and call DontDestroyOnLoad on that object in the first scene
Now that object will travel to every scene.
If you want a shop or level object to talk to that "global data object" you can do:
GameObject.Find ("GlobalDataObject").GetComponent<GlobalData> ();
to get that same instance from any scene
Answer by Wokarol · Jan 23, 2018 at 04:56 PM
I don't know how to store data inside one class. One of my ideas is to create "SceneData" classes that holds important data and make "SaveData" class that hold SceneData like
[System.Serializable]
public class SaveData {
public ArenaSceneData[] arenaSceneDatas;
public ShopSceneData ShopSceneData;
public ProgressionData progressionData;
public CustomizationData customizationData;
}
[System.Serializable]
public class ArenaSceneData {
public GameObject killedEnemies;
public Collectibles collectedCollectibles;
}
[System.Serializable]
public class ShopSceneData {
public Item[] aviableItems;
}
[System.Serializable]
public class ProgressionData {
public int level;
public int exp;
public SkillTree acctualSkillTree;
}
[System.Serializable]
public class CustomizationData {
public string playerName;
public Color playerColor;
}
But this aproach isn't quite good because every Arena will need to have index, and if project will get bigger this would be a mess
And then that SaveData would be deserialized from save file, and scenes would be able to get data by writing something like SaveLoad$$anonymous$$anager.saveData.shopSceneData
It would be better if script will write SaveLoad$$anonymous$$anager.Load("Shop data") as ShopSceneData
and SaveLoad$$anonymous$$anager.Save("Shop data", localShopData)
You could add a 'name' field inside of ArenaSceneData, or use a hash ins$$anonymous$$d of an array and map a name to an ArenaSceneData Object
It's only a script made for tests but I will keep this in $$anonymous$$d.
It will be best if I would be able to save multiple classes that derive from one base class into single array.
But when I test this idea with json serializer it saves only data contained within base class using System.Collections; using System.Collections.Generic; using UnityEngine;
public class SaveLoad$$anonymous$$anager :$$anonymous$$onoBehaviour {
public SavePack savePack;
public string json;
[SerializeField]
public bool saving;
public bool loading;
void Start () {
savePack = new SavePack();
savePack.data = new List<SaveData>();
// Saving
if (saving) {
ShopData newShopData = new ShopData {
dataName = "Shop data",
items = "Sword, Shield, Helmet",
cost$$anonymous$$ultiplier = 2
};
savePack.data.Add(newShopData);
CustomizationData newCustomizationData = new CustomizationData {
dataName = "Cust data",
color = Color.black
};
savePack.data.Add(newCustomizationData);
}
}
[Context$$anonymous$$enu("Save")]
void Save () {
json = JsonUtility.ToJson(savePack);
Debug.Log("Changed To Json as " + json);
}
}
[System.Serializable]
public class SavePack {
public List<SaveData> data;
}
[System.Serializable]
public class SaveData {
public string dataName;
}
[System.Serializable]
public class ShopData :SaveData {
public string items;
public int cost$$anonymous$$ultiplier;
}
[System.Serializable]
public class CustomizationData :SaveData {
public Color color;
}
in this script json string have only dataNames
Follow this Question
Related Questions
Unity How to Save Serialized Levels 1 Answer
Store Reference to a Serializable Class 0 Answers
How to save a two-dimensional array, as part of the variable inspector? 0 Answers
Do you need to have specific script types for different mobile platforms? 1 Answer
Why do nested if statements act differently than the && operator? 1 Answer