# 代码深度评审 DeepDive 2026 Q2 > 评审范围:`Assets/Scripts/` 416 个 .cs 文件(DeepDive_2026.md 修复完成后的新一轮评审) > 重点模块:Audio、Camera、Dialogue、Quest、Progression、EventChain、UI、Tutorial、World(全子系统)、Support > 评审标准:以商业级成熟作品(Hollow Knight、Celeste、Hades)为参照基线 --- ## 一、评审维度与总分 | 维度 | 满分 | 得分 | 说明 | |------|------|------|------| | 架构设计 (Architecture) | 25 | 21 | SO 事件总线 + ServiceLocator 整体优秀,但仍有混用 Instance/ServiceLocator | | 性能 (Performance) | 25 | 20 | 批处理 / 对象池 / 环形缓冲区均到位;3 处反射调用是负担 | | 可扩展性 (Extensibility) | 20 | 17 | 谜题接口、EventChain、WorldStateRegistry 设计良好;对话变体未实装 | | 编辑器友好 (Editor UX) | 15 | 13 | HurtBoxEditor / EventBusMonitorWindow 完善;极少数字段缺少 Tooltip | | 使用便利性 (DX / API) | 15 | 12 | 核心 API 简洁;namespace 缺失与 SaveManager.Instance 残留拉低得分 | | **合计** | **100** | **83** | | --- ## 二、各维度详细评分与问题清单 ### 2.1 架构设计 (21/25) #### 优点 - **SO 事件频道体系**成熟,`BaseEventChannelSO` + `EventSubscription(IDisposable)` + `CompositeDisposable.AddTo()` 完整闭环,各系统无直接依赖。 - **ServiceLocator** 统一服务注册,`GetOrDefault` 优雅处理可选服务。 - **GameStateMachine** 显式白名单状态机,避免非法转换,DeepDive_2026 已完善。 - **25 个 asmdef** 严格单向依赖链(Core → Player → Combat → … → World),编译隔离优秀。 - **WorldStateRegistry** 作为 ScriptableObject,SO 注入代替全局单例,设计一流。 - **EventChainManager** 中继 C# 事件架构清晰,Editor 专用静态事件零运行时开销。 #### 问题 | ID | 文件 | 描述 | 严重性 | |----|------|------|--------| | A-1 | `QuestManager.cs` | `OnEnable/OnDisable` 使用已废弃的 `SaveManager.Instance?.Register/Unregister` | 中 | | A-2 | `ShopController.cs` | 同 A-1,`SaveManager.Instance?.Register/Unregister` | 中 | | A-3 | `EventChainManager.cs` | `Awake` 中使用 `SaveManager.Instance?.GetCompletedChains()` | 中 | | A-4 | `TutorialManager.cs` | 使用原始 Singleton 模式(`public static Instance`),未注册 ServiceLocator | 低 | | A-5 | `DialogueManager.cs` | `ResolveVariant()` 为存根,变体条件从未与 `WorldStateRegistry` 实际对接 | 低 | --- ### 2.2 性能 (20/25) #### 优点 - `EventBusMonitor`:固定 256 条 `EventRecord[]` 环形缓冲区,Editor 零 GC。 - `GlobalObjectPool`:`WarmupAsync` 预热,`IObjectPoolService` 接口注册,`ServiceLocator` 解耦。 - `BatchLOSSystem`:`HashSet + List` 双结构,O(1) 查重 + 分帧限制 8 个请求。 - `EquipmentManager.UsedNotches`:缓存字段,完全消除 LINQ Sum。 - `AudioManager`:6 路 SFX 轮转池,避免高密度战斗音效互戳;BGM 双 Source 交叉淡入淡出。 - `HomingProjectile`:方向向量用 `sqrMagnitude` 比较速度上限,无开方开销。 #### 问题 | ID | 文件 | 描述 | 严重性 | |----|------|------|--------| | P-1 | `LiquidZone.cs` | `PlayFeedback()` 通过 `GetMethod("PlayFeedbacks")` 反射调用,每次玩家进出液体区都触发 | 高 | | P-2 | `PuzzleSwitch.cs` | 同 P-1,同一反射模式 | 高 | | P-3 | `PuzzleReceiver.cs` | 同 P-1,同一反射模式 | 高 | | P-4 | `Projectile.cs` | `ReturnToPool()` 使用 `GlobalObjectPool.Instance`(已标废弃),应走 ServiceLocator | 低 | --- ### 2.3 可扩展性 (17/20) #### 优点 - `PuzzleInterfaces.cs`:`ISwitchable / IMovable / IActivatable` 三接口,谜题元素完全可替换实现。 - `AchievementCondition` + 11 个具体实现:抽象基类 + 工厂,新增成就类型零侵入现有代码。 - `EventChainSO` + `ChainCondition`:ScriptableObject 配置驱动,策划可在 Inspector 搭建复杂叙事链。 - `WorldStateRegistry.WorldObjectCategory`:枚举泛化 API,一个 registry 统一 Collectible/Door/Flag 等全部世界状态。 - `ToolSlotManager`:工具栏插槽与 SO 解耦,扩展新工具只需新建 ToolSO。 #### 问题 | ID | 文件 | 描述 | 严重性 | |----|------|------|--------| | E-1 | `DialogueManager.cs` | `ResolveVariant` 永远返回原始序列;条件分支对话完全无效 | 中 | | E-2 | `AchievementManager.cs` | 注册为具体类型 `Register`,无法在测试中 mock | 低 | --- ### 2.4 编辑器友好 (13/15) #### 优点 - `HurtBoxEditor`:运行时实时展示注入对象,调试受击逻辑极为便利。 - `EventBusMonitorWindow`:环形缓冲区在 Editor 窗口可视,零 GC。 - `BossSkillSequenceWindow`:Boss 技能序列可视化 Inspector。 - `AddressKeyValidator`:构建时自动校验 Addressable Key 拼写,防止发布错误。 - `WorldStateRegistry.OnEnable() => _states.Clear()`:每次进入 Play Mode 自动重置 SO 状态,无脏数据问题。 - `EventChainManager`:`OnChainExecutedInEditor` 静态事件仅在编辑器存在,零运行时影响。 #### 问题 | ID | 文件 | 描述 | 严重性 | |----|------|------|--------| | UX-1 | 全局 | `SpeedrunTimer`、`AccessibilityManager` 缺少 namespace,IDE 浏览/搜索时易混淆 | 低 | | UX-2 | `AntiSoftlockSystem.cs` | 类体未在 namespace 内缩进,与项目其他文件风格不一致 | 低 | --- ### 2.5 使用便利性(API/DX)(12/15) #### 优点 - `ServiceLocator.GetOrDefault(fallback)` 安全查询,代码调用方无需 null 判断。 - `DamageInfo.From(so, knockDir, sourcePos, layer)` 工厂方法 + `Builder`:两种构造路径清晰。 - `CompositeDisposable.AddTo()`:Rx 风格订阅管理,防止事件泄漏。 - `QuestManager`:`IQuestManager` 接口 + `ServiceLocator.Register(this)`,调用方面向接口编程。 - `SkillSlotNames`:常量类消除 `"SoulSkill"` 等魔法字符串。 #### 问题 | ID | 文件 | 描述 | 严重性 | |----|------|------|--------| | D-1 | `SpeedrunTimer.cs` | 缺少 namespace,与全局命名空间污染冲突 | 低 | | D-2 | `AccessibilityManager.cs` | 缺少 namespace | 低 | | D-3 | `UIManager.cs` | `TogglePause()` 只开不合,按两次暂停后第二次无效 | 中 | | D-4 | `AchievementManager.cs` | `_saveRef` 字段在 `OnLoad` 赋值后从未读取(死代码) | 低 | --- ## 三、与商业标准的横向对比 | 对比项 | Hollow Knight 参照模式 | 本项目现状 | |--------|------------------------|-----------| | 事件解耦 | 自定义 C# 事件 + delegate | SO 频道体系,更 Inspector 友好 ✓ | | 状态机 | 纯 C# 非 MonoBehaviour 状态 | 同,PlayerStateBase 模式一致 ✓ | | 对象池 | 静态池,键值 string | GlobalObjectPool + IObjectPoolService + ServiceLocator ✓✓ | | 存档系统 | PlayerPrefs + 二进制 | Newtonsoft.Json + MD5 校验 + SemaphoreSlim 防并发 ✓✓ | | 依赖注入 | 无(大量 singleton) | ServiceLocator(部分残留 singleton 待清理) ≈ | | Addressables | Unity 自有 AssetBundle | Addressables + AddressKeyValidator 构建校验 ✓✓ | | 谜题系统 | 基于碰撞的单一谜题 | ISwitchable/IActivatable 接口体系 ✓✓ | | 对话变体 | 全局标记条件分支 | 框架存在但未接入 WorldStateRegistry(TODO) △ | | 速通支持 | 无内置计时器 | SpeedrunTimer + ISaveable 持久化 ✓ | | 无障碍 | 无内置色盲/震屏控制 | AccessibilityManager + ColorblindFilter ✓ | --- ## 四、修复项汇总(按优先级) | 优先级 | ID | 文件 | 修复内容 | |--------|----|------|----------| | 高 | P-1,P-2,P-3 | `LiquidZone.cs`, `PuzzleSwitch.cs`, `PuzzleReceiver.cs` | 反射 → `MoreMountains.Feedbacks.MMFeedbacks` 直接转型 | | 中 | A-1 | `QuestManager.cs` | `SaveManager.Instance` → `ServiceLocator.GetOrDefault()` | | 中 | A-2 | `ShopController.cs` | 同上 | | 中 | A-3 | `EventChainManager.cs` | 同上 | | 中 | D-3 | `UIManager.cs` | `TogglePause()` 改为真实 toggle | | 低 | P-4 | `Projectile.cs` | `GlobalObjectPool.Instance` → `ServiceLocator.GetOrDefault()` | | 低 | D-1 | `SpeedrunTimer.cs` | 补齐 namespace | | 低 | D-2 | `AccessibilityManager.cs` | 补齐 namespace | | 低 | D-4 | `AchievementManager.cs` | 删除 `_saveRef` 死代码字段 | | 低 | UX-2 | `AntiSoftlockSystem.cs` | 类体补全缩进 | --- ## 五、不在本次修复范围内的已知问题(技术债) | 问题 | 原因/说明 | |------|----------| | `DialogueManager.ResolveVariant()` 存根 | 需 Phase 4 完整接入 `WorldStateRegistry` 条件标记,属功能开发范畴,非代码质量问题 | | `TutorialManager` raw singleton | 功能正确,仅可测试性不足;整改需新增接口,成本大于收益 | | `AchievementManager` 注册具体类型 | 暂无 mock 需求,改为接口注册需新建 interface,暂缓 | | `AudioManager.PlayBGM/PlaySFX(key)` 存根 | 等待 Phase 2 AudioEventSO 模块,属功能开发范畴 |