Unity跨会话保存数据:复杂对象存储问题及优化方案求助
我正在开发一款游戏,需要跨会话保存玩家进度。目前我使用以下方法保存PlayerState类:
// Get the user data path string userDataPath = Path.Combine(Application.persistentDataPath, "userState_" + username + ".json"); // Convert to JSON and save to file string playerData = JsonUtility.ToJson(this); File.WriteAllText(userDataPath, playerData);
该方法在处理字符串、整数等简单类型(如用户名、等级、金币)时运行正常,但保存装备、英雄等复杂类时出现问题。例如我的EquipmentData类如下:
using UnityEngine; public enum EquipmentType { Armour, Weapon, Medalion, Horse, Cloak, Book, Horn}; public enum EquipmentGrade { Blue, Green, Yellow, Red, Purple, Golden }; [System.Serializable] public class EquipmentData : MonoBehaviour { public Sprite sprite; public string equipmentName; public EquipmentType equipmentType; public EquipmentGrade equipmentGrade; [Range(0f, 1f)] public float dropRate; [HideInInspector] public int ownedFragments; public int fragmentsToSynthesize; public int valorAttack; public int valorDefense; public int spiritAttack; public int spiritDefense; public int elementAttack; public int elementDefense; public int troopBase; }
玩家可强化装备的至少7项属性,每件装备最多有10项可修改属性,且背包中可能存在数百件不同等级的装备。我尝试将包含挂载EquipmentData的GameObject列表的inventory添加到PlayerState中,但跨会话保存无效:
[HideInInspector] [SerializeField] public List<GameObject> inventory;
Unity仅会在会话内保存instanceID,重启后无法使用。
我曾考虑拆分到不同JSON文件(如username_equipment.json),但文件体积过大,序列化/反序列化繁琐,且后续更新装备、英雄等内容时维护难度高。
现提出两个问题:
- 能否在Unity中保存GameObject或类以实现跨会话复用?
- 若不可行,如何更优地保存这类大量数据?
问题1:能否在Unity中保存GameObject或类以实现跨会话复用?
直接保存GameObject不可行——Unity序列化GameObject时仅存储会话内有效的实例ID、引用关系等数据,重启后这些ID完全失效,无法重建对象。
但可以保存纯数据类(不继承MonoBehaviour的可序列化类),这是Unity跨会话保存复杂数据的标准做法。你当前的EquipmentData继承了MonoBehaviour,会被当作组件而非纯数据处理,序列化时会包含大量Unity内部组件信息,干扰数据保存。
问题2:更优的大量数据保存方案
针对你的装备系统,推荐以下优化方案:
1. 重构数据类,分离逻辑与数据
将EquipmentData改为纯数据类,移除MonoBehaviour继承,保留[System.Serializable]特性:
using UnityEngine; public enum EquipmentType { Armour, Weapon, Medalion, Horse, Cloak, Book, Horn}; public enum EquipmentGrade { Blue, Green, Yellow, Red, Purple, Golden }; [System.Serializable] public class EquipmentData { // 用Sprite的资源路径代替Sprite对象,加载时通过路径读取 public string spritePath; public string equipmentName; public EquipmentType equipmentType; public EquipmentGrade equipmentGrade; public float dropRate; public int ownedFragments; public int fragmentsToSynthesize; public int valorAttack; public int valorDefense; public int spiritAttack; public int spiritDefense; public int elementAttack; public int elementDefense; public int troopBase; // 新增强化等级等动态属性 public int强化Level; }
注意:Sprite无法直接序列化,改用资源路径(如"Sprites/Equipment/Armour_01"),加载时通过Resources.Load<Sprite>(spritePath)重建引用。
2. 调整PlayerState的Inventory结构
将List<GameObject>替换为List<EquipmentData>,直接存储数据而非游戏对象:
[HideInInspector] [SerializeField] public List<EquipmentData> inventory;
这样JsonUtility.ToJson()可直接序列化整个装备列表,不会丢失数据。
3. 优化JSON存储方式
- 单文件分块存储:无需拆分多个文件,在
PlayerState中嵌套不同数据模块(如PlayerEquipmentData、PlayerHeroData),保持单文件的同时让结构清晰:
[System.Serializable] public class PlayerState { public string username; public int level; public int gold; public PlayerEquipmentData equipmentData; public PlayerHeroData heroData; } [System.Serializable] public class PlayerEquipmentData { public List<EquipmentData> inventory; public List<EquipmentData> equippedItems; }
- 压缩数据:若文件体积过大,可将JSON字符串压缩后再写入文件,读取时先解压:
// 保存时压缩 string json = JsonUtility.ToJson(playerState); byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); using (var ms = new System.IO.MemoryStream()) { using (var gzip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress)) { gzip.Write(jsonBytes, 0, jsonBytes.Length); } File.WriteAllBytes(userDataPath, ms.ToArray()); } // 读取时解压 byte[] compressedBytes = File.ReadAllBytes(userDataPath); using (var ms = new System.IO.MemoryStream(compressedBytes)) { using (var gzip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)) { using (var reader = new System.IO.StreamReader(gzip)) { string json = reader.ReadToEnd(); JsonUtility.FromJsonOverwrite(json, playerState); } } }
4. 可选:使用更强大的序列化库
如果JsonUtility功能不足(如不支持字典、复杂嵌套结构),可使用Unity官方集成的Newtonsoft.Json(在Package Manager中搜索安装),它对复杂数据结构的序列化支持更好,API与JsonUtility类似,迁移成本低。
内容的提问来源于stack exchange,提问作者eligolf

