Unity中将类数据保存为JSON的完整指南
在Unity开发中,将类的数据持久化为JSON(JavaScript Object Notation)是一种常见需求,例如存档系统、配置文件保存、玩家数据存储等,JSON格式轻量、易读,且跨语言兼容性强,Unity内置了JsonUtility工具,能方便地实现类与JSON的相互转换,本文将详细介绍Unity中将类保存为JSON的完整流程,包括类的要求、核心方法、代码示例及常见问题解决。
可序列化类的准备:满足JsonUtility的要求
在使用JsonUtility将类转换为JSON前,类必须满足Unity的序列化规则,否则转换会失败或数据丢失,核心要求如下:
类声明为[Serializable]
Unity的序列化系统只能识别被[Serializable]特性标记的类,需要保存的类必须添加此特性:
using UnityEngine;
[System.Serializable] // 必须添加此特性才能被序列化
public class PlayerData
{
// 类成员定义
}
成员变量类型限制
可序列化的成员变量类型需为以下之一:
- 基本类型(
int、float、bool、string等) - 基本类型数组(
int[]、string[]等) - Unity内置对象类型(
Vector3、Quaternion、Color等,需注意版本兼容性) - 其他
[Serializable]的自定义类 List<T>或Dictionary<K,V>(需特殊处理,见下文)
不可序列化的类型:
- 字典(
Dictionary<K,V>)默认不可序列化,需通过包装类或第三方库处理 - 私有字段(
private)或static字段(static)默认不参与序列化 GameObject、MonoBehaviour等复杂引用类型(除非使用JsonUtility的FromJsonOverwrite配合特定逻辑)
示例:定义可序列化的类
假设我们需要保存玩家的位置、生命值、名称和技能列表,定义如下类:
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public string playerName; // 玩家名称
public int health; // 生命值
public Vector3 position; // 位置(Unity内置类型,可直接序列化)
// 技能列表(List<T>需特殊处理,见下文)
public List<string> skills;
public PlayerData(string name, int hp, Vector3 pos)
{
playerName = name;
health = hp;
position = pos;
skills = new List<string> { "Fireball", "Ice Shield" };
}
}
核心方法:使用JsonUtility进行序列化
Unity提供了JsonUtility类,位于UnityEngine.Serialization命名空间下,核心方法包括:
ToJson(object obj):将对象序列化为JSON字符串FromJson<T>(string json):将JSON字符串反序列化为对象(需指定目标类型)
序列化:将类对象转为JSON字符串
使用ToJson()方法时,需传入类的实例对象,返回JSON格式的字符串,示例:
using UnityEngine;
public class JsonSaveExample : MonoBehaviour
{
void Start()
{
// 1. 创建类对象
PlayerData playerData = new PlayerData("Alice", 100, new Vector3(10f, 0f, 5f));
// 2. 序列化为JSON字符串
string json = JsonUtility.ToJson(playerData, prettyPrint: true); // prettyPrint格式化输出,便于阅读
Debug.Log("生成的JSON: " + json);
// 3. 保存到文件(见下文“文件存储”部分)
}
}
输出结果:
{
"playerName": "Alice",
"health": 100,
"position": {
"x": 10.0,
"y": 0.0,
"z": 5.0
},
"skills": [
"Fireball",
"Ice Shield"
]
}
参数说明:
prettyPrint: true:启用格式化输出(缩进、换行),便于调试;设为false时,JSON会压缩为单行(节省存储空间)。
反序列化:将JSON字符串转回类对象
若需从JSON字符串恢复对象,使用FromJson<T>(),其中T为目标类类型:
string json = "{\"playerName\":\"Alice\",\"health\":100,\"position\":{\"x\":10.0,\"y\":0.0,\"z\":5.0},\"skills\":[\"Fireball\",\"Ice Shield\"]}";
PlayerData loadedData = JsonUtility.FromJson<PlayerData>(json);
Debug.Log("加载的玩家名称: " + loadedData.playerName); // 输出: Alice
处理复杂类型:List、字典与嵌套类
实际开发中,类可能包含List、字典或嵌套类,这些类型的序列化需要额外注意。
List的序列化
List<T>默认不可直接序列化,但Unity 2018.1+支持[Serializable]的List,需确保:
- List被声明为
public(或[SerializeField]) - List的泛型类型
T是可序列化的类型
修改PlayerData类,添加List<string>并测试:
[System.Serializable]
public class PlayerData
{
public List<string> skills; // 可直接序列化
}
// 使用示例
PlayerData player = new PlayerData();
player.skills = new List<string> { "Skill1", "Skill2" };
string json = JsonUtility.ToJson(player);
Debug.Log(json); // 输出: {"skills":["Skill1","Skill2"]}
字典(Dictionary<K,V>)的序列化
Dictionary<K,V>默认不可序列化,需通过“包装类”将其转换为List或键值对数组,常见方法:
方案1:使用List<SerializableKeyValuePair>
定义可序列化的键值对结构,并用List存储:
[System.Serializable]
public class SerializableDictionary<TKey, TValue>
{
[System.Serializable]
public class KeyValuePair
{
public TKey key;
public TValue value;
}
public List<KeyValuePair> items;
// 可选:添加索引器,模拟字典的访问方式
public TValue this[TKey key]
{
get
{
return items.Find(x => EqualityComparer<TKey>.Default.Equals(x.key, key)).value;
}
set
{
var index = items.FindIndex(x => EqualityComparer<TKey>.Default.Equals(x.key, key));
if (index != -1)
items[index].value = value;
else
items.Add(new KeyValuePair { key = key, value = value });
}
}
}
使用示例:
[System.Serializable]
public class PlayerData
{
public SerializableDictionary<string, int> skillLevels; // 技能名: 技能等级
}
// 初始化并序列化
PlayerData player = new PlayerData();
player.skillLevels = new SerializableDictionary<string, int>();
player.skillLevels["Fireball"] = 5;
player.skillLevels["Ice Shield"] = 3;
string json = JsonUtility.ToJson(player);
Debug.Log(json);
// 输出: {"skillLevels":{"items":[{"key":"Fireball","value":5},{"key":"Ice Shield","value":3}]}}
方案2:使用第三方库(如Newtonsoft.Json)
若项目已引入Newtonsoft.Json(Unity 2019.4+可通过Package Manager安装),可直接序列化字典:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
// 序列化字典
Dictionary<string, int> skillLevels = new Dictionary<string, int> { { "Fireball", 5 } };
string json = JsonConvert.SerializeObject(skillLevels);
Debug.Log(json); // 输出: {"Fireball":5}
// 反序列化
Dictionary<string, int> loadedDict = JsonConvert.DeserializeObject<Dictionary<string, int>>(json);
嵌套类的序列化
嵌套类只需确保所有层级类均标记[Serializable],JsonUtility会自动处理嵌套关系:
[System.Serializable]
public class WeaponData
{
public string name;
public int damage;
}
[System.Serializable]
public class PlayerData
{
public string playerName;
public WeaponData equippedWeapon; // 嵌套类
}
// 使用示例
PlayerData player = new PlayerData
{
playerName = "Bob",
equippedWeapon = new WeaponData { name = "Sword", damage = 20 }
};
string json = JsonUtility.ToJson(player);
Debug.Log(json);
// 输出: {"playerName":"Bob","


还没有评论,来说两句吧...