Unity JSON 数据存储与读取最佳实践:JsonMgr 工具类详解

在 Unity 游戏开发中,数据持久化是一个必不可少的环节。今天我要分享一个我自己封装的 JSON 数据管理工具类 JsonMgr,它简化了 Unity 中 JSON 的序列化和反序列化过程,并支持多种 JSON 处理库。

为什么需要这个工具类?

在 Unity 开发中,我们经常需要:

  • 保存游戏设置
  • 存储玩家进度
  • 管理游戏配置数据

虽然 Unity 提供了 JsonUtility,但在实际使用中我发现它有一些局限性:

  1. 对复杂数据结构支持不够友好
  2. 需要处理文件路径和 IO 操作
  3. 不同平台路径处理差异

而第三方库如 LitJson 虽然功能强大,但 API 使用不够统一。因此我封装了这个 JsonMgr 工具类来解决这些问题。

工具类设计

核心特性

  1. 双 JSON 引擎支持:同时支持 Unity 原生 JsonUtility 和第三方 LitJson
  2. 智能路径查找:自动尝试从不同路径加载数据
  3. 简洁 API:只需一两行代码即可完成数据存取
  4. 安全设计:文件不存在时返回默认值而非抛出异常

代码实现

public enum JsonType
{
    JsonUnity,  // Unity 原生 JsonUtility
    LitJson     // 第三方 LitJson
}

public class JsonMgr
{
    // 单例模式确保全局唯一访问点
    private static JsonMgr instance;
    public static JsonMgr Instance => instance;

    // 保存数据方法
    public void SaveData(object obj, string fileName, JsonType jsonType = JsonType.LitJson)
    {
        string path = Path.Combine(Application.persistentDataPath, $"{fileName}.json");
        
        string json = jsonType == JsonType.JsonUnity 
            ? JsonUtility.ToJson(obj) 
            : LitJson.JsonMapper.ToJson(obj);
            
        File.WriteAllText(path, json);
    }

    // 加载数据方法
    public T LoadData<T>(string fileName, JsonType jsonType = JsonType.LitJson) where T : new()
    {
        // 优先尝试从 StreamingAssets 加载
        string path = Path.Combine(Application.streamingAssetsPath, $"{fileName}.json");
        
        if(!File.Exists(path))
            path = Path.Combine(Application.persistentDataPath, $"{fileName}.json");
            
        if (!File.Exists(path))
            return new T();
            
        string jsonStr = File.ReadAllText(path);
        
        return jsonType == JsonType.JsonUnity
            ? JsonUtility.FromJson<T>(jsonStr)
            : LitJson.JsonMapper.ToObject<T>(jsonStr);
    }
}

使用示例

1. 定义数据类

[Serializable]
public class PlayerData
{
    public string playerName;
    public int level;
    public float experience;
    public List<string> inventory;
}

2. 保存数据

// 创建玩家数据
var player = new PlayerData
{
    playerName = "游戏开发者",
    level = 99,
    experience = 9999.9f,
    inventory = new List<string> { "剑", "盾", "药水" }
};

// 使用 LitJson 保存(默认)
JsonMgr.Instance.SaveData(player, "player_data");

// 使用 Unity JsonUtility 保存
JsonMgr.Instance.SaveData(player, "player_data_backup", JsonType.JsonUnity);

3. 加载数据

// 使用 LitJson 加载(默认)
PlayerData loadedData = JsonMgr.Instance.LoadData<PlayerData>("player_data");

// 使用 Unity JsonUtility 加载
PlayerData backupData = JsonMgr.Instance.LoadData<PlayerData>("player_data_backup", JsonType.JsonUnity);

技术细节解析

1. 路径处理策略

工具类采用了双路径查找策略

  1. 首先检查 StreamingAssets 路径 - 适合存放初始/只读数据
  2. 如果不存在,再检查 PersistentDataPath - 适合存放运行时修改的数据

这种设计既保证了初始数据的存在,又允许玩家数据被修改保存。

2. JSON 引擎选择

提供两种 JSON 处理引擎可选:

  • JsonUtility:Unity 原生,性能较好,但对复杂类型支持有限
  • LitJson:功能更强大,支持字典等复杂结构

3. 错误处理

当文件不存在时,LoadData 方法会返回类型 T 的新实例,而不是抛出异常。这种"宽容"设计使得调用方可以更简洁地处理默认情况。

最佳实践建议

  1. 数据类设计

    • 标记为 [Serializable]
    • 提供无参构造函数
    • 避免使用多态和复杂继承结构
  2. 文件管理

    • 初始配置放在 StreamingAssets
    • 玩家数据保存在 PersistentDataPath
    • 定期备份重要数据
  3. 性能考虑

    • 频繁存取的数据可以考虑内存缓存
    • 大数据量考虑分文件存储
  4. 版本兼容

    • 考虑添加数据版本字段
    • 为数据结构变更准备迁移方案

扩展思考

这个工具类还可以进一步扩展:

  1. 添加异步保存/加载支持
  2. 增加加密功能保护玩家数据
  3. 添加压缩功能减少存储空间
  4. 实现数据变更自动保存

总结

JsonMgr 工具类通过简洁的 API 封装了 Unity 中 JSON 数据存取的复杂性,提供了灵活可靠的解决方案。无论是简单的玩家偏好设置,还是复杂的游戏状态保存,都能轻松应对。

在实际项目中,这个工具类已经帮我节省了大量重复工作,希望它也能为你的 Unity 开发带来便利!如果你有任何改进建议,欢迎在评论区交流讨论。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐