Thursday, May 9, 2019

unity - How to save/persist a GameObject with incremental levels? Dictionary? List?


I create buildings and they have child Text objects that will reflect the building level.


The Problem:


What can I use to store the buildings a player has built so the data can be persisted?


I've looked at Lists, but when I upgrade a building, how would I update the list so that particular building has its new level reflected?


I'm working on a dictionary so I can update the key with the new value (level) but running into a problem with the keys and names. If I have lets say 10 "Farms" and try to add them to the dictionary, even though they have different properties, I get an error that I have a duplicate.


Currently I am learning how to persist that data through scenes;


GameManager.CS



public class GameManager : MonoBehaviour
{

public static Dictionary playerBuilt = new Dictionary();

public void SaveState()
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/EmpireGame", FileMode.Open);


SaveClass sc = new SaveClass()
{
food = Player.food.amount,
buildingList = playerBuilt
};

bf.Serialize(file, sc);
file.Close();
}
}


[Serializable]
class SaveClass
{
public int food, wood, iron, stone;
public Dictionary buildingList = new Dictionary();
}

Building.CS


public abstract class Building : MonoBehaviour, IUpgradable {


public int ID;

//level this building is
public Text levelText;
public int level = 0;

//starting cost to amplify the upgrade cost
public int foodBase, woodBase, ironBase, stoneBase;


//Upgrade cost
public int foodCost, woodCost, ironCost, stoneCost;
public float BuildingCostPercentage = 5f;

public void UpdateDictionary()
{
if (GameManager.playerBuilt.ContainsKey(this))
GameManager.playerBuilt[this] = level;
else
GameManager.playerBuilt.Add(this, level);

}
}

Note: I have not tested the save function so I expect errors.



Answer



Myself, I'd pull out just the parts of the building I really want to save - ie. those that are unique to this instance of the building. Eg..


[System.Serializable]
public struct BuildingRecord {
public BuildingType type;
public Vector2 position;

public int level;
}

Here BuildingType could be an enumeration, or a reference/index to a Type Object, or even just a string key - whatever will help you look up the appropriate source assets like a prefab when you want to spawn this building back into the game when you load from your save file.


Your Building can have a method like so...


public BuildingRecord GetRecord() {
return new BuildingRecord(){
type = this.type,
position = (Vector2)transform.position,
level = this.level

};
}

Then your save function can simply iterate over a list of Building component instances that you've maintained all along, or fetched on demand with FindObjectsOfType() and make a simple serializable array of them:


BuildingRecord[] SaveBuildings(IList buildings) {
var records = new BuildingRecord[buildings.Count];
for(int i = 0; i < records.Length; i++)
records[i] = buildings[i].GetRecord();
return records;
}


On deserialization, you can pass each record to a factory method to look up the right prefab using the type information, spawn it at the given position, and initialize it to the given level.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...