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

7.7 KiB
Raw Blame History

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 一次 FindWithTagMainMenuUIController 对象名耦合)
  • UI 反射读私有字段(GameHUDEnemyHealthBar
  • God ClassGameManager/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.csGameEvent<T> + Int/Float/Vector3/String/GameObject 通道及监听器(含补全的 StringEventListener
  • Variables/ — Float/Int/Bool/Vector3 Variable,带 OnValueChanged + ContextMenu 重置
  • RuntimeSets/RuntimeSet.csRuntimeSet<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. 关键待改文件清单(按阶段)

  • P1GameManager.cs(去 onGameOver/onGameWin static)、HealthSystem.csEchoSystem.csScoreManager.cs(去 onScoreChanged + onScoreSettled 两个 static,二者需一并迁移)
  • P2GameHUD.cs:104 条件 FindWithTag + :150-199 反射)、EnemyHealthBar.cs:50-53,73-75 反射)、EnemyAI.cs:112 FindWithTag + :232 Damage)、GameManager.csFindObjectsOfType<EnemyAI>)、MainMenuUIController.cs:55,61,66,143 对象名耦合)、GameLostOverlay.cs:85 自查找);并创建 PlayerRuntimeSet/EnemyRuntimeSet/LanternRuntimeSet 资产
  • P3AudioManager/SceneLoader/TimeController/ScoreManager 改订阅者;ScorePickup.cs:39/SoulDrop.cs:110/ScoringUIController.cs/MainMenuUIController.cs:206,216/GameLostOverlay.cs:246Raise
  • P4GameManager.cs 拆分;HealthSystem.cs 拆分;Player.cs 轻量剥离 RequireComponent
  • P5AudioManager.cs:121/StoryPVPlayer.cs:141Resources.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(SpriteWithGroundClipEditor 脚本,运行时不进包,可保留 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 显示缺失引用(编译期可查),不会静默失效——比反射/单例安全