Unity 3D中从JSON加载多个GameObject遇问题求助
Unity JSON存读系统问题解决方案
错误原因分析
你遇到的CS1579错误,是因为JsonUtility.FromJson<objectData>(json)返回的是单个objectData实例,而非可枚举的集合(比如List、数组),foreach语句只能遍历实现了IEnumerable接口的类型,所以无法直接遍历单个对象。
同时,原代码用File.WriteAllText写入文件时,会完全覆盖原有内容;如果直接用File.AppendAllText追加字符串,会破坏JSON格式导致无法解析,必须通过读取已有数据合并新内容的方式实现“追加”效果。
修正后的完整代码
1. 定义序列化数据类与容器类
Unity的JsonUtility无法直接序列化顶级数组/List,需要用容器类包裹;同时确保数据类可被序列化:
using System.Collections.Generic; using UnityEngine; using System.IO; [Serializable] public class ObjectDataContainer { public List<objectData> objectList = new List<objectData>(); } [Serializable] public class objectData { public string name; public float trfx; public float trfy; public float trfz; public float rotx; public float roty; public float rotz; }
2. 修正保存方法(支持追加数据)
读取已有文件数据,合并新对象后再写入,避免覆盖原有内容:
public void SaveToJson(string ObjectName, float trfx, float trfy, float trfz, float rotx, float roty, float rotz) { string filePath = Application.dataPath + "/ObjectDataFile.json"; ObjectDataContainer container = new ObjectDataContainer(); // 读取已有数据(如果文件存在) if (File.Exists(filePath)) { string existingJson = File.ReadAllText(filePath); container = JsonUtility.FromJson<ObjectDataContainer>(existingJson); } // 创建新数据并添加到列表 objectData newData = new objectData(); newData.name = ObjectName; newData.trfx = trfx; newData.trfy = trfy; newData.trfz = trfz; newData.rotx = rotx; newData.roty = roty; newData.rotz = rotz; container.objectList.Add(newData); // 序列化并写入文件(合并后覆盖,实现追加效果) string json = JsonUtility.ToJson(container, true); File.WriteAllText(filePath, json); }
3. 修正加载方法(遍历多个对象)
读取容器类中的对象列表,逐个实例化:
public void LoadFromJson() { string filePath = Application.dataPath + "/ObjectDataFile.json"; if (!File.Exists(filePath)) { Debug.LogError("对象数据文件不存在"); return; } string json = File.ReadAllText(filePath); ObjectDataContainer container = JsonUtility.FromJson<ObjectDataContainer>(json); // 遍历所有保存的对象数据 foreach (objectData data in container.objectList) { // 注意:GameObject.Find仅能找到场景中已激活的对象,若加载预制体建议用Resources.Load GameObject targetPrefab = GameObject.Find(data.name); if (targetPrefab == null) { Debug.LogError($"找不到名为 {data.name} 的对象/预制体"); continue; } Vector3 pos = new Vector3(data.trfx, data.trfy, data.trfz); Quaternion rot = Quaternion.Euler(data.rotx, data.roty, data.rotz); Instantiate(targetPrefab, pos, rot); } }
额外注意事项
- 预制体加载优化:如果要实例化预制体,建议将预制体放入
Resources文件夹,改用Resources.Load<GameObject>(data.name)加载,避免GameObject.Find受对象激活状态的限制。 - 字段序列化权限:确保
objectData的字段为public,或添加[SerializeField]标签,否则JsonUtility无法序列化这些字段。 - 路径适配:发布后建议改用
Application.persistentDataPath作为文件存储路径,该路径在所有平台都具备读写权限,避免Application.dataPath在部分平台的权限问题。
内容的提问来源于stack exchange,提问作者ShulkTNT2
相关产品推荐
相关产品推荐

