【Unity】 ScriptableObject ——生成多个ScriptableObject作为子对象,可以点击展开并显示二级菜单
官方是这么介绍ScriptabelObject的:
“ScriptableObject 是一个可独立于类实例来保存大量数据的数据容器。ScriptableObject 的一个主要用例是通过避免重复值来减少项目的内存使用量。如果项目有一个预制件在附加的 MonoBehaviour 脚本中存储不变的数据,这将非常有用。
每次实例化预制件时,都会产生单独的数据副本。这种情况下可以不使用该方法并且不存储重复数据,而是使用 ScriptableObject 来存储数据,然后通过所有预制件的引用访问数据。这意味着内存中只有一个数据副本。
就像 MonoBehaviour 一样,ScriptableObject 派生自基本 Unity 对象,但与 MonoBehaviour 不同,不能将 ScriptableObject 附加到游戏对象。正确的做法是需要将它们保存为项目中的资源。
如果使用 Editor,可以在编辑时和运行时将数据保存到 ScriptableObject,因为 ScriptableObject 使用 Editor 命名空间和 Editor 脚本。但是,在已部署的构建中,不能使用 ScriptableObject 来保存数据,但可以使用在开发期间设置的 ScriptableObject 资源中保存的数据。
从 Editor 工具作为资源保存到 ScriptableObject 的数据将写入磁盘,因此将在会话之间一直保留。”
但是在实际项目中,如果遇到需要配置很多个同类型ScriptableObject对象,但是ScriptableObject具体数据不同的情况下,如果全部保存成单个文件,看下来会比较乱。
于是我们可以把归属于同一个模块的ScriptabelObject放入同一个大的模块下,在后期查找修改也比较方便。
1.想要获得上方的效果,首先我们需要一个最外层ScriptabelObject对象
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "ItemTemplate", menuName = "Custom/ItemTemplate")] public class ItemTemplate : ScriptableObject { public List<SubItemTemplate> subItems = new List<SubItemTemplate>(); }
通过这个类,我们可以点击菜单栏的Assets→Creat→Custem→ItemTemplate创建一个ScriptabelObject对象。
2.最外层ScriptabelObject需要包含若干子对象,具备一个折叠效果
1 2 3 4 5 6 7 8 9 10 11 | using System.Collections; using UnityEngine; [CreateAssetMenu(fileName = "SubItem" , menuName = "Custom/SubItem" )] public class SubItemTemplate : ScriptableObject { public int ID; } |
3.需要自己定义一个Editor编辑器拓展,使得在Inspector界面上具备一定的功能。

using UnityEditor; using UnityEngine; [CustomEditor(typeof(ItemTemplate))] public class ItemTemplateEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); GUILayout.Space(10); ItemTemplate mainObject = (ItemTemplate)target; if (GUILayout.Button("Add Child Object")) { SubItemTemplate childObject = ScriptableObject.CreateInstance<SubItemTemplate>(); childObject.name = "SubItem"; Undo.RegisterCreatedObjectUndo(childObject, "Create Child Object"); AssetDatabase.AddObjectToAsset(childObject, mainObject); AssetDatabase.SaveAssets(); mainObject.subItems.Add(childObject); EditorUtility.SetDirty(mainObject); } GUILayout.Space(10); if (GUILayout.Button("Remove All Child Objects")) { foreach (SubItemTemplate childObject in mainObject.subItems) { AssetDatabase.RemoveObjectFromAsset(childObject); DestroyImmediate(childObject, true); } mainObject.subItems.Clear(); AssetDatabase.SaveAssets(); EditorUtility.SetDirty(mainObject); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?