关于 unity-patterns
面向 Unity 开发者的模式选择技能,根据具体问题评估是否需要采用设计模式,并比较可行方案的复杂度与取舍。强调只推荐少量合适模式,避免不必要的抽象。
主要功能
- 01评估模式是否适用
- 02涵盖常见 Unity 设计模式
- 03比较实现方案的成本与风险
- 04说明最小实现边界和取舍
适用场景
- 01为解耦系统选择合适模式
- 02在事件、状态机和对象池间作判断
- 03比较暂停多个敌人 AI 的实现方案
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ besty0728/ unity-skills --skill unity-patterns安装后在 Claude Code 中输入/unity-patterns确认已加载。
详细介绍
调用此模块中的任何技能前: 如果你打算根据技能名称或描述猜测参数后调用技能,请先停下——先阅读此文件(或通过
GET /skills/recommend?includeSchema=true获取其架构)。如果你已从 recommend/schema 获得参数定义,则可直接进行 dryRun。
触发条件
- 判断哪种模式适合某个问题
- 构建解耦系统
- 在事件、状态机和对象池方案间做选择
- 判断哪种模式适合某个问题、构建解耦系统、在事件/状态机/对象池方案间抉择
Unity 模式选择器
使用此技能判断某种模式是否合理。不要一次性推荐所有模式。
注意事项
模式:仅限文档——无 REST 技能需要控制;任何运行模式(Approval / Auto / Bypass)下均可自由加载。
- 最多推荐 1-3 种模式,并说明为什么更简单的方案不够用。
模式指南
-
ScriptableObject- 适用于创作配置、共享静态数据、事件通道和可复用数据资源。
- 避免将其作为每次运行时可变游戏状态的默认存放位置。
-
C# events / delegates- 适用于所有权和取消订阅时机明确的一对多通知。
- 避免用于需要顺序执行、返回值或复杂调试的命令式流程。
-
Global event bus / observer hub- 谨慎使用,且仅在许多系统确实需要广泛的解耦通知时使用。
- 避免将其作为解决耦合问题的默认方案。它常会隐藏所有权,让调试更困难。
-
Interfaces- 适用于需要多种实现或更清晰依赖边界的场景。
- 如果没有实际的扩展点,避免为每个类都添加接口。
-
State machine- 适用于具有互斥状态和明确转换的角色。
- 如果少量布尔值或简单命令流程就足够,避免使用状态机。
-
Object pool- 适用于频繁生成和销毁子弹、VFX、敌人和 UI 项目。
- 对于很少使用的对象,或生命周期简单的对象,避免使用对象池。
-
Service layer- 适用于数量较少、需要跨场景使用且具有明确启动流程和接口的系统。
- 避免将所有内容都变成隐藏的单例或服务定位器。
-
Generics / custom attributes- 适用于能够通过明确的类型安全性或编辑器元数据价值减少重复样板代码的场景。
- 如果它们让游戏代码比重复的简单代码更难阅读,就应避免使用。
决策实验室:相同目标,多种实现方式
上面的模式指南回答了“该用哪种模式?”。对于大多数非简单的设计决策,更好的做法是:选出 2-3 种可行的实现方式,逐一并排比较切换成本、查询成本、代码复杂度和故障模式。下面是一个完整示例;请将其作为其他决策的参考形式,而不是直接套用的答案。
实例:“在过场动画期间暂停 100 个敌人”
| 实现方式 | 切换成本(进入/退出过场动画) | 暂停期间每帧成本 | 代码复杂度 | 失败模式 |
|---|---|---|---|---|
字段标记:每个 EnemyAI.Update 开头都执行 if (_paused) return;;管理器设置该标记 | O(N) 次写入,无分配 | 每帧 N 次分支判断 + 分派开销 | 最低——一个 bool,一个保护子句 | 开发者新增 Update 却忘记添加保护逻辑时,会出现不易察觉的错误 |
enabled = false:管理器禁用每个敌人上的 MonoBehaviour | O(N) 次写入,无分配 | 零——Unity 会在消息列表中跳过已禁用的 Behaviours | 较低,但状态分散在各组件中 | OnDisable / OnEnable 副作用(协程停止、监听器取消订阅)可能意外触发 |
子集列表:管理器维护 _active / _frozen 列表;不再逐个敌人调用 Update——管理器只对 _active 中的敌人进行逐帧处理 | 切换时移动 O(N) 个列表项 | 仅与 _active 的数量成正比——可完美提前剔除 | 最高——所有权由单一事实来源管理,且需要由管理器逐帧处理 | 在敌人上新增 Update 会重新引入逐帧成本;如果其他代码直接重新生成敌人,列表很容易不同步 |
如何使用
- 选择权衡开始显现的最小规模。N=5 时,三种方式没有明显区别;N=5000 时,只有子集列表的成本保持不变。
- 说明每种方案会在哪些方面变差,而不只是哪些方面有所改善。表格里只有优点,说明你还没有充分考虑。
- ECS 的经验是,同样的三种形式(值变更、结构变更、可启用)会在各处出现——即使框架不同,这些标签也适用。来源:
Dots101/Entities101/Assets/HelloCube/13. StateChange/SetStateSystem.cs:42-80——一个系统通过config.Mode将任务分派到三种实现,每种实现的成本都能在性能分析器中清晰测量。
何时跳过此练习
如果某个方案显然有明确边界(N ≤ 10、每次会话只改变一次状态,或代码只在启动时运行一次),用一段话说明“我们选择了 X,因为它最简单”就足够了。Decision Lab 适用于那些影响会超出当前任务范围的选择。
输出格式
- 推荐的模式
- 为什么适合当前情况
- 为什么不选择更简单的替代方案
- 最小实现边界
- 已知权衡
评论
支持 Markdown