关于 unity-scriptableobjects
unity-scriptableobjects 是面向 Unity 6.3 LTS 项目的架构技能,使用 ScriptableObject 资产管理共享数据并解耦系统。适用于可由设计师编辑的配置、事件通道和运行时对象注册表。
主要功能
- 01创建共享数据资产
- 02使用事件通道解耦系统
- 03构建运行时对象注册表
- 04通过资产引用共享配置
- 05处理运行时变更与重置
适用场景
- 01配置武器属性或关卡数据
- 02让不同系统通过事件通信
- 03追踪运行中的对象集合
- 04避免用单例管理共享数据
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill unity-scriptableobjects安装后在 Claude Code 中输入/unity-scriptableobjects确认已加载。
附带文件references/event-channels.md
详细介绍
Unity ScriptableObject 架构
使用 ScriptableObject 资源存储共享数据,在 Unity 6.3 LTS 中解耦系统——配置、事件通道和注册表都作为项目资源存在,而不是硬编码到场景或单例中。目标版本为 Unity 6.3 LTS (6000.3)。
适用场景
- 需要可由设计师编辑的配置(武器属性、关卡数据)、在无关系统之间共享同一个值、通过事件通道解耦发送方与监听方,或构建活动对象的运行时注册表,且不想使用
static/单例管理器时。 - 项目包含由
: ScriptableObject类支持的*.asset数据文件时。
不适用场景: 因 GameObject 而异的每实例运行时状态(这类状态应放在 MonoBehaviour 上)——ScriptableObject 资源会被所有引用它的对象共享。将玩家进度保存到磁盘 → save-systems。永远不需要作为资源的普通 DTO 可以直接使用 [System.Serializable] 类。
核心工作流
- 定义类,使其继承自
ScriptableObject,并添加[CreateAssetMenu]标记,让设计师可以从 Assets 菜单创建实例。 - 在 Project 窗口中创建一个或多个
.asset实例;每个实例都是一份共享且命名的数据,可通过[SerializeField]字段引用。 - 引用,而非复制。 MonoBehaviour 持有对资源的引用;它们看到的都是同一份数据,因此修改资源会影响所有使用者。
- 实现解耦时,将 信号 和 共享变量 建模为 ScriptableObject:HUD 读取、玩家写入的 "FloatVariable";玩家触发、多个系统监听的 "event channel"。双方都不引用对方。
- 如果在运行期间修改了资源,请在
OnEnable中重置运行时改动,因为在运行时于 Editor 中所做的编辑会保留在资源上(这是“我的值在运行后变了”的常见原因)。 - 验证:在 Play 模式下检查资源值,并确认使用者会作出响应。
模式
1. 配置/数据资源
using UnityEngine;
[CreateAssetMenu(fileName = "WeaponData", menuName = "Game/Weapon Data", order = 0)]
public class WeaponData : ScriptableObject
{
public string displayName = "Pistol";
public int damage = 10;
public float fireRate = 0.25f;
public GameObject projectilePrefab;
}
public class Weapon : MonoBehaviour
{
[SerializeField] private WeaponData data; // assign the shared asset in the Inspector
private void Fire() => Debug.Log($"{data.displayName} for {data.damage}");
}
2. 共享运行时变量(解耦生产者与使用者)
[CreateAssetMenu(menuName = "Game/Float Variable")]
public class FloatVariable : ScriptableObject
{
[SerializeField] private float initialValue;
[System.NonSerialized] public float runtimeValue; // not saved to the asset
private void OnEnable() => runtimeValue = initialValue; // reset each play session
}
// Player writes playerHealth.runtimeValue; the HUD reads it — neither references the other.
3. 在运行时创建实例(不是磁盘上的资源)
// For transient SO data you build in code (e.g. a generated config).
var temp = ScriptableObject.CreateInstance<WeaponData>();
temp.damage = 25;
// ...use temp... Destroy(temp); // clean up runtime-created instances
注意事项
- 在运行时编辑 SO 会在 Editor 中保留——你在 Play 期间修改的值,在停止后仍会保留在资源上。请将可变运行时状态放在
[NonSerialized]字段中,并在OnEnable中重置,否则可能造成意外。(在 构建版本 中,资源编辑不会跨启动保留。) - 禁用 Domain Reload 会跳过你的
OnEnable重置——启用 Enter Play Mode Options 并关闭 Reload Domain(Unity 6.3 LTS 的快速迭代设置)时,已加载的 SO 在按下 Play 时不会重新创建,因此不会触发OnEnable,runtimeValue会保留上次会话中的值。请改为通过ISerializationCallbackReceiver或场景加载钩子显式重置,而不要只依赖OnEnable。 - 不要期待每个对象拥有独立状态——每个引用都指向 同一个 资源。如果两个敌人需要不同的当前 HP,请将 HP 存储在 MonoBehaviour 上,而不是共享 SO 中。
- 没有逐帧生命周期——ScriptableObject 有
OnEnable/OnDisable/OnDestroy,但没有Update。不要期待逐帧回调。 - 不要将 SO 用作存档文件——它们是创作资源,不用于运行时持久化;请改用
save-systems保存进度。 - 不要泄漏
CreateInstance对象——运行时创建的实例不像普通 C# 对象那样由垃圾回收器回收;使用完毕后请调用Destroy销毁它们。
参考资料
- 关于事件通道模式(
GameEventSO + 监听器、类型安全的负载)和运行时集合/注册表(活动敌人的共享列表),请阅读references/event-channels.md。 - 主要文档:Unity Manual“ScriptableObject”(
/Manual/class-ScriptableObject.html)以及ScriptReference/ScriptableObject、ScriptReference/CreateAssetMenuAttribute。
相关技能
unity-csharp-scripting— 使用这些资源的 MonoBehaviours。save-systems— 将状态持久化到磁盘(这不是 SO 的用途)。card-game/rpg/survival-crafting— 依赖 SO 驱动数据的游戏类型。
评论
支持 Markdown