Best practices for serializing grid map data to disk - problems saving data structure

Hi,

I’m creating a grid based game and want to save my map data files to disk (this should be flexible, I haven’t set on a particular format yet).
Here’s what I’d like to store:

[Serializable]
public class Map
{
    public string name { get; set; }
    public int xSize { get; private set; }
    public int zSize { get; private set; }

    Tile[] _tiles; // problem: reference types are not copied.
}

[Serializable]
public class Tile
{
    public TileType type;
    public int x { get; private set; }
    public int z { get; private set; }
}

public enum TileType
{
    Empty,
    Grass,
}

Those classes also contain constructors and methods for basic functionality.
Here is my initial problem, which made me think about my approach of saving data:

public class MapController : MonoBehaviour
{
    Map _map;

    void Start()
    {
        _map = new Map(xSize, zSize);
        // ... initialize etc.

        // Save
        using (Stream stream = new FileStream(Application.dataPath + "/MyLevel.map", FileMode.OpenOrCreate))
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, _map); // Doesn't work because _map is stored within MapController,
            //which is a MonoBehaviour that can't be serialized.
        }
    }
}

The error message is “MapController is not marked as serializable…”. Of course I don’t want to save my controller, I just want to save the map. I know that I have to make a deep copy of the Tiles array, because if any copy of it references the array in the controller script, it won’t work. So naturally I wrote some code to copy all fields individually and also create a new array before saving to disk. So in the end I got it to work, but it seems like a messy approach.

What is a good practice for storing data like this?

I thought about making my classes structs, but it doesn’t seem performant to copy all values all the time. So maybe I could create structs only for saving, such as MapSaveData and TileSavaData. Any other ideas how to structure my classes and data? Maybe my “map” could contain basic logic and store a grid struct as internal representation, etc…so many options, I’m kind of lost.

Thanks for any suggestions! :slight_smile:

If all you need is to save an array of tile types, just write it into a long array of integers
(then optionally compress with something)

After a few hours of experimenting and googling I found my actual problem. The code I posted would work, but my version also includes public events in the Tile class, which the BinaryFormatter tries to save by serializing not only the class itself but all other classes who have handlers implemented (therefore it tried to save the MonoBehaviour controller class). So now that I made the event NonSerialized everything works as expected.

However, my general question remains: What’s a good approach for these types of classes? Currently I’m mixing logic (events, methods) and pure data (TileType) which I have to account for before serializing by marking some fields or properties etc. Maybe it would be clearer if I’d separate those two things. I just don’t know what the more common practice is.