如何制作可在运行时保存Unity特定对象及组件值的存档系统
Unity 复杂对象与集合的存档解决方案
问题根源
多数通用存档工具只支持基础类型,本质是因为Unity的内置值类型(Vector、Quaternion等)、集合(字典)以及场景对象(GameObject/组件)无法被常规序列化工具直接处理:
JsonUtility对非Unity原生支持的类型(比如字典)兼容性极差,且需要类和字段都标记[Serializable];Newtonsoft.Json不识别Unity对象的内部结构,直接序列化GameObject/组件会生成一堆无效数据,甚至抛出异常。
分步解决方法
1. 处理Unity值类型(Vector3、Color等)
给Newtonsoft.Json写自定义转换器,把复杂值类型拆成基础字段序列化:
public class Vector3Converter : JsonConverter<Vector3> { public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer) { writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.x); writer.WritePropertyName("y"); writer.WriteValue(value.y); writer.WritePropertyName("z"); writer.WriteValue(value.z); writer.WriteEndObject(); } public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); return new Vector3( (float)jo["x"], (float)jo["y"], (float)jo["z"]); } }
使用时把转换器加入序列化配置:
var jsonSettings = new JsonSerializerSettings(); jsonSettings.Converters.Add(new Vector3Converter()); string serializedData = JsonConvert.SerializeObject(yourSaveData, jsonSettings);
2. 处理字典与自定义集合
JsonUtility 不支持原生字典,需要封装可序列化的字典类:
[Serializable] public class SerializableDict<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver { [SerializeField] private List<TKey> _keys = new(); [SerializeField] private List<TValue> _values = new(); public void OnBeforeSerialize() { _keys.Clear(); _values.Clear(); foreach (var pair in this) { _keys.Add(pair.Key); _values.Add(pair.Value); } } public void OnAfterDeserialize() { Clear(); for (int i = 0; i < Math.Min(_keys.Count, _values.Count); i++) { Add(_keys[i], _values[i]); } } }
Newtonsoft.Json原生支持字典,但如果字典里存Unity值类型,要配合上面的自定义转换器使用。
3. 处理GameObject/组件(核心原则:不直接序列化引用)
Unity场景对象是动态实例,直接序列化会导致存档无法跨场景/版本兼容,正确做法是只序列化关键业务数据:
- 先定义纯数据类,存储需要存档的参数:
[Serializable] public class PlayerSaveData { public Vector3 position; public Quaternion rotation; public int currentHealth; public SerializableDict<string, int> inventory; // 用自定义可序列化字典 } - 存档时从组件提取数据,读档时把数据赋值回对象:
// 存档逻辑 var saveData = new PlayerSaveData(); saveData.position = playerTransform.position; saveData.currentHealth = playerHealthComp.currentHealth; string json = JsonConvert.SerializeObject(saveData, jsonSettings); File.WriteAllText(Application.persistentDataPath + "/playerSave.json", json); // 读档逻辑 string loadedJson = File.ReadAllText(Application.persistentDataPath + "/playerSave.json"); var loadedData = JsonConvert.DeserializeObject<PlayerSaveData>(loadedJson, jsonSettings); playerTransform.position = loadedData.position; playerHealthComp.currentHealth = loadedData.currentHealth;
4. 现成工具替代
如果不想自己写逻辑,Asset Store里的Easy Save 3或Save Game Pro都原生支持Unity值类型、集合,还封装了场景对象的安全序列化逻辑,不用额外写转换器。
避坑提醒
- 永远不要直接序列化
MonoBehaviour、GameObject这类Unity对象,只序列化纯数据类; JsonUtility要求序列化类必须标记[Serializable],私有字段要加[SerializeField]才能被序列化;- Newtonsoft.Json序列化时,用
[JsonIgnore]标记不需要存档的字段,避免生成冗余数据。
内容的提问来源于stack exchange,提问作者Yasser Ahmed
相关产品推荐
相关产品推荐

