Dynamic Objects Saving and Loading

Share on facebook
Facebook
Share on google
Google+
Share on twitter
Twitter
Share on linkedin
LinkedIn

Introduction

When storing data that is specific to a certain object and not the game as a hole, such as a chest’s state or a door’s state, compared to volume, controls, or level, things change and it gets a bit more complicated. In my last game CaveBrawlers chest’s states were stored like this.

Id:0,
Opened:;
Id:1,
Opened:;
....

I had to manually enter an increasing Identifier to chests and define whether they were opened or not. This was bearable for the scale of game CaveBrawlers was, there was a total of 41 chests so this was easy to manage.

New Game, New Challenges

In the Multiplier, I have more ambitious hopes for dynamic objects and am making more use of them, particularly for story events. I need a new system. I will not be manually ensuring that each dynamic object has a unique identifier and be limited to hard coding data models.

First we need each object to have a unique id that is persistent unity has instance IDs but they change every time a scene is loaded. This needs to stay the same regardless of anything else. So the logical step is to create a guid, a randomly generated 128-bit key. A duplicate guid is incredibly rare to occur.

To make the process more streamlined, I created a script that is dedicated to keeping unique identifiers,

[ExecuteInEditMode] public class UniqueObject : MonoBehaviour { private string id; void Start() { if (string.IsNullOrEmpty(id)) { GenerateID(); } } private void GenerateID() { Guid guid = Guid.NewGuid(); string id = guid.ToString() + "_" + DateTime.UtcNow.Millisecond; Debug.Log("Generating Object for: " + gameObject.name + ", " + id); this.id = id; } public string GetId() { return id; } }

Data Models

Now that an object has a unique identifier, now we can actually make a data model to hold data in it. This script will be attached to every object that might need to contain data in it. We need a class that we can serialize into JSON or however you decide to serialize it. Luckily using JSON.NET and C# We can create a dictionary array with a string key type and an object value type. Allowing us to declare a dictionary like this,

Dictionary<string, object> dic;
dic.Add(“Health”, 0);
dic.Add(“Name”, “Samuel”);
dic.Add(“HasLegendarySword”, true);

This is perfect and as long are your object type is a supported by your serialization library then you’re good!

[RequireComponent(typeof(UniqueObject))] public class DynamicObject : MonoBehaviour { public Dictionary<string, object> dataDic = new Dictionary<string, object>(); private UniqueObject uniqueObj; private void Awake() { uniqueObj = GetComponent<UniqueObject>(); DataManager.instance.sceneData.TrackDynamicObject(this); } public string GetId() { return uniqueObj.GetId(); } public DynamicObjectData GetData() { DynamicObjectData data = new DynamicObjectData(); data.id = GetId(); data.data = dataDic; return data; } public void SetData(DynamicObjectData data) { this.dataDic = data.data; } } public class DynamicObjectData { public string id; public Dictionary<string, object> data; }

Tracking Objects and Saving/Loading

Keeping track of these objects is the challenge. To do this, I have a DataManager singleton which has a list of DynamicObjects. Every DynamicObject adds itself to it. When the Save method is called, I get every object in that list and make a new list of DynamicObjectData from their GetData method. The DynamicObjectData is serialized to a json string and stored in a text file specifically for dynamic objects on the user’s device. To load, the opposite happens, the json string is read from the text file and then the DynamicObjectData is deserialized into a list. I iterate through the list and get the appropriate DynamicObject based on the id from the DynamicObjectData, then assign the data.

 I hope I helped any developers who were having trouble with dynamic object saving. Had I had this system, I’d have saved myself from a headache with my previous game of making sure each object had a unique id and being restricted to a single hard data model.

More to explore