top of page

PROGRAMMING TECHNIQUES

JSON Saving system & Inventory system

JSON Saving system

I have started by creating the file that keeps track of the game’s data (class GameData). There, I have created a public constructor. This constructor will always contain the initial values which the game starts with.

The DataManager script is a singleton class (there should not be more than of its instances in the scene, verified in the Awake() method). It uses a static instance, which allows it to be read publicly, but only be modified within this class.


This class is responsible with managing what happens with the game’s data and saving/loading it. Therefore, it uses three different methods:

    - NewGame() = initializes the gameData to be a new GameData() object;

    - LoadGame() = loads the saved data using a different script, that handles the files (FileDataHandler). If there is no data to load (if the gameData is null), it will initialize a new game. Lastly, if there is data found, it will transmit it to all the other scripts that need it.

    - SaveGame() = passes the data to other scripts that need that data. Lastly, it will save the data in a file using a different script (FileDataHandler).  


Since all of these methods are public, they can be called from any other script, making it a very flexible saving method.


The IDataManager (named according to the conventions) is an interface. To allow the scripts to save and load data, the IDataManager interface has to be implemented in all the scripts that contain the data that I want to save. When the game starts up, this script will look through all the scripts and provide the necessary data, as well as save it before exiting the game.


FileDataHandler is the stream that takes care of serializing and deserializing the data from the JSON file using a set/automatic path and is managed by the DataManager. If the saving system will ever be changed, the only modification that must take place is modify this script. This will not affect the rest of the system.

Inventory system: Dictionaries & Lists

Dictionaries


I used a dictionary that uses a String and a Boolean as the key-value pair. The string is an unique ID for each item in particular, and the value of the bool tracks whether or not the item has been collected. This is a great system for collectables, checkpoints, etc.


In my GameData script, I declared the dictionary, called itemsCollected. In the constructor, it is initialized as an empty dictionary. Because each prefab has its own script in the template, I wanted to keep things the same for my system as well.


I used a new script which extends from PickUp and IDataManager. In that script, I added a private string called ID. The ID (GUID) is a string composed of 32 characters and are very likely to be unique. To create an ID, I added a ContextMenu called Generate ID and a GenerateID method. That method simply just generates the ID. Now, in Unity, by right click on the script in the Inspector, I can generate an ID.


Next, I added the LoadData() and SaveData() methods:

     - LoadData() = calls TryGetValue on the dictionary, using the ID, to check whether or not the item has been collected. If collected, the item is destroyed.

     - SaveData() = check if the ID is already contained in the dictionary. If it is, it will first get removed before trying to get added again. When added, the ID is written as well as the corresponding Boolean value.


JSONUtility does not support Dictionaries, or other such complex data types, therefore I have to serialize the data. To do this, there are multiple ways available, such as importing a third party library.


The way I did it was by creating a script called SerializibleDictionary. In that script, I added a generic key and value and extended from the standard dictionary class, and also implemented an interface called ISerializationCallbackReceiver.


Now, I created the OnBeforeSerialize() and OnAfterDeserialize() methods:

     - OnBeforeSerialize() = make sure that both lists are cleared. Loop through each key-value pair in this dictionary, and add those to the lists.  

     - OnAfterSerialize() = make sure that the dictionary is cleared. Loop through each key-value pair in this dictionary and add those to the dictionary. Here, I am also checking whether the number of keys is equal to the one of values. If not, this indicates an error.

Lists


I created an Inventory script which was added to the player’s components, and one for the objects that will be picked up. The script adds all the collected items in a list, which displays them in the inventory UI immediately after picking them up. The list is then overring the one in GameData() to make sure it is stored in the JSON file.


The collected items are all ScriptableObjects. Sadly, at the moment, they all save as InstanceID instead of their actual name. This happens because when Unity tries to serialize referenced data, like assets (i.e. scriptable objects), by default it uses the objects InstanceID.


To fix this, I should either create a Lookup table of the ScriptableObjects or use Unity’s AssetDatabase which handles that. For a small project, InstanceIDs work, but they are not a reliable source.

bottom of page