Saving and reading GameObjects

37 Views Asked by At

I would like the user to be able to save the state (transform data) of child gameobjects of a specific parent object to a text file and then next time being able read from the file and recreate the gameobjects at runtime. When the user hits the save button then the program loops through the child gameobjects of the parent and for each writes the state to the file. I created a normal class (not a MonoBehaviour) called ItemSettings which is a variable in my gameobject's class. This ItemSettings I made serializable.

I write the info to file as follows:

public void SaveProject()
{
    string path = "D:/Unity/test.txt";

    FileStream file;

    if (File.Exists(path)) file = File.OpenWrite(path);
    else file = File.Create(path);

    BinaryFormatter bf = new BinaryFormatter();

    foreach (Transform g in cupboard.transform)
    {
        CubeObject cubeObject = g.GetComponent<CubeObject>();

        if (cubeObject)
        {
            bf.Serialize(file, cubeObject.GetSettings());
        }
    }

    file.Close();
}

I try to read the file as follows:

public void LoadFile()
{
    string destination = "D:/Unity/test.txt";
    FileStream file;

    if (File.Exists(destination)) file = File.OpenRead(destination);
    else
    {
        Debug.LogError("File not found");
        return;
    }

    BinaryFormatter bf = new BinaryFormatter();
    ItemSettings data = (ItemSettings)bf.Deserialize(file);

    // Wants to do the following:
    // for each ItemSetting in file instantiate an ItemSettings object

    file.Close();
}

However I am not sure how to read from a file with multiple ItemSettings data. How do I loop through it and read the ItemSettings data one at a time? Or is there a better way of doing this?

1

There are 1 best solutions below

0
derHugo On

First of all STOP using BinaryFormatter!


And then after e.g. switching to JSON (com.unity.nuget.newtonsoft-json) you do not want to serialize multiple individual objects into one file stream.

  • How should the serializer know where to stop when you deserializer to a single instance?
  • And further how do you want to get multiple instances at all this way?

You rather want to add them all to a list/array and serialize that one.

=> you can deserialize into a list/array, iterate over it and instantiate and initialize according GameObjects with component


Something like (e.g. using mentioned Newtonsoft Json.Net)

// See https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html
// usually you as a user do not want any application simply accessing any file location ;)
private readonly string path = Path.Combine(Application.persistentDataPath, "test.json");

public void SaveProject()
{
    var settings = new List<ItemSettings>(cupboard.transform.childCount);

    foreach (Transform g in cupboard.transform)
    {
        if(g.TryGetComponent<CubeObject>(out var cubeObject))
        {
            settings.Add(cubeObject.GetSettings());
        }
    }

    var json = JsonConvert.SerializeObject(settings);

    File.WriteAllText(path, json);
}

public void LoadFile()
{
    if(!File.Exists(path))
    {
        Debug.LogWarning($"No settings file found at \"{path}\"");
        return;
    }

    var json = File.ReadAllText(path);

    var settings = JsonConvert.DeserializeObject<List<ItemSettings>>(json);

    foreach(var setting in settings)
    {
        // Todo Instantiate (probably from prefab) and apply setting
    }
}

For other alternatives (including binary ones) see Preferred Alternatives