Saving Scene states, map state etc.

I’m making a 2D platformer rougelike, which involves multiple scenes.

The Player starts a new game by selecting one of three mainhand weapons (scriptable objects which are randomly chosen at start) and an offhand weapon, then the game begins by launching into the ‘Map’ scene, shown below:

The Map scene starts by generating Nodes and ends by creating paths between the nodes which the Player can traverse by clicking on a node. This triggers a scene load into a ‘Battle’ scene or a 'Shop scene etc. The Player then goes back to the Map scene after the Battle or Shop scene is finished.

My question is how do i save the state of the map between scenes? I also want to save the Player inventory and other things. These all need to be associated on one ‘save’ and should persist if the game is closed and opened again. I also need to save the weapons the game randomly chose at the start of the new game so that Players can’t simply close the game and reopen it to get a different selection of weapons at the start.

For each battle scene i also need information from the Map, such as map level etc. to determine the difficulty of the level.

For reference, the map works similarly to the Slay the Spire map.

Thanks.

If you centralize all the data you need to save inside one serializable class, then saving and loading becomes really easy.

You can then use for example JsonUtility to serialize the class to a json string and then write the data to disk.

You can save your files at Application.persistentDataPath, and it should work for data persistence on pretty much all the platforms. PlayerPrefs is another place where you could store your json string for later retrival.

Each node on the map is a GameObject which contains everything from its type (enum), its forward nodes and backward nodes as a list of type gameobject, sprite etc. How do i represent a list of gameobjects, enums, sprites etc when i’m restricted to basic data types?

Handling serialization of UnityEngine.Object references is one of the more difficult aspects of serialization.

One thing you could do is to split the building of the map into two parts.

First you just generate a MapState that contains the complete instructions for building the map, but you don’t yet instantiate any Nodes.

Then you can use the data on the MapState class for actually building the map. But you can now also reuse the same MapState for easily serializing the state of the map. Since the MapState itself doesn’t contain any GameObject references, serializing it is easy.

Here is a quick example to demonstrate what I mean in practice:

public class Map : MonoBehaviour
{
    public Nodes[] nodes;

    private MapState mapState;

    public void BuildNew()
    {
        Load(Generate());
    }

    public string Serialize()
    {
        return mapState.Serialize();   
    }

    public void Deserialize(string serializedData)
    {
        Load(MapState.Deserialize(serializedData));
    }
   
    private MapState Generate()
    {
        mapState = new MapState();

        // generate the map here
    }
   
    private void Load(MapState loadState)
    {
        Clear();
        mapState = loadState;
        Build(mapState);
    }

    private void Clear()
    {
        foreach(var node in nodes)
        {
                Destroy(node);
        }
    }   
   
    private void Build(MapState mapState)
    {
        nodes = new Node[mapState.nodes];
        for(int n = 0; n < mapState.nodes.Length; n++)
        {
            var nodeState = mapState.nodes[n];
            var node = Instantiate(nodeState.position);
            node.id = nodeState.id;
            nodes[n] = node;
        }
       
        // establish connections between nodes here based on NodeState.connections
    }
}

[Serializable]
public class MapState
{
    public NodeState[] nodes;
   
    public string Serialize()
    {
        JsonUtility.ToJson(this);
    }
   
    public static MapState Deserialize(string serializedData)
    {
        return JsonUtility.FromJson<MapState>(serializedData);
    }
}

[Serializable]
public class NodeState
{
    public int id; // each Node is given a unique id
    public int[] connections; // array of ids representing connections between nodes
    public Vector3 position;
    public Vector3 scale;
}
1 Like