unity-reusable-systems

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Unity 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

规则

ALWAYSNEVER
One system = one UPM packageCreate a "shared contracts" package with interfaces
Data in ScriptableObjects, behavior in MonoBehavioursPut data and behavior in the same class
SO Event Channels for cross-system communicationUse singletons, service locators, or static managers
One assembly definition per folder (Runtime, Editor, Tests)Ship without assembly definitions
Version Defines for optional cross-package awarenessUse
#if
defines without versionDefines in asmdef
Define Constraints for conditional integration assembliesCreate hard dependencies between gameplay packages
Small MonoBehaviours with
[RequireComponent]
God classes that handle input + logic + rendering
ScriptableVariable for shared runtime statePublic static fields or global state holders
RuntimeSet for tracking active instancesFindObjectsOfType or singleton registries
Awaitable
with
destroyCancellationToken
for async
Coroutines for new async work
[SerializeReference]
for polymorphic serialized data
Deep inheritance hierarchies
Composition: many small components on one GameObjectOne MonoBehaviour doing everything
Interfaces only at package boundaries when SO Events can't solve itInterfaces inside a single package
Tests using ScriptableObject.CreateInstance in Edit ModeSkipping tests because "it's just a SO"
必须遵循严禁操作
一个系统对应一个UPM包创建包含接口的「共享契约」包
数据存于ScriptableObject,行为存于MonoBehaviour将数据和行为放在同一个类中
跨系统通信使用SO Event Channels使用单例、服务定位器或静态管理器
每个文件夹(Runtime、Editor、Tests)对应一个assembly definition发布时不带assembly definition
可选跨包感知使用Version Defines在asmdef中使用
#if
定义但不配置versionDefines
条件集成程序集使用Define Constraints为游戏玩法包创建硬依赖
小型MonoBehaviour搭配
[RequireComponent]
创建同时处理输入+逻辑+渲染的上帝类
共享运行时状态使用ScriptableVariable使用公共静态字段或全局状态持有者
跟踪活动实例使用RuntimeSet使用FindObjectsOfType或单例注册器
异步操作使用带
destroyCancellationToken
Awaitable
新异步任务使用协程
多态序列化数据使用
[SerializeReference]
过深的继承层次结构
组合模式:一个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:
  • package.json
    with correct
    name
    ,
    version
    ,
    unity
    (6000.0+),
    displayName
  • Runtime/
    with
    {Company}.{Package}.asmdef
    — zero external references
  • Editor/
    with Editor-only asmdef (if any editor code exists)
  • Tests/Editor/
    with test asmdef using
    overrideReferences
    and
    testAssemblies
  • Samples~/
    with at least one importable sample
  • CHANGELOG.md
    following SemVer
  • All SOs have
    [CreateAssetMenu]
    with organized menu paths
  • All MonoBehaviours use
    [RequireComponent]
    where applicable
  • 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
    FindObjectsOfType
    , no singletons, no static mutable state
发布任何包前,请确认:
  • package.json
    包含正确的
    name
    version
    unity
    (6000.0+)、
    displayName
  • Runtime/
    目录下有
    {Company}.{Package}.asmdef
    —— 无外部引用
  • 若存在编辑器代码,
    Editor/
    目录下有仅编辑器可用的asmdef
  • Tests/Editor/
    目录下有使用
    overrideReferences
    testAssemblies
    的测试asmdef
  • Samples~/
    目录下至少有一个可导入的示例
  • CHANGELOG.md
    遵循SemVer规范
  • 所有SO都配置
    [CreateAssetMenu]
    并设置规整的菜单路径
  • 所有MonoBehaviour在适用时使用
    [RequireComponent]
  • 每个输出事件都使用SO Event Channel(无直接订阅列表)
  • 共享运行时状态使用ScriptableVariable
  • 所有「所有活动X」查询使用RuntimeSet
  • 可选包感知在asmdef中配置Version Defines
  • FindObjectsOfType
    、无单例、无静态可变状态

System Pattern Quick Reference

系统模式速查

SystemSO ConfigSO Event ChannelsScriptableVariableRuntimeSetBridge Pattern
InventoryItemDefinition, SlotConfigOnItemAdded, OnItemRemovedCurrentWeight, SlotCountActiveInventoriesVersion Defines to shop/crafting
CombatWeaponData, AttackConfigOnHitDealt, OnHitReceivedActiveCombatantsSO Event to health system
HealthHealthConfig, ResistanceProfileOnDamaged, OnHealed, OnDiedCurrentHPActiveHealthComponentsListens to combat's SO Events
DialogueDialogueTree, NodeDataOnDialogueStarted, OnChoiceMadeCurrentDialogueVersion Defines to quest system
Save/LoadSaveConfigOnSaveRequested, OnLoadCompleteSaveableEntitiesEach system implements ISaveable
QuestQuestDefinition, ObjectiveDataOnQuestStarted, OnObjectiveCompleteActiveQuestActiveQuestsListens to dialogue/combat events
AIBehaviorTreeData, StateConfigOnStateChangedCurrentTargetActiveAIAgentsVersion Defines to combat/nav
系统SO配置SO事件通道ScriptableVariableRuntimeSet桥接模式
背包系统ItemDefinition、SlotConfigOnItemAdded、OnItemRemovedCurrentWeight、SlotCountActiveInventories通过Version Defines对接商店/制作系统
战斗系统WeaponData、AttackConfigOnHitDealt、OnHitReceivedActiveCombatantsSO事件对接生命值系统
生命值系统HealthConfig、ResistanceProfileOnDamaged、OnHealed、OnDiedCurrentHPActiveHealthComponents监听战斗系统的SO事件
对话系统DialogueTree、NodeDataOnDialogueStarted、OnChoiceMadeCurrentDialogue通过Version Defines对接任务系统
存档/读档SaveConfigOnSaveRequested、OnLoadCompleteSaveableEntities每个系统实现ISaveable接口
任务系统QuestDefinition、ObjectiveDataOnQuestStarted、OnObjectiveCompleteActiveQuestActiveQuests监听对话/战斗系统事件
AI系统BehaviorTreeData、StateConfigOnStateChangedCurrentTargetActiveAIAgents通过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测试模式、事件测试模式、编辑模式与运行模式测试指南