Unity ScriptableObject 架构
将以下提示词粘贴到你的 AI 对话框中:
请根据 https://skillhub.cn/install/skillhub.md 的步骤,将 @user_3c6cb52e/unity-scriptableobjects-f6ns 安装到你的 AI 助手中。
技能介绍
要解决的问题
Unity 项目里最常见的耦合来源,是"数据放在谁身上"这件事没有明确边界。把武器数值写进 MonoBehaviour,策划改一个攻击力就得动代码;用 static 单例做全局配置,场景切换后引用丢失,测试也难以隔离。当多个互不相关的系统需要共享同一份数据时,硬连线的方式会让模块之间互相依赖,改一处牵一片。
这个技能的思路是:让 ScriptableObject 资产承担共享数据的角色,把配置、事件和注册表从场景与单例中剥离出来,成为项目窗口里可视化的、可被设计师直接编辑的资产。
核心能力与工作方式
技能面向 Unity 6 (6000.0 LTS),围绕三类典型场景组织:
- 配置/数据资产——武器属性、关卡数据这类设计期数据,通过
[CreateAssetMenu]从 Assets 菜单创建实例,策划在编辑器里直接维护。 - 共享运行时变量——例如一个
FloatVariable资产,玩家代码写入、HUD 读取,生产方与消费方互不引用,彻底解耦。 - 事件通道与运行时注册表——信号与事件以 ScriptableObject 建模,配合类型安全的负载实现多监听者模式;注册表则维护一组活跃对象的共享列表。
核心工作流分六步:定义继承 ScriptableObject 的类并标记 [CreateAssetMenu];在 Project 窗口创建 .asset 实例;MonoBehaviour 只持有引用而非拷贝;以信号和共享变量模型建模解耦;若运行中修改过资产,在 OnEnable 中重置运行时状态;最后在 Play 模式下检查资产值并确认消费者正确响应。
适用边界与注意点
不适合的场景要明确:每个 GameObject 独有的运行时状态(如两只敌人的当前血量不同)应放在 MonoBehaviour 上;玩家进度存档应走 save-systems;纯数据传输对象用 [System.Serializable] 类即可,不必做成资产。
几个高频陷阱值得警惕:
- Play 模式下的资产编辑会持久化——运行时改的值在停止后仍留在资产上,建议把可变运行时状态放进
[NonSerialized]字段并在OnEnable重置(构建版本中不会持久化,仅限编辑器)。 - 禁用 Domain Reload 会跳过 OnEnable 重置——Unity 6 的快速迭代设置下,已加载的 SO 在按 Play 时不会重建,需要改用
ISerializationCallbackReceiver或场景加载钩子显式重置。 - SO 没有逐帧生命周期——只有
OnEnable/OnDisable/OnDestroy,没有Update。 - 运行时
CreateInstance的对象不会像普通 C# 对象那样被 GC——用完要Destroy,避免泄漏。
更深入的事件通道模式(带类型安全负载)与运行时注册表用法,可参见技能的 references/event-channels.md。
使用场景
- 游戏策划需要频繁调整武器数值与关卡配置,希望不改代码、不重新打包即可立即生效
- UI 与玩家控制器等互不引用的系统需要读写同一个共享变量,如金币数或当前血量
- 需要在运行时收集并共享当前所有活跃敌人的列表,替代静态单例全局管理器
- 想把全局配置与信号从场景硬连线中剥离,统一改为项目窗口里设计师可编辑的 .asset 资产
适合人员
- Unity 客户端工程师:想消除系统间的硬连线依赖,用共享资产替代 static 单例与场景内置配置
- 游戏策划 / 关卡设计师:需要自行调整武器与关卡数值,不必每次改动都走程序流程或等构建
- 团队技术负责人:想为项目的数据存放与事件通信建立统一规范,避免各处自建单例造成的耦合