Files
gold_dolphin/unity/Docs/quantum-pulse-turing.md
2026-07-07 03:40:27 +08:00

84 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Unity 项目解耦架构重构 — 整体计划(v1.1)
> 配套详细诊断与改造映射见 `Docs/解耦架构重构方案.md`(已据同行评审修正至 v1.1)
> 当前状态:**P0 地基 + P1 事件去静态化 + P2 大部分(去 Find/反射/Shader.Find)已落地**P2d 运行时集合接入、P3/P4/P5/P6 待推进
## 1. 目标
**ScriptableObject 为通信总线**,消除当前耦合腐烂信号:
- 7 个跨场景单例(`GameManager`/`AudioManager`/`ScoreManager`/`SceneLoader`/`TimeController`/`EnemyManager`/`LightMaskSystem`
- `GameObject.Find/FindWithTag/FindObjectsByType` 散落运行时(含 `GameHUD` 条件性 `FindWithTag` 补救、`EnemyAI` Start 一次 `FindWithTag``MainMenuUIController` 对象名耦合)
- UI 反射读私有字段(`GameHUD``EnemyHealthBar`
- God Class`GameManager`/`HealthSystem`);`PlayerController` 仅轻度耦合
- `static Action` 事件伪总线(`onGameOver/onGameWin/onPlayerDamaged/OnEchoReleased/onScoreChanged`
- `Resources.Load` / `Shader.Find` 字符串硬编码资源路径
**结果形态**:所有共享状态进 Variable 资产、跨系统消息走 Event 通道、实体集合走 RuntimeSet。MonoBehaviour 只认 SO 资产引用,彼此不再直连。
## 2. 目标架构分层
```
L0 SO 通信总线(项目级资产,跨场景存活,无 MonoBehaviour
· Event 通道:GameEvent / IntEvent / Vector3Event / StringEvent / GameObjectEvent
· Variable 资产:FloatVariable / IntVariable / BoolVariable / Vector3Variable
· RuntimeSet<T>:玩家集 / 敌人集 / 灵灯集
↓ 监听/触发(Inspector 引用) ↓ 注册/读取
L1 系统服务(Audio/Scene/Time/Spawn L2 实体(Player/Enemy/Lantern
↓ 触发事件
L3 表现层(HUD/Overlay,只读 Variable + 监听 Event
```
层间**零直接类引用**,谁触发/监听全在 Inspector 可见可配。
## 3. 四条铁律
1. **调用方不碰单例** → 改 `XxxEvent.Raise()`,服务类自己订阅
2. **生产代码零 `GameObject.Find`** → 找实体走 `RuntimeSet`
3. **共享状态进 Variable** → UI 订阅 `OnValueChanged`,不再反射/逐帧 Find
4. **一个 MonoBehaviour 一件事** → 拆分 God Class
## 4. 已落地地基(P0,增量零侵入)
`Assets/Architecture/`(**未改动任何现有文件**,可整体回滚):
- `Core/GameEvent.cs` — 无参事件通道 + `GameEventListener`
- `Core/TypedGameEvents.cs``GameEvent<T>` + Int/Float/Vector3/String/GameObject 通道及监听器(含补全的 `StringEventListener`
- `Variables/` — Float/Int/Bool/Vector3 Variable,带 `OnValueChanged` + `ContextMenu` 重置
- `RuntimeSets/RuntimeSet.cs``RuntimeSet<T>` + `TransformRuntimeSet` + `RuntimeSetRegistrar` + 泛型 `RuntimeSetRegistrar<T>`
- `Editor/VariableDrawer.cs` — Inspector 实时显示变量值
- `Variables/VariableRegistry.cs`**运行时状态泄漏防护**`IVariable` 接口 + `VariableRegistry`,在每次进入 Play Mode 时(`[RuntimeInitializeOnLoadMethod(BeforeSceneLoad)]`)统一 `ResetToDefault()`,防止 SO 变量跨局持久化(如 PlayerHealth 残留 0 直接触发死亡)
- `Editor/AssetBootstrap.cs` — 一键生成核心 SO 资产(菜单 `Architecture > Bootstrap Core Assets`),已存在则跳过;变量同时写入 `_value``_defaultValue`,从源头杜绝跨 Play Mode 泄漏
## 5. 分阶段路线图
| 阶段 | 目标 | 关键动作 | 风险 |
|---|---|---|---|
| **P0 地基**(已完成) | 引入通信总线 | 落地 `Assets/Architecture/` + 创建首批资产 | 极低 |
| **P1 事件去静态化** | 消灭 `static Action` 事件 | `onGameOver/onGameWin/onPlayerDamaged/onScoreChanged/onScoreSettled/OnEchoReleased` → SO 事件资产,1:1 替换订阅 | 低 |
| **P2 去掉 Find** | 消灭 Find / 反射 | 建 `PlayerRuntimeSet`/`EnemyRuntimeSet`/`LanternRuntimeSet`,预制体挂 Registrar;改写 `GameHUD`/`EnemyAI`/`GameManager`/`MainMenuUIController`/`GameLostOverlay`/`EnemyHealthBar` | 中 |
| **P3 去单例调用方** | 调用方不再 `XxxManager.Instance` | `Audio/Scene/Time/Score` 改事件订阅者;`ScorePickup`/`SoulDrop`/`ScoringUIController` 改走 Variable/Event | 中 |
| **P4 拆分 God Class** | 单一职责 | `GameManager`→状态机+过场+敌人控制;`HealthSystem`→健康+死亡表现;`PlayerController` 轻量剥离 `RequireComponent` | 中高 |
| **P5 资源与配置** | 去 `Resources.Load`/`Shader.Find`/魔法串 | 音频/视频→**SerializeField 直接引用(AudioClip/VideoClip 拖到 SO/组件)****不引入 Addressables**(此项目体量下 Addressables 工程复杂度过高,需装包/建分组/异步加载);`Shader.Find`→资产引用;场景名/标签→SO 配置 | 中 |
| **P6 工具与守门** | 防回归 | `VariableDrawer`(已完成)+ 构建期校验脚本(扫描生产代码 `GameObject.Find`+ 设计师文档 | 低 |
建议节奏:**P0→P1→P2 一个迭代内完成**(收益最大、风险最低);P3/P4 按系统逐个推进;P5/P6 并行。
## 6. 关键待改文件清单(按阶段)
- **P1**`GameManager.cs`(去 `onGameOver`/`onGameWin` static)、`HealthSystem.cs``EchoSystem.cs``ScoreManager.cs`(去 `onScoreChanged` **+ `onScoreSettled` 两个 static**,二者需一并迁移)
- **P2**`GameHUD.cs``:104` 条件 `FindWithTag` + `:150-199` 反射)、`EnemyHealthBar.cs``:50-53,73-75` 反射)、`EnemyAI.cs``:112` FindWithTag + `:232` Damage)、`GameManager.cs``FindObjectsOfType<EnemyAI>`)、`MainMenuUIController.cs``:55,61,66,143` 对象名耦合)、`GameLostOverlay.cs``:85` 自查找);并创建 `PlayerRuntimeSet`/`EnemyRuntimeSet`/`LanternRuntimeSet` 资产
- **P3**`AudioManager`/`SceneLoader`/`TimeController`/`ScoreManager` 改订阅者;`ScorePickup.cs:39`/`SoulDrop.cs:110`/`ScoringUIController.cs`/`MainMenuUIController.cs:206,216`/`GameLostOverlay.cs:246``Raise`
- **P4**`GameManager.cs` 拆分;`HealthSystem.cs` 拆分;`Player.cs` 轻量剥离 `RequireComponent`
- **P5**`AudioManager.cs:121`/`StoryPVPlayer.cs:141``Resources.Load` → SO 资产引用;`Shader.Find` **共 5 处** → 序列化 `Shader` 字段引用:`GameLostOverlay.cs:358`(WaterRippleFade)、`EchoSystem.cs:140`(EchoRing,已有 `ringShader` 字段)、`GroundBuilder.cs:180`(AbyssEdgeGlow)、`CliffWallBuilder.cs:108`(AbyssEdgeGlow)、`GroundClipTool.cs:19`(SpriteWithGroundClip**Editor 脚本,运行时不进包,可保留 Shader.Find,但建议同样改字段引用**));场景名魔法串 → `SceneList` SO
- **P6**:构建期校验脚本(扫描 `GameObject.Find`+ 设计师 SO 配置文档
## 7. 本迭代建议起点(P1+P2 验证链路)
1. 运行菜单 `Architecture > Bootstrap Core Assets` 一键生成首批资产(`PlayerHealth`/`Score` IntVariable、`OnGameOver`/`OnGameWin`/`OnPlayerDied`/`OnPlayerDamaged` GameEvent、`EchoReleased`/`ScoreChanged`/`ScoreSettled` 带载荷事件、`Players`/`Enemies` RuntimeSet);已存在则跳过
2. 从最小系统切入:把 `GameHUD` 接到 `PlayerHealth` 变量(消灭逐帧条件 Find 回退)+ 消除 `EnemyHealthBar` 反射(改用 `maxHealth`/`health` 的 IntVariable 订阅)
3. 跑通后按路线图逐阶段推进;具体系统改造指名文件即可
## 8. 风险与回滚
- 架构核心位于 `Assets/Architecture/`,可整体删除回滚;P1/P2 对既有文件的改造均为"加 SO 字段 + 改订阅方式",保留原逻辑,可逐文件回退
- 迁移保持"旧接口可用、新接口并行",每阶段独立验证,避免大爆炸重写
- 事件通道为引用语义:误删资产会在 Inspector 显示缺失引用(编译期可查),不会静默失效——比反射/单例安全