Unity C# ScriptableObject修改内容无法保存到磁盘问题求助
问题原因
- 缺少显式序列化标记:
List<Textures> textures字段未显式添加[SerializeField],特殊场景下Unity会跳过该字段的序列化,导致重启后数据被重置。 - 编辑器API调用不规范:
EditorUtility.SetDirty、AssetDatabase.SaveAssets等编辑器专属API没有加条件编译限制,如果脚本放在Runtime目录下会触发编译错误,直接导致序列化失败;且在OnValidate、OnDisable、OnDestroy中频繁强制保存资源,会在序列化未完成时写入错误数据,最终覆盖你的修改。 - 自动保存逻辑打乱默认时序:你在生命周期函数中强制调用
AssetDatabase.SaveAssets会打乱Unity自身的资源保存逻辑,尤其在编辑器退出时调用该接口,大概率会将未完成序列化的空数据写入资源文件,直接导致修改丢失。
解决方案
- 给所有需要持久化的字段显式添加
[SerializeField]标记,确保Unity正确序列化内容。 - 所有编辑器专属API用
#if UNITY_EDITOR条件编译包裹,避免运行时编译报错。 - 移除生命周期函数中不必要的
AssetDatabase.SaveAssets调用,Unity会在你手动保存项目(Ctrl+S)或正常退出时自动保存所有标记为Dirty的资源。 - 调整
OnValidate逻辑,仅在race字段实际修改时触发列表重置,避免误覆盖已编辑的内容。
修改后参考代码
using System; using System.Collections.Generic; using UnityEngine; // 编辑器命名空间用条件编译引入 #if UNITY_EDITOR using UnityEditor; #endif namespace ModelManager { [CreateAssetMenu(fileName = "New Texture Set", menuName = "Model Manager/New Texture Set")] public class TextureSetSO : ScriptableObject { [SerializeField] public RaceModelSO race; // 显式加SerializeField确保序列化 [SerializeField] public List<Textures> textures; // 非序列化私有字段加NonSerialized标记,避免不必要的序列化尝试 [NonSerialized] private RaceModelSO _race; private void OnEnable() { _race = race; } private void OnValidate() { if (race != _race) { _race = race; textures.Clear(); if (race) { var slots = race.GetRaceBodySlots(); if (slots.Length != 0) { for (int i = 0; i < slots.Length; i++) { Textures newTexture = new Textures(); newTexture.raceSlot = slots[i]; textures.Add(newTexture); } } } // 仅在数据实际变更时标记Dirty,且加条件编译 #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } } } [Serializable] public class Textures { public RaceSlotSO raceSlot; public Texture normalMap; public Texture albedoMap; public Texture metalicMap; public Texture ambientOcullsionMap; public Texture emissionMap; } }
额外持久化方案(可选)
如果需要额外的备份机制,可以在类中添加右键菜单功能,将ScriptableObject内容序列化为JSON存储到本地:
#if UNITY_EDITOR [ContextMenu("导出配置到JSON")] public void ExportToJson() { string json = EditorJsonUtility.ToJson(this, prettyPrint: true); string path = EditorUtility.SaveFilePanel("导出配置", Application.dataPath, name + ".json", "json"); if (!string.IsNullOrEmpty(path)) { System.IO.File.WriteAllText(path, json); AssetDatabase.Refresh(); } } [ContextMenu("从JSON导入配置")] public void ImportFromJson() { string path = EditorUtility.OpenFilePanel("导入配置", Application.dataPath, "json"); if (!string.IsNullOrEmpty(path)) { string json = System.IO.File.ReadAllText(path); EditorJsonUtility.FromJsonOverwrite(json, this); EditorUtility.SetDirty(this); } } #endif
修改完成后,每次编辑完ScriptableObject内容按Ctrl+S保存项目即可,重启Unity不会再丢失修改。
内容的提问来源于stack exchange,提问作者Venelin
相关产品推荐
相关产品推荐

