Unity_数据持久化_Json
Unity_数据持久化
四、Json数据持久化
4.1 Json基本语法
4.1.1 基本概念
什么是JSON:
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有以下特点:
- 轻量级:相比XML,JSON格式更简洁,数据量更小
- 可读性:人类和机器都能轻松理解
- 跨平台:不依赖特定编程语言,支持多种平台
- 自描述性:数据结构清晰,易于解析
JSON在Unity中的应用:
- 游戏配置数据存储
- 网络通信数据格式
- 存档文件格式
- 第三方API数据交换
4.1.2 数据类型
JSON支持六种基本数据类型:
1. 字符串(String)
"Hello World"
"Unity游戏开发"
"12345"
2. 数字(Number)
42 // 整数
3.14 // 浮点数
-273 // 负数
1.23e-4 // 科学计数法
3. 布尔值(Boolean)
true // 真
false // 假
4. 空值(Null)
null // 表示空值或未定义
5. 数组(Array)
[1, 2, 3, 4, 5] // 数字数组
["苹果", "香蕉", "橙子"] // 字符串数组
[true, false, true] // 布尔值数组
[1, "混合", true, null] // 混合类型数组
6. 对象(Object)
{"name": "张三","age": 25,"isStudent": true
}
4.1.3 语法规则
基本语法规则:
1. 键值对格式
{"键名": "值"
}
2. 命名规则
- 键名必须用双引号包围
- 键名区分大小写
- 键名不能重复
- 支持中文和特殊字符
3. 值类型规则
- 字符串必须用双引号包围
- 数字不需要引号
- 布尔值和null不需要引号
- 数组和对象不需要引号
4. 嵌套规则
{"player": {"name": "张三","stats": {"health": 100,"mana": 50},"inventory": [{"id": 1, "name": "剑"},{"id": 2, "name": "盾"}]}
}
5. 分隔符规则
- 键值对之间用逗号分隔
- 数组元素之间用逗号分隔
- 最后一个元素后不能有逗号
4.1.4 格式示例
游戏数据JSON示例:
1. 玩家信息
{"playerId": 1001,"playerName": "游戏玩家","level": 15,"experience": 2500,"isOnline": true,"lastLogin": "2024-01-15T10:30:00Z","position": {"x": 100.5,"y": 200.0,"z": 50.0},"skills": ["剑术", "魔法", "治疗"],"equipment": {"weapon": "传说之剑","armor": "龙鳞甲","accessory": "生命戒指"}
}
2. 游戏配置
{"gameSettings": {"graphics": {"resolution": "1920x1080","quality": "high","fullscreen": false},"audio": {"masterVolume": 0.8,"musicVolume": 0.6,"sfxVolume": 0.9},"controls": {"mouseSensitivity": 1.0,"invertY": false,"keyBindings": {"moveForward": "W","moveBackward": "S","moveLeft": "A","moveRight": "D"}}}
}
4.3 C#读取存储Json文件
4.3.1 JsonUtility
4.3.1.1 基本概念
什么是JsonUtility:
JsonUtility是Unity内置的JSON序列化工具,提供了线程安全的方法,可以将C#类对象序列化为JSON字符串,也可以将JSON字符串反序列化为C#对象。
核心特点:
- 内置工具:Unity引擎自带,无需额外导入
- 线程安全:提供线程安全的序列化方法
- 简单易用:API简洁,学习成本低
- 性能优化:针对Unity引擎优化
4.3.1.2 主要方法
核心序列化方法:
// 序列化:将对象转换为JSON字符串
string jsonString = JsonUtility.ToJson(object obj);
string jsonString = JsonUtility.ToJson(object obj, bool prettyPrint);// 反序列化:将JSON字符串转换为对象
T result = JsonUtility.FromJson<T>(string json);
参数说明:
- obj:要序列化的对象
- prettyPrint:是否格式化输出(美化JSON格式)
- T:目标类型
- json:JSON字符串
4.3.1.3 使用示例
基于您的脚本的完整示例:
using UnityEngine;
using System.IO;
using System.Collections.Generic;[System.Serializable]
public class Skill
{public int id;public string name;public int damage;// 必须有无参构造函数public Skill() { }public Skill(int id, string name, int damage){this.id = id;this.name = name;this.damage = damage;}
}[System.Serializable]
public class Player
{public int id;public string name;public List<int> nums;public Skill skill;public List<Skill> skills;// 注意:Dictionary类型JsonUtility不支持// public Dictionary<string,int> dict;// public Dictionary<string,Skill> dict2;
}public class JsonUtilityExample : MonoBehaviour
{void Start(){// 创建测试数据Player player = new Player();player.id = 1;player.name = "张三";player.nums = new List<int>(){1, 2, 3};player.skill = new Skill(1, "技能1", 100);player.skills = new List<Skill>(){new Skill(2, "技能2", 200), new Skill(3, "技能3", 300)};// 序列化对象为JSON字符串string jsonString = JsonUtility.ToJson(player, true); // 美化输出print("序列化结果: " + jsonString);// 保存到文件string filePath = Application.persistentDataPath + "/player.json";File.WriteAllText(filePath, jsonString);print("文件保存路径: " + filePath);// 从文件读取JSON字符串string loadedJson = File.ReadAllText(filePath);// 反序列化JSON字符串为对象Player player2 = JsonUtility.FromJson<Player>(loadedJson);// 验证反序列化结果if (player2 != null){print("反序列化成功!");print("玩家ID: " + player2.id);print("玩家姓名: " + player2.name);print("数字列表第一个: " + player2.nums[0]);print("技能名称: " + player2.skill.name);print("技能列表第一个: " + player2.skills[0].name);}}
}
4.3.1.4 优缺点分析
优点:
- 内置工具:无需额外导入第三方库
- 性能优秀:针对Unity引擎优化
- 简单易用:API简洁明了
- 线程安全:提供线程安全的序列化方法
缺点:
- 功能限制:不支持Dictionary等复杂类型
- 特性要求:需要添加[System.Serializable]特性
- 私有字段:默认不支持私有字段序列化
- 精度问题:float类型可能有精度误差
4.3.1.5 注意事项
重要限制和注意事项:
1. 序列化特性要求
// 自定义类必须添加[System.Serializable]特性
[System.Serializable]
public class CustomClass
{public string name;public int value;
}
2. 私有字段序列化
[System.Serializable]
public class CustomClass
{public string publicField; // 可以直接序列化[SerializeField] // 需要添加此特性private string privateField; // 私有字段才能序列化
}
3. 不支持的数据类型
// JsonUtility不支持以下类型:
// - Dictionary<TKey, TValue>
// - 接口类型
// - 委托类型
// - 静态字段
// - 只读字段
4. 构造函数要求
public class Skill
{public int id;public string name;// 必须有无参构造函数public Skill() { }public Skill(int id, string name){this.id = id;this.name = name;}
}
5. 精度问题
// float类型在序列化时可能有精度误差
public float preciseValue = 3.14159f;
// 序列化后可能变成3.14159或3.1416
4.3.2 LitJson
4.3.2.1 基本概念
什么是LitJson:
LitJson是一个第三方库,用于处理Json的序列化和反序列化。它是C#编写的,体积小、速度快、易于使用,可以很容易地嵌入到我们的代码中。
核心特点:
- 第三方库:不属于Unity官方内置工具
- C#编写:完全由C#语言实现
- 体积小:代码库占用空间小
- 速度快:序列化和反序列化性能优秀
- 易于使用:API设计简洁直观
- 易于嵌入:只需要将LitJson代码拷贝到工程中即可
4.3.2.2 获取LitJson
获取方式:
- 前往LitJson官网
- 通过官网前往GitHub获取最新版本代码
- 将代码拷贝到Unity工程中即可开始使用LitJson
4.3.2.3 使用LitJson进行序列化
方法:
JsonMapper.ToJson(对象)
注意:
- 相对JsonUtility不需要加特性
- 不能序列化私有变量
- 支持字典类型
- 需要引用LitJson命名空间
4.3.2.4 使用LitJson反序列化
方法:
JsonMapper.ToObject<类型>(json字符串)
两种反序列化方式:
1. 动态反序列化(使用JsonData)
// JsonData是LitJson提供的类对象,可以用键值对的形式去访问其中的内容
JsonData data = JsonMapper.ToObject(jsonStr);
print(data["name"]);
print(data["age"]);
2. 强类型反序列化(使用泛型)
// 通过泛型转换更加的方便,建议使用这种方式
MrTang2 t2 = JsonMapper.ToObject<MrTang2>(jsonStr);
注意:
- 类结构需要无参构造函数,否则反序列化时报错
- 字典虽然支持,但是键在使用为数值时会有问题,需要使用字符串类型
- 需要引用LitJson命名空间
4.3.2.5 优缺点分析
优点:
- 支持Dictionary:原生支持Dictionary等复杂类型
- 体积小:代码库占用空间小
- 速度快:序列化和反序列化性能优秀
- 易于使用:API简洁,学习成本低
- 易于嵌入:只需拷贝文件即可使用
缺点:
- 第三方库:不属于Unity官方工具
- 功能相对简单:相比大型JSON库功能有限
- 更新维护:依赖第三方维护更新
- 错误处理:错误信息可能不够详细
4.3.3 JsonUtility和LitJson对比
4.3.3.1 相似点
共同特点:
- 都是用于JSON序列化和反序列化
- JSON文档编码格式必须是UTF-8
- 都是通过静态类调用方法
4.3.3.2 差异点
主要区别:
1. 来源和导入
- JsonUtility:Unity内置,无需额外导入
- LitJson:第三方库,需要导入命名空间
2. 特性要求
- JsonUtility:自定义类使用时需要加特性
- LitJson:不需要加特性
3. 私有变量支持
- JsonUtility:支持私有变量(需要加特性)
- LitJson:不支持私有变量
4. 字典类型支持
- JsonUtility:不支持字典
- LitJson:支持字典(但键必须是字符串)
5. 数据集合反序列化
- JsonUtility:不能直接反序列化数据到数据集合(如数组字典)
- LitJson:可以
6. 构造函数要求
- JsonUtility:自定义类不需要有无参构造函数
- LitJson:需要有无参构造函数
7. null值处理
- JsonUtility:存储null对象时不会是null,而是默认值的数据
- LitJson:存储null
4.3.3.3 选择方法
选择标准:
- 根据项目需求选择合适的工具
- 考虑性能、功能、维护成本等因素
- 权衡内置工具和第三方库的优缺点
4.3.3.4 选择建议
推荐使用场景:
选择JsonUtility的情况:
- 项目对性能要求较高
- 数据结构相对简单
- 希望使用Unity官方工具
- 不需要支持Dictionary类型
选择LitJson的情况:
- 需要支持Dictionary等复杂类型
- 对序列化特性没有严格要求
- 希望更灵活的JSON处理能力
- 可以接受第三方库的维护成本