- Home /
JSON save/load system
Hey guys,
So I'm building a system that serializes certain data items in my saveable game objects and stores them in a .json file. But I'm having a problem completing it, and I'm not sure what the solution is.
So far, this has three scripts: SaveLoadManager.cs, that is attached to a SaveLoadManager game object, SavedGameObject.cs, which is attached to any game object I want to save data for, and ShipController.cs, which is an example game logic script for the game objects being saved.
In SaveLoadManager, there is a List called SavedGameObjects, in which all of the objects with SavedGameObject.cs adds itself to during Start. Also in this script are the Save and Load functions.
In SavedGameObject.cs, there is the serializable data in it's own class, as well as the two functions that prepare the data to be saved(UpdateSaveData) and reintegrate the loaded data back into the game(UpdateLoadData).
The problem I'm having is getting additional game objects to add data to the jsonString, as opposed to overwriting it, and also figuring out how to properly parse the data when loading it back in. For this aspect, there are no tutorials I can find. So if someone could tell me what I need to do to get this working, I would really appreciate it.
Here are my scripts:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
// As you can probably see, this script is attached to a SaveLoadManager game object, and the other two scripts are attached to the game objects to be saved.
// ShipController just handles the game logic for that object. It is not involved in the save/load process.
// SavedGameObject contains the save data class andhas functions to update the game variables for saving or loading.
// when Save or Load is called from this script, it grabs that information from SavedGameObject and uses it to compose the jsonString
// but it will only do that for one object at the moment, it will not add it all together
// despite my best efforts, I can't figure out how to make that part work
public class SaveLoadManager : MonoBehaviour
{
private static SaveLoadManager instance;
private string FilePath;
public ObjectData objectData;
public List<SavedGameObject> SavedGameObjects { get; private set; }
public static SaveLoadManager Instance
{
get
{
if (instance == null) // if this doesn't exist...
{
instance = GameObject.FindObjectOfType<SaveLoadManager>(); // set the instance
}
return instance;
}
}
void Awake()
{
SavedGameObjects = new List<SavedGameObject>(); // create the list for saveable objects to add themselves to when they are instantiated
}
void Start ()
{
FilePath = Path.Combine(Application.persistentDataPath, "save.txt");
}
void Update ()
{
// If F5 is pressed, run the Save function
if (Input.GetKeyDown(KeyCode.F5))
{
Save();
}
// If F9 is pressed, run the Load function
if (Input.GetKeyDown(KeyCode.F9))
{
Load();
}
}
public void Save()
{
for (int i = 0; i < SavedGameObjects.Count; i++)
{
SavedGameObjects[i].UpdateSaveData();
// TO DO: need a way to "amend" the jsonString so that the data for ALL the game objects is saved
}
if (File.Exists(FilePath))
{
File.Delete(FilePath);
}
string jsonString = JsonUtility.ToJson(objectData);
File.WriteAllText(FilePath, jsonString);
}
public void Load()
{
string jsonString = File.ReadAllText(FilePath);
JsonUtility.FromJsonOverwrite(jsonString, objectData);
for (int i = 0; i < SavedGameObjects.Count; i++)
{
SavedGameObjects[i].UpdateLoadData();
// TO DO: I think that if the jsonString is set up correctly, this may work as is, but I'm not sure. There needs to be some type of "parsing" code here.
// It doesn't work right now, understandably.
}
}
}
and
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SavedGameObject : MonoBehaviour
{
private ShipController shipController;
public ObjectData objectData;
public GameObject Ship;
void Start ()
{
SaveLoadManager.Instance.SavedGameObjects.Add(this);
Ship = this.gameObject;
shipController = Ship.GetComponent<ShipController>();
}
public void UpdateSaveData()
{
objectData.save_shipID = shipController.shipID;
objectData.save_shipName = shipController.shipName;
shipController.shipLocation = Ship.transform.position;
objectData.save_shipLocation = shipController.shipLocation;
objectData.save_shipHealth = shipController.shipHealth;
objectData.save_shipAmmo = shipController.shipAmmo;
}
public void UpdateLoadData()
{
shipController.shipID = objectData.save_shipID;
shipController.shipName = objectData.save_shipName;
shipController.shipLocation = objectData.save_shipLocation;
Ship.transform.position = shipController.shipLocation;
shipController.shipHealth = objectData.save_shipHealth;
shipController.shipAmmo = objectData.save_shipAmmo;
}
}
[System.Serializable]
public class ObjectData
{
public int save_shipID;
public string save_shipName;
public Vector3 save_shipLocation;
public float save_shipHealth;
public int save_shipAmmo;
}
and
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShipController : MonoBehaviour
{
public int shipID;
public string shipName;
public Vector3 shipLocation;
public float shipHealth = 100;
public int shipAmmo = 40;
}
I have no solution, but you might want to check out the venerable Unity Serializer asset, it had the option for JSON serialization.
Really? I was just looking at that, but I thought it only used the binary formatter. I will definitely take another look. I was thinking of using it anyway, but it seemed like overkill just to save a dozen or so variables per game object. But I'll try it out and see how it goes.
Yes, it's something of a monster and no longer supported, that's why some time ago I wrote my own save/load system somewhat based on it: Unity Save Load Utility
It doesn't save to JSON, however. I tried to keep things simple ;)
Answer by dvandamme · Mar 28, 2017 at 07:21 PM
A data set should be easy to search, sort, add to and delete from, and a json string has none of those functions. JSON is a way to send and store data.
Build a dataset of your own and manage that, not a json string.
You can either manage that dataset when you manipulate the game objects, or do a scene wide hunt and store when you save out to a file.
You can use something like 'find by tag' or find all with a particular component (similar to your saveable object class) to get all the saveable objects, read the interesting values off them, into the dataset, and then stringify that dataset for saving to a file.
so youd have a dataset controller which contains a list of items which are the bare necessities to populate a world with. Youd provide some useful functions for manipulating that dataset, such as find, add, remove, sort, and and the controller would be able to use that dataset to populate a game world.
Answer by EqLogic · Mar 28, 2017 at 04:42 AM
I would suggest using json.Net,
http://stackoverflow.com/questions/33081102/json-add-new-object-to-existing-json-file-c-sharp