Menu
CoddyTech

加载与默认值

本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 32 课,共 64 课。

加载时必须处理存档不存在或不完整的情况。赛车游戏会保存一个 RaceSave;游戏的第 2 个版本添加了 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();
}

新玩家没有存档文件,而对不存在的文件调用 File.ReadAllText 会抛出 FileNotFoundException,因此要先检查 File.Exists,再从 new RaceSave() 开始:0 个奖杯、Rookie Kart 和 0.8 的音量,这些都是字段初始化器设置的值。老玩家的第 1 版存档文件中有 {"trophies":3,"car":"Red Racer"}。FromJson 会创建一个新的 RaceSave,运行字段初始化器,然后只设置 JSON 中包含的键,因此 musicVolume 的值是 0.8。类中没有对应字段的键会被忽略。因此,只要每个新增字段都有合理的初始化值,新版本的游戏就能读取旧存档。

JsonUtility.FromJsonOverwrite(json, obj) 会填充一个已有对象,而不是创建新对象,并让 JSON 中没有的字段保持原样。FromJson 无法创建 MonoBehaviour 或 ScriptableObject(Unity 会抛出 Cannot deserialize JSON to new instances of type 'RaceSettings.'),因此要通过覆盖的方式加载设置资源:JsonUtility.FromJsonOverwrite(json, settings);。覆盖操作也会保留对象已有的值,例如 Inspector 设置的值;而 FromJson 会恢复类的初始化器设置的值。

challenge icon

挑战

中等

为新玩家和旧存档安全地加载 pet.json。

  1. 在 Start() 中,用 if (File.Exists(path)) 和 else 替换 FromJson 行。
  2. 如果文件存在,就填充 Inspector 中的 pet:JsonUtility.FromJsonOverwrite(File.ReadAllText(path), pet);,然后通过 pet.petName 输出 Welcome back, Mochi。
  3. 如果文件不存在,就用同样的方式输出 A new pet: Biscuit。

点击“开始”,喂宠物,然后点击 Stop,再点击“开始”:你会看到欢迎回来的提示。然后点击“检查”。

亲手试试

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;
    }
}

Unity 游戏架构中的所有课

自己练习: Unity 在线编辑器