Menu
CoddyTech

Load and Defaults

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 32 of 64.

Loading has to cope with saves that are not there or not complete. A racing game saves a RaceSave; version 2 of the game added musicVolume:

[System.Serializable]
public class RaceSave
{
    public int trophies;
    public string car = "Rookie Kart";
    public float musicVolume = 0.8f;
}
RaceSave save;
if (File.Exists(path))
{
    save = JsonUtility.FromJson<RaceSave>(File.ReadAllText(path));
}
else
{
    save = new RaceSave();
}

A new player has no file, and File.ReadAllText on a missing file throws FileNotFoundException, so check File.Exists first and start from new RaceSave(): 0 trophies, the Rookie Kart and volume 0.8, the field initializers. An old player's version 1 file holds {"trophies":3,"car":"Red Racer"}. FromJson makes a new RaceSave, which runs the field initializers, and then sets only the keys the JSON has, so musicVolume is 0.8. A key the class has no field for is ignored. A new version of the game can therefore read old saves, as long as every new field has an initializer with a sensible value.

JsonUtility.FromJsonOverwrite(json, obj) fills an object that already exists instead of making one, and leaves every field the JSON lacks as it was. FromJson cannot make a MonoBehaviour or a ScriptableObject (Unity throws Cannot deserialize JSON to new instances of type 'RaceSettings.'), so a settings asset is loaded by overwriting it: JsonUtility.FromJsonOverwrite(json, settings);. Overwriting also keeps the values an object already holds, such as the ones the Inspector gave it, where FromJson would bring back the class's initializers.

challenge icon

Challenge

Medium

Load pet.json safely for new players and old saves.

  1. In Start(), replace the FromJson line with if (File.Exists(path)) and an else.
  2. With a file, fill the Inspector's pet: JsonUtility.FromJsonOverwrite(File.ReadAllText(path), pet);, then log Welcome back, Mochi from pet.petName.
  3. Without one, log A new pet: Biscuit the same way.

Press Play, feed the pet, then Stop and Play: it says welcome back. Then Check.

Try it yourself

using System.IO;
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;

public class PetCare : MonoBehaviour
{
    public PetSave pet;
    public TMP_Text petText;
    private string path;

    void Start()
    {
        path = Path.Combine(Application.persistentDataPath, "pet.json");
        pet = JsonUtility.FromJson<PetSave>(File.ReadAllText(path));
        Show();
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            pet.hunger = Mathf.Max(pet.hunger - 10, 0);
            pet.happiness = Mathf.Min(pet.happiness + 5, 100);
            File.WriteAllText(path, JsonUtility.ToJson(pet));
            Show();
        }
    }

    void Show()
    {
        petText.text = pet.petName + ": hunger " + pet.hunger + ", happiness " + pet.happiness;
    }
}

All lessons in Game Architecture in Unity

Practice on your own: Unity playground