unity-reusable-systems
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnity Reusable Systems
Unity可复用系统
Build every gameplay system as a self-contained UPM package. Data lives in
ScriptableObjects, behavior lives in small single-responsibility MonoBehaviours,
and systems talk through SO Event Channels — never direct references.
Target: Unity 6+ / C# 11.
将每个游戏玩法系统构建为独立的UPM包。数据存储在ScriptableObject中,行为由单一职责的小型MonoBehaviour实现,系统间通过SO Event Channels通信——绝不使用直接引用。
适用版本:Unity 6+ / C# 11.
The Rules
规则
| ALWAYS | NEVER |
|---|---|
| One system = one UPM package | Create a "shared contracts" package with interfaces |
| Data in ScriptableObjects, behavior in MonoBehaviours | Put data and behavior in the same class |
| SO Event Channels for cross-system communication | Use singletons, service locators, or static managers |
| One assembly definition per folder (Runtime, Editor, Tests) | Ship without assembly definitions |
| Version Defines for optional cross-package awareness | Use |
| Define Constraints for conditional integration assemblies | Create hard dependencies between gameplay packages |
Small MonoBehaviours with | God classes that handle input + logic + rendering |
| ScriptableVariable for shared runtime state | Public static fields or global state holders |
| RuntimeSet for tracking active instances | FindObjectsOfType or singleton registries |
| Coroutines for new async work |
| Deep inheritance hierarchies |
| Composition: many small components on one GameObject | One MonoBehaviour doing everything |
| Interfaces only at package boundaries when SO Events can't solve it | Interfaces inside a single package |
| Tests using ScriptableObject.CreateInstance in Edit Mode | Skipping tests because "it's just a SO" |
| 必须遵循 | 严禁操作 |
|---|---|
| 一个系统对应一个UPM包 | 创建包含接口的「共享契约」包 |
| 数据存于ScriptableObject,行为存于MonoBehaviour | 将数据和行为放在同一个类中 |
| 跨系统通信使用SO Event Channels | 使用单例、服务定位器或静态管理器 |
| 每个文件夹(Runtime、Editor、Tests)对应一个assembly definition | 发布时不带assembly definition |
| 可选跨包感知使用Version Defines | 在asmdef中使用 |
| 条件集成程序集使用Define Constraints | 为游戏玩法包创建硬依赖 |
小型MonoBehaviour搭配 | 创建同时处理输入+逻辑+渲染的上帝类 |
| 共享运行时状态使用ScriptableVariable | 使用公共静态字段或全局状态持有者 |
| 跟踪活动实例使用RuntimeSet | 使用FindObjectsOfType或单例注册器 |
异步操作使用带 | 新异步任务使用协程 |
多态序列化数据使用 | 过深的继承层次结构 |
| 组合模式:一个GameObject上挂载多个小型组件 | 单个MonoBehaviour处理所有逻辑 |
| 仅在SO事件无法解决时,在包边界使用接口 | 在单个包内部使用接口 |
| 编辑模式下使用ScriptableObject.CreateInstance进行测试 | 以「只是个SO」为由跳过测试 |
Where Does This Code Belong?
代码归属指南
- Data or config? → ScriptableObject
- Needs MonoBehaviour lifecycle? → MonoBehaviour
- Editor-only tooling? → Editor/ folder (EditorWindow / PropertyDrawer)
- Pure logic, no Unity deps? → Plain C# class in Runtime/
- Otherwise → MonoBehaviour
- 数据或配置?→ ScriptableObject
- 需要MonoBehaviour生命周期?→ MonoBehaviour
- 仅编辑器工具?→ Editor/ 文件夹(EditorWindow / PropertyDrawer)
- 纯逻辑、无Unity依赖?→ Runtime/ 下的普通C#类
- 其他情况 → MonoBehaviour
How Should Systems Communicate?
系统通信方式指南
- Same package, same GameObject/parent-child? → C# event/delegate
- Same package, different GameObjects? → SO Event Channel
- Cross-package, sharing runtime state? → ScriptableVariable
- Cross-package, always installed together? → SO Event Channel
- Cross-package, optionally installed? → Version Defines + SO Event Channel or bridge package
- 同包、同GameObject/父子对象?→ C#事件/委托
- 同包、不同GameObject?→ SO Event Channel
- 跨包、共享运行时状态?→ ScriptableVariable
- 跨包、始终一起安装?→ SO Event Channel
- 跨包、可选安装?→ Version Defines + SO Event Channel 或桥接包
New Package Checklist
新包检查清单
Before shipping any package, verify:
- with correct
package.json,name,version(6000.0+),unitydisplayName - with
Runtime/— zero external references{Company}.{Package}.asmdef - with Editor-only asmdef (if any editor code exists)
Editor/ - with test asmdef using
Tests/Editor/andoverrideReferencestestAssemblies - with at least one importable sample
Samples~/ - following SemVer
CHANGELOG.md - All SOs have with organized menu paths
[CreateAssetMenu] - All MonoBehaviours use where applicable
[RequireComponent] - SO Event Channels for every output event (no direct subscriber lists)
- ScriptableVariables for any shared runtime state
- RuntimeSets for any "all active X" queries
- Version Defines in asmdef for any optional package awareness
- No , no singletons, no static mutable state
FindObjectsOfType
发布任何包前,请确认:
- 包含正确的
package.json、name、version(6000.0+)、unitydisplayName - 目录下有
Runtime/—— 无外部引用{Company}.{Package}.asmdef - 若存在编辑器代码,目录下有仅编辑器可用的asmdef
Editor/ - 目录下有使用
Tests/Editor/和overrideReferences的测试asmdeftestAssemblies - 目录下至少有一个可导入的示例
Samples~/ - 遵循SemVer规范
CHANGELOG.md - 所有SO都配置并设置规整的菜单路径
[CreateAssetMenu] - 所有MonoBehaviour在适用时使用
[RequireComponent] - 每个输出事件都使用SO Event Channel(无直接订阅列表)
- 共享运行时状态使用ScriptableVariable
- 所有「所有活动X」查询使用RuntimeSet
- 可选包感知在asmdef中配置Version Defines
- 无、无单例、无静态可变状态
FindObjectsOfType
System Pattern Quick Reference
系统模式速查
| System | SO Config | SO Event Channels | ScriptableVariable | RuntimeSet | Bridge Pattern |
|---|---|---|---|---|---|
| Inventory | ItemDefinition, SlotConfig | OnItemAdded, OnItemRemoved | CurrentWeight, SlotCount | ActiveInventories | Version Defines to shop/crafting |
| Combat | WeaponData, AttackConfig | OnHitDealt, OnHitReceived | — | ActiveCombatants | SO Event to health system |
| Health | HealthConfig, ResistanceProfile | OnDamaged, OnHealed, OnDied | CurrentHP | ActiveHealthComponents | Listens to combat's SO Events |
| Dialogue | DialogueTree, NodeData | OnDialogueStarted, OnChoiceMade | CurrentDialogue | — | Version Defines to quest system |
| Save/Load | SaveConfig | OnSaveRequested, OnLoadComplete | — | SaveableEntities | Each system implements ISaveable |
| Quest | QuestDefinition, ObjectiveData | OnQuestStarted, OnObjectiveComplete | ActiveQuest | ActiveQuests | Listens to dialogue/combat events |
| AI | BehaviorTreeData, StateConfig | OnStateChanged | CurrentTarget | ActiveAIAgents | Version Defines to combat/nav |
| 系统 | SO配置 | SO事件通道 | ScriptableVariable | RuntimeSet | 桥接模式 |
|---|---|---|---|---|---|
| 背包系统 | ItemDefinition、SlotConfig | OnItemAdded、OnItemRemoved | CurrentWeight、SlotCount | ActiveInventories | 通过Version Defines对接商店/制作系统 |
| 战斗系统 | WeaponData、AttackConfig | OnHitDealt、OnHitReceived | — | ActiveCombatants | SO事件对接生命值系统 |
| 生命值系统 | HealthConfig、ResistanceProfile | OnDamaged、OnHealed、OnDied | CurrentHP | ActiveHealthComponents | 监听战斗系统的SO事件 |
| 对话系统 | DialogueTree、NodeData | OnDialogueStarted、OnChoiceMade | CurrentDialogue | — | 通过Version Defines对接任务系统 |
| 存档/读档 | SaveConfig | OnSaveRequested、OnLoadComplete | — | SaveableEntities | 每个系统实现ISaveable接口 |
| 任务系统 | QuestDefinition、ObjectiveData | OnQuestStarted、OnObjectiveComplete | ActiveQuest | ActiveQuests | 监听对话/战斗系统事件 |
| AI系统 | BehaviorTreeData、StateConfig | OnStateChanged | CurrentTarget | ActiveAIAgents | 通过Version Defines对接战斗/导航系统 |
Reference Files
参考文件
Load these as needed — they contain code snippets and detailed patterns:
- references/package-structure.md — UPM directory layout, asmdef setup, Version Defines, Define Constraints, SemVer rules, distribution
- references/so-architecture.md — ScriptableVariable, SO Event Channel, GameEventListener, RuntimeSet code patterns
- references/patterns.md — Component composition, cross-package integration, bridge packages, SerializeReference, Awaitable async, system decomposition
- references/testing.md — Test asmdef setup, SO test patterns, event test patterns, Edit vs Play Mode guidance
按需查阅以下文件——它们包含代码片段和详细模式说明:
- references/package-structure.md — UPM目录结构、asmdef配置、Version Defines、Define Constraints、SemVer规则、分发方式
- references/so-architecture.md — ScriptableVariable、SO Event Channel、GameEventListener、RuntimeSet代码模式
- references/patterns.md — 组件组合、跨包集成、桥接包、SerializeReference、Awaitable异步、系统拆分
- references/testing.md — 测试asmdef配置、SO测试模式、事件测试模式、编辑模式与运行模式测试指南