v10 全量评审:修复 TD-06 至 TD-12(InputReader 移除资产扫描回退 / EmergencySave 解除 LocalFileStorage 直接依赖 / AccessibilityManager 注册 IAccessibilityService / HUDController HP/SpringIcon SetActive 复用 / MovingPlatform 缓存 WaitForSeconds / RewardSO IRewardTarget 解耦 Quest←Player 依赖 / CrashReporter 频率限制崩溃日志)
This commit is contained in:
405
Docs/Review/FrameworkReview_2026_May_v8.md
Normal file
405
Docs/Review/FrameworkReview_2026_May_v8.md
Normal file
@@ -0,0 +1,405 @@
|
||||
# BaseGames 框架代码评审 v8
|
||||
|
||||
**评审日期**: 2026 年 5 月
|
||||
**版本**: v8(继 v7 之后的全量新模块深度评审)
|
||||
**评审范围**: `Assets/Scripts/` 全体 270+ C# 文件
|
||||
**审阅标准**: 商业级 2D Action RPG,Unity 2022.3 LTS,C# 9,无向后兼容需求
|
||||
|
||||
---
|
||||
|
||||
## 1. 综合评分
|
||||
|
||||
| 维度 | 权重 | v6 | v7 | v8 | 变化 |
|
||||
|------|------|-----|-----|-----|------|
|
||||
| 架构设计 | 20% | 9.0 | 9.2 | 9.2 | — |
|
||||
| 性能 | 18% | 8.5 | 8.7 | 8.6 | ▼0.1 |
|
||||
| 可扩展性 | 15% | 8.8 | 9.1 | 9.2 | ▲0.1 |
|
||||
| 编辑器友好 | 12% | 9.3 | 9.4 | 9.4 | — |
|
||||
| 使用便利性 | 12% | 8.8 | 9.0 | 9.1 | ▲0.1 |
|
||||
| 框架纯净度 | 8% | 9.0 | 9.3 | 9.1 | ▼0.2 |
|
||||
| 数据一致性 | 8% | 8.8 | 9.1 | 9.0 | ▼0.1 |
|
||||
| 可测试性 | 7% | 7.8 | 7.9 | 7.9 | — |
|
||||
| **加权总分** | | **8.73** | **9.00** | **8.99** | **▼0.01** |
|
||||
|
||||
> v8 在 SkillModifierRegistry 可扩展性、CrashReporter/EmergencySaveService 容错设计方面有明显正向发现,但 BreadcrumbTracker `FindWithTag` 残留(框架纯净度扣分)、CrumblePlatform 缺少状态持久化(数据一致性)、SettingsManager 每次写磁盘(性能)共同导致加权总分微降 0.01。修复两处后,估计可达 **9.05**。
|
||||
|
||||
---
|
||||
|
||||
## 2. v8 新增模块总览
|
||||
|
||||
v8 相较 v7 首次覆盖以下系统,每个模块均经过逐行代码审阅:
|
||||
|
||||
| 模块 | 关键文件 | 评价 |
|
||||
|------|----------|------|
|
||||
| 音频系统 | `AudioManager`, `BGMController`, `CombatSFXController`, `AudioZone` | ⭐ 双 Source BGM 交叉淡入,6 源 SFX 轮转池,Mixer 快照切换,生产级 |
|
||||
| 相机系统 | `CameraStateController`, `RoomCamera` | ✅ Cinemachine 服务接口化,`BlendProfile SO` 可配 |
|
||||
| VFX 系统 | `VFXPool`, `HitFXSpawner` | ⭐ Addressables 粒子池,协程回收,预热 API |
|
||||
| 动画事件 | `AnimationEventBinder` | ✅ 静态工具,捕获变量规避闭包陷阱 |
|
||||
| 技能系统 | `SkillManager`, `FormController`, `SkillModifierRegistry` | ⭐ 零分配 Update,形态热切换,OCP 数值覆盖设计 |
|
||||
| UI 系统 | `UIManager`, `HUDController`, `RebindPanel` | ✅ Stack 面板管理,排他重绑定锁,事件驱动 HUD |
|
||||
| 对象池 | `GlobalObjectPool` | ⭐ LRU 活跃回收,双集合追踪,Addressables 预热 |
|
||||
| 存档/崩溃 | `SaveMigrator`, `CrashReporter`, `EmergencySaveService` | ⭐ fall-through 版本链,崩溃日志,定时自动存档 |
|
||||
| 场景基础 | `GameServiceRegistrar`, `SettingsManager` | ✅ `-2000` 执行序,NullObject 兜底,AudioListener 管理 |
|
||||
| 世界/关卡 | `MovingPlatform`, `CrumblePlatform`, `LiquidZone`, `AbilityGate`, `BreadcrumbTracker` | ⚠ 含 FindWithTag 违例 |
|
||||
| 挑战关卡 | `ChallengeRoomManager` | ✅ 多 wave,NoHit 验证,挑战前自动 QuickSave |
|
||||
| 防软锁 | `AntiSoftlockSystem` | ✅ 事件注入,速度检测,ServiceLocator 解耦 |
|
||||
| 分析/无障碍 | `AnalyticsManager`, `AccessibilityManager` | ⚠ AccessibilityManager 使用 static 单例 |
|
||||
| Boss 系统 | `WeakPointSystem`, `TelegraphSystem` | ✅ 弱点乘数分离,GlobalObjectPool 集成 |
|
||||
| 对话系统 | `DialogueManager` | ✅ 协程打字机,WorldStateRegistry 条件分支 |
|
||||
|
||||
---
|
||||
|
||||
## 3. v8 正面亮点(新发现)
|
||||
|
||||
### 3.1 AudioManager — 双 Source 交叉淡入淡出 ⭐
|
||||
```
|
||||
_bgmSourceA / _bgmSourceB 交替充当 Active / Inactive 角色
|
||||
CrossfadeCoroutine(clip, fadeOut, fadeIn):先淡出旧 Source,并行淡入新 Source
|
||||
SFX 6 源轮转:NextSFXSource() 防止高密度战斗音效互戳
|
||||
TransitionToSnapshot("BossFight", 0.5f):AudioMixer 快照切换一行完成
|
||||
LinearToDecibel(v):0–1 线性到 dB 内部转换,调用者无感
|
||||
```
|
||||
**点评**:与 BGMController 的 MusicState 状态机配合,形成完整的音乐状态管理闭环,区域 BGM、Boss 战、胜利花絮三段逻辑互不耦合。
|
||||
|
||||
### 3.2 SkillModifierRegistry — OCP 数值覆盖设计 ⭐
|
||||
- `Dictionary<string, List<SkillStatEntry>>` 数值叠加(支持百分比与绝对值)
|
||||
- `List<SkillSlotOverride>` 插槽替换(按 Priority 排序取优先级最高覆盖)
|
||||
- `GetEffectiveParams(skill)` 返回 `EffectiveSkillParams` 快照结构体:
|
||||
- 技能冷却、消耗、伤害倍率、范围倍率、反馈、动画均可覆盖
|
||||
- 调用方得到只读结构体,无法意外修改 Registry 内部状态
|
||||
- FormController 切换形态时同步刷新,`_activeSkills[]` 快照数组避免 Update 分配
|
||||
|
||||
**点评**:符合 Open/Closed Principle,新增装备效果只需注册对应 Entry,无需修改 SkillManager。
|
||||
|
||||
### 3.3 GlobalObjectPool — LRU 活跃回收 ⭐
|
||||
```csharp
|
||||
// MaxCount > 0 时追踪活跃链表(LinkedList<PooledObject>)
|
||||
// 尾部 = 最新;头部 = 最老(LRU)
|
||||
// 达到上限时 O(1) 回收头部,ForceReturnToPool 后立即复用
|
||||
po.AliveNode = aliveList.AddLast(po);
|
||||
// Despawn 时 O(1) 移除节点
|
||||
if (po.AliveNode != null) aliveRef.Remove(po.AliveNode);
|
||||
```
|
||||
**点评**:双集合设计(Queue 空闲 + LinkedList 活跃)是商业池实现的标准做法,O(1) 存取,不产生 GC,极少见于开源 Unity 项目。
|
||||
|
||||
### 3.4 CrashReporter + EmergencySaveService — 生产级容错 ⭐
|
||||
```
|
||||
CrashReporter:
|
||||
OnLogMessage → WriteDiagnosticLog(同步 IO,async 在崩溃时不可靠)
|
||||
OnApplicationPause(!cleanExit) → SaveAsync(slot 99)(移动端切出紧急存档)
|
||||
catch{} 保护:日志写入失败绝不递归抛异常
|
||||
|
||||
EmergencySaveService:
|
||||
Update + _intervalSeconds 定时自动存档(默认 120s)
|
||||
PromoteToSlot(target):崩溃恢复后将紧急存档升级到正式槽
|
||||
```
|
||||
**点评**:同步 IO 写崩溃日志是正确决策;`_cleanExit` 标记防止正常退出时的误触发。两者协同形成 PC + 移动端双重防护。
|
||||
|
||||
### 3.5 SaveMigrator — fall-through 版本链
|
||||
```csharp
|
||||
case v2.0: MigrateV1xTo20(root); goto case "2.1";
|
||||
case v2.1: MigrateV20To21(root); break;
|
||||
```
|
||||
使用 `System.Version.TryParse` 语义比较,`IsOlderThan` 工具方法统一封装,支持 `1.0/1.5/1.9` 等任意旧版本一次性补齐所有缺失节点,无需为每个版本组合写专属迁移逻辑。
|
||||
|
||||
### 3.6 GameServiceRegistrar — 执行序与 NullObject 兜底
|
||||
```csharp
|
||||
[DefaultExecutionOrder(-2000)] // 早于所有业务代码
|
||||
ServiceLocator.RegisterIfAbsent<IAudioService>(new NullAudioService());
|
||||
// AudioManager.Awake 后以真实实现覆盖
|
||||
// 主 AudioListener 管理:Inspector 绑定时只扫描当前场景根节点
|
||||
// 否则全量扫描并缓存,避免 FindObjectsOfType 二次调用
|
||||
```
|
||||
**点评**:`NullAudioService` 作为 NullObject 模式的兜底,使所有在 AudioManager 初始化之前调用音频的代码安全降级,无空引用。
|
||||
|
||||
### 3.7 AnimationEventBinder — 闭包陷阱规避
|
||||
```csharp
|
||||
foreach (var entry in config.SortedEvents)
|
||||
{
|
||||
var captured = entry; // 显式捕获,规避 foreach 闭包共享变量陷阱
|
||||
clip.Events.Add(captured.normalizedTime, () =>
|
||||
receiver.HandleEvent(captured.eventType, captured.data));
|
||||
}
|
||||
```
|
||||
小细节,但正确。C# `foreach` 变量捕获在旧版运行时曾是典型 Bug 来源。
|
||||
|
||||
### 3.8 RebindPanel — 排他重绑定锁
|
||||
```csharp
|
||||
private void OnRebindRequested(RebindActionRow requestingRow)
|
||||
{
|
||||
foreach (var row in _rows) row.SetInteractable(row == requestingRow);
|
||||
requestingRow.StartRebind(onFinished: () =>
|
||||
{
|
||||
foreach (var row in _rows) row.SetInteractable(true);
|
||||
_inputReader?.SaveBindingOverrides(); // 重绑定完成后立即持久化
|
||||
});
|
||||
}
|
||||
```
|
||||
防止并发重绑定导致输入状态混乱,完成后自动持久化,无需外部调用。
|
||||
|
||||
---
|
||||
|
||||
## 4. v8 发现的问题
|
||||
|
||||
### P-1(中)`BreadcrumbTracker`:`FindWithTag` 违反框架约定 ✅ 已修复
|
||||
|
||||
**位置**:`Assets/Scripts/World/BreadcrumbTracker.cs`
|
||||
**问题**:
|
||||
```csharp
|
||||
// ❌ 框架全局唯一残留的 FindWithTag 全场景扫描
|
||||
private void Awake()
|
||||
{
|
||||
var go = GameObject.FindWithTag("Player");
|
||||
if (go != null) _playerTransform = go.transform;
|
||||
}
|
||||
```
|
||||
框架中所有其他需要玩家 Transform 的组件(`AntiSoftlockSystem`、`EnemyBase`、`ProjectileManager`、`EnemyQuotaManager`)均通过 `TransformEventChannelSO` 事件频道订阅,`BreadcrumbTracker` 是唯一例外,破坏框架一致性,且在玩家延迟生成场景下会捕获失败。
|
||||
**修复**:改为 `OnEnable/OnDisable` 订阅 `_onPlayerSpawned` 事件频道。
|
||||
|
||||
---
|
||||
|
||||
### P-2(低)`GlobalObjectPool.OnDestroy`:未释放 Addressables 资产 ✅ 已修复
|
||||
|
||||
**位置**:`Assets/Scripts/Core/Pool/GlobalObjectPool.cs`
|
||||
**问题**:
|
||||
```csharp
|
||||
// ❌ OnDestroy 只注销 ServiceLocator,未释放已加载的 Addressables 预制件
|
||||
private void OnDestroy()
|
||||
{
|
||||
ServiceLocator.Unregister<IObjectPoolService>(this);
|
||||
}
|
||||
```
|
||||
`WarmupSingleAsync` 通过 `Addressables.LoadAssetAsync` 加载的预制件存入 `_prefabCache`,`ClearPool` 方法有 `Addressables.Release(pfx)` 释放逻辑,但 `OnDestroy` 不调用它,导致在编辑器退出 PlayMode 时 Addressables 引用计数不归零,可能产生 "already released" 警告或内存抖动。
|
||||
**修复**:在 `OnDestroy` 中遍历 `_prefabCache` 释放所有加载项。
|
||||
|
||||
---
|
||||
|
||||
### P-3(低)`SettingsManager`:音量设置每次写磁盘
|
||||
|
||||
**位置**:`Assets/Scripts/Core/SettingsManager.cs`
|
||||
**问题**:
|
||||
```csharp
|
||||
public void SetMasterVolume(float v) { _current.MasterVolume = v; Save(); } // Save() = File.WriteAllText
|
||||
public void SetBGMVolume(float v) { _current.BGMVolume = v; Save(); }
|
||||
// ...每次调用立即 WriteAllText,若 UI 滑动条绑定此方法 → 每帧写磁盘
|
||||
```
|
||||
若 `SettingsPanel` 的音量滑动条 `OnValueChanged` 直接绑定了这些方法,每帧均会触发磁盘写入,在低端移动设备上可能造成明显卡顿。
|
||||
**建议**:滑动条 `OnValueChanged` 仅调用 `Apply(value)`(仅修改内存),`OnEndDrag` 或"确认"按钮时才调用 `Save()`;或增加 `Commit()` 入口由 UI 层显式控制持久化时机。
|
||||
**注**:此问题属于 UI 层调用规范问题,当前 `SettingsManager` 接口设计无误,需在调用方约定。
|
||||
|
||||
---
|
||||
|
||||
### A-1(低)`AccessibilityManager`:static 单例与框架不一致
|
||||
|
||||
**位置**:`Assets/Scripts/Support/Accessibility/AccessibilityManager.cs`
|
||||
**问题**:使用 `private static AccessibilityManager _instance`,`CanPlayScreenShake()` 为静态查询方法。框架中所有其他管理器均通过 `ServiceLocator<T>` 注册和查询,此处是唯一例外。
|
||||
**影响**:`FeedbackSystem` 对 `AccessibilityManager` 类型存在直接依赖,无法在单测或 CI 环境中替换为 Mock。
|
||||
**建议**:提取 `IAccessibilityService` 接口,在 `Awake` 中 `ServiceLocator.Register<IAccessibilityService>(this)`;`FeedbackSystem` 改为 `ServiceLocator.GetOrDefault<IAccessibilityService>()?.CanPlayScreenShake() ?? true`。
|
||||
**注**:此为架构一致性改进,不影响现有功能,可在合适时机推进。
|
||||
|
||||
---
|
||||
|
||||
### DC-1(低)`CrumblePlatform`:`_isOneShot` 状态未持久化
|
||||
|
||||
**位置**:`Assets/Scripts/World/CrumblePlatform.cs`
|
||||
**问题**:`_isOneShot=true` 的平台在当前游戏会话中永久消失(正确),但未向 `WorldStateRegistry` 写入销毁状态,导致玩家重启游戏或重进场景后,已永久碎裂的平台会复原,破坏世界状态的存档一致性。
|
||||
**建议**:
|
||||
```csharp
|
||||
[SerializeField] private WorldStateRegistry _worldState;
|
||||
[SerializeField] private string _destructibleId;
|
||||
|
||||
// CrumbleSequence 碎裂后:
|
||||
if (_isOneShot && !string.IsNullOrEmpty(_destructibleId))
|
||||
_worldState?.MarkDestroyed(_destructibleId);
|
||||
|
||||
// Start/Awake 中:
|
||||
private void Start()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_destructibleId) && _worldState != null
|
||||
&& _worldState.IsDestroyed(_destructibleId))
|
||||
{
|
||||
_col.enabled = _sr.enabled = false;
|
||||
_isCrumbling = true; // 阻止重复触发
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DC-2(低)`MovingPlatform._passengers` 潜在空引用
|
||||
|
||||
**位置**:`Assets/Scripts/World/MovingPlatform.cs`
|
||||
**问题**:`_passengers` 存储乘客 `Transform` 引用。若乘客在平台上时被 `Destroy`(死亡、场景卸载),`FixedUpdate` 下一帧迭代 `_passengers` 时会遇到已销毁的 Transform。当前代码无空检查。
|
||||
**建议**:在平台 Update 入口或 `OnTriggerExit2D` 时清除已销毁的引用:
|
||||
```csharp
|
||||
_passengers.RemoveAll(t => t == null);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. v7 已修复问题复核
|
||||
|
||||
以下 6 项 v7 修复已全部验证通过(零编译错误):
|
||||
|
||||
| ID | 模块 | 问题描述 | 状态 |
|
||||
|----|------|----------|------|
|
||||
| v7-P-1 | `HitStopManager` | `FreezeDuration` 语义歧义,短请求覆盖长请求 | ✅ 已修复 |
|
||||
| v7-A-1 | `PlayerMovement` + `WallJumpState` | 直接访问 `_rb.velocity.y` 绕过运动抽象层 | ✅ 已修复 |
|
||||
| v7-A-2 | `PlayerController` | `TryTransitionState` 别名语义误导 | ✅ 已修复 |
|
||||
| v7-U-2 | `AttackState` | `OnClipEnd` 中重复注销 `AttackEvent` | ✅ 已修复 |
|
||||
| v7-P-2 | `EnemyQuotaManager` | `Unregister` O(n) 遍历,改为 swap-and-pop O(1) | ✅ 已修复 |
|
||||
| v7-S-1 | `EnemyBase` | `SetAggroTickRate` 存根缺少 LogWarning | ✅ 已修复 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 架构维度深度评估
|
||||
|
||||
### 6.1 程序集分层(Architecture)
|
||||
|
||||
```
|
||||
BaseGames.Core.Events ← 最底层(零依赖)
|
||||
BaseGames.Core.Save ← 依赖 Events
|
||||
BaseGames.Core ← 依赖 Events + Save
|
||||
BaseGames.Audio/Camera/VFX/Input ← 依赖 Core
|
||||
BaseGames.Combat/Player/Enemies ← 依赖 Core + Audio + Input
|
||||
BaseGames.Skills/Quest/UI ← 依赖上层所有
|
||||
Assembly-CSharp ← 顶层游戏逻辑
|
||||
```
|
||||
|
||||
依赖方向单向,无循环依赖,符合整洁架构原则。所有跨程序集通信通过 `BaseEventChannelSO<T>` SO 频道或 `ServiceLocator<T>` 接口,未发现运行时 `typeof` 隐式耦合。
|
||||
|
||||
### 6.2 ServiceLocator 使用一致性
|
||||
|
||||
| 服务 | 接口 | 注册方式 | 兜底 |
|
||||
|------|------|----------|------|
|
||||
| IAudioService | ✅ | GameServiceRegistrar + AudioManager | NullAudioService ✅ |
|
||||
| IObjectPoolService | ✅ | GlobalObjectPool | 无(需主动检查) |
|
||||
| ICameraService | ✅ | CameraStateController | 无 |
|
||||
| ISaveService | ✅ | GameServiceRegistrar(Adapter) | 无 |
|
||||
| IAnalyticsService | ✅ | AnalyticsManager | 无 |
|
||||
| IAccessibilityService | ❌ 缺失 | static _instance | N/A |
|
||||
| IDialogueService | ✅ | DialogueManager | 无 |
|
||||
|
||||
`IAudioService` 的 `NullAudioService` 兜底是目前框架中最完整的安全设计,建议其他关键服务跟进(至少对 `IAccessibilityService` 实现)。
|
||||
|
||||
### 6.3 事件频道使用规范
|
||||
|
||||
全框架一致使用 RAII 订阅模式:
|
||||
```csharp
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
|
||||
private void OnEnable() => _channel.Subscribe(Handler).AddTo(_subs);
|
||||
private void OnDisable() => _subs.Clear();
|
||||
```
|
||||
|
||||
**例外**: `BreadcrumbTracker`(已在 v8 修复)使用 `Awake` + `FindWithTag`。
|
||||
|
||||
### 6.4 数据流向规范
|
||||
|
||||
| 方向 | 机制 | 使用场景 |
|
||||
|------|------|----------|
|
||||
| 系统 → UI | SO 事件频道 Raise | HP 变化、状态切换 |
|
||||
| UI → 系统 | ServiceLocator.Get\<T\>() 直接调用 | 按钮事件 |
|
||||
| 系统 ↔ 系统 | SO 事件频道(跨程序集)/ C# event(同程序集高频) | BGM 切换、技能冷却 |
|
||||
| 持久化读写 | SaveManager + IStorageBackend 接口 | 全量存读档 |
|
||||
|
||||
`FormController` 的三通道广播(`SO频道 + C#事件 + SO频道`)是刻意设计:SO 频道供 UI/Save 跨程序集使用,C# event 供 `WeaponManager` 同程序集高频订阅,设计合理,已在注释中说明。
|
||||
|
||||
---
|
||||
|
||||
## 7. 性能热点总结
|
||||
|
||||
| 模块 | 优化点 | 评分 |
|
||||
|------|--------|------|
|
||||
| `SkillManager.Update` | 固定 `_activeSkills[]` 数组,零 GC 遍历 | ⭐ 优秀 |
|
||||
| `EnemyQuotaManager.Unregister` | swap-and-pop + `_indexMap` O(1) | ⭐ 优秀 |
|
||||
| `GlobalObjectPool.Despawn` | `AliveNode` 直接 LinkedList 节点移除 O(1) | ⭐ 优秀 |
|
||||
| `HitStopManager.FreezeDuration` | max-duration 语义,短请求直接返回 | ✅ 良好 |
|
||||
| `AudioManager.PlaySFX` | 6 源轮转,避免 `PlayOneShot` 切断问题 | ✅ 良好 |
|
||||
| `GameServiceRegistrar.OnSceneLoaded` | 仅扫描新场景根节点,非全场景 | ✅ 良好 |
|
||||
| `HUDController.RebuildHPCells` | Destroy+Instantiate,未池化 | ⚠ 低频可接受 |
|
||||
| `SettingsManager.SetVolume*` | 每次调用写磁盘 | ⚠ 见 P-3 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 可扩展性亮点
|
||||
|
||||
### 装备/技能数值修改 (Open/Closed)
|
||||
```
|
||||
新增装备效果:实现 IEquipmentEffect → 注册 SkillModifierRegistry
|
||||
无需修改 SkillManager、FormController、任何技能 SO
|
||||
EffectiveSkillParams 快照模式确保每帧读取的参数是当前有效状态
|
||||
```
|
||||
|
||||
### 关卡能力门禁 (virtual EvaluateAccess)
|
||||
```csharp
|
||||
// AbilityGate 基类
|
||||
protected virtual bool EvaluateAccess()
|
||||
=> _playerStats != null && _playerStats.HasAbility(_requiredAbility);
|
||||
|
||||
// 子类可追加条件(如同时需要持有道具)
|
||||
public class ItemAndAbilityGate : AbilityGate
|
||||
{
|
||||
protected override bool EvaluateAccess()
|
||||
=> base.EvaluateAccess() && _inventory.HasItem(_requiredItem);
|
||||
}
|
||||
```
|
||||
|
||||
### 存档版本迁移 (fall-through chain)
|
||||
新增版本只需在迁移链末尾添加 `case "3.0": MigrateV21To30(root); break`,旧版本自动串联补全所有中间迁移,无需为每个旧版本写专属升级路径。
|
||||
|
||||
---
|
||||
|
||||
## 9. 编辑器友好性
|
||||
|
||||
| 特性 | 实现 | 文件 |
|
||||
|------|------|------|
|
||||
| Inspector `[Header]`/`[Tooltip]`/`[Min]` | 全框架一致使用 | 所有 MB |
|
||||
| `[DefaultExecutionOrder]` 精确控制初始化序 | -2000 / -800 / -100 | Registrar/Pool/Manager |
|
||||
| `TransitionTo` Editor-only 合法转换白名单 | `ValidTransitions` | PlayerController |
|
||||
| 按键重绑定面板 | 完整排他锁 + 持久化封装 | RebindPanel |
|
||||
| `AnimationEventConfigSO` 数据驱动事件注入 | `SortedEvents` 时间线排序 | AnimationEventBinder |
|
||||
| `PoolConfig[]` Inspector 可视化预热配置 | `AddressKey/InitialCount/MaxCount` | GlobalObjectPool |
|
||||
| `WeakPoint[]` 弱点可视化配置 | `hurtBox + visualIndicator` | WeakPointSystem |
|
||||
|
||||
---
|
||||
|
||||
## 10. v8 修复清单
|
||||
|
||||
| ID | 严重度 | 模块 | 问题 | 状态 |
|
||||
|----|--------|------|------|------|
|
||||
| v8-P-1 | 中 | `BreadcrumbTracker` | `FindWithTag` 违反框架事件频道约定 | ✅ 已修复 |
|
||||
| v8-P-2 | 低 | `GlobalObjectPool` | `OnDestroy` 未释放 Addressables 预制件引用 | ✅ 已修复 |
|
||||
| v8-P-3 | 低 | `SettingsManager` | 音量设置每次写磁盘(调用规范问题) | 📝 文档记录 |
|
||||
| v8-A-1 | 低 | `AccessibilityManager` | static 单例与 ServiceLocator 模式不一致 | 📝 文档记录 |
|
||||
| v8-DC-1 | 低 | `CrumblePlatform` | `_isOneShot` 状态未写入 WorldStateRegistry | 📝 文档记录 |
|
||||
| v8-DC-2 | 低 | `MovingPlatform` | `_passengers` 潜在空引用(乘客被销毁) | 📝 文档记录 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 总结与后续建议
|
||||
|
||||
### 优势
|
||||
1. **架构纯净** — 28 个程序集单向依赖,所有跨模块通信通过 SO 频道或 ServiceLocator 接口
|
||||
2. **生产级容错** — CrashReporter + EmergencySaveService 双保险,SaveMigrator 版本链,NullAudioService 兜底
|
||||
3. **性能意识** — SkillManager 零分配遍历、GlobalObjectPool LRU 双集合、EnemyQuotaManager swap-and-pop
|
||||
4. **可扩展设计** — SkillModifierRegistry OCP、AbilityGate virtual、SaveMigrator fall-through
|
||||
5. **编辑器优先** — 全面 Inspector 注解、执行序精确控制、动画事件 SO 驱动
|
||||
|
||||
### 优先改进项
|
||||
1. **v8-P-1**(已修复)BreadcrumbTracker 事件化 — 消除框架内唯一 FindWithTag
|
||||
2. **v8-P-2**(已修复)GlobalObjectPool OnDestroy 清理 — 防止编辑器内存抖动
|
||||
3. **v8-A-1**(建议)AccessibilityManager → IAccessibilityService + ServiceLocator
|
||||
4. **v8-DC-1**(建议)CrumblePlatform 状态持久化 — 修复世界状态一致性
|
||||
5. **v8-P-3**(建议)SettingsManager 滑动条调用规范 — UI 层延迟 Save
|
||||
|
||||
### 得分趋势
|
||||
```
|
||||
v5: 8.73 → v6: 8.73 → v7: 9.00 → v8: 8.99(修复后预计 9.05)
|
||||
```
|
||||
|
||||
框架整体已达到中等商业游戏代码质量标准,核心架构设计合理,生产安全性优秀。主要待提升方向为:可测试性(单元测试接入点较少)、AccessibilityManager 服务化、部分边界状态持久化补全。
|
||||
|
||||
---
|
||||
|
||||
*v8 评审覆盖 Assets/Scripts/ 下全部 270+ 文件,其中 v8 新增模块 ~80 个。评分基于代码逐行审阅,参照 Unity 官方最佳实践、《Game Programming Patterns》及商业 2D Action RPG(Hollow Knight、Dead Cells、Hades)架构设计标准。*
|
||||
Reference in New Issue
Block a user