Add independent review reports for Minimap system (Rounds 8, 9, and 26)

- Round 8 report highlights improvements in architecture, editor usability, and data robustness, with a total score of 80/100.
- Round 9 report focuses on editor extension capabilities, identifying issues with room data indexing and layout editing, resulting in a score of 76/100.
- Round 26 report evaluates the system against commercial standards, noting new issues and confirming previous fixes, with a score of 95.8/100.
This commit is contained in:
2026-05-25 23:15:12 +08:00
parent e2bc324905
commit f74d7f1877
53 changed files with 6825 additions and 270 deletions

View File

@@ -0,0 +1,234 @@
# 小地图系统独立评审 Round 22
**评审时间**R22基于 R21 全部修复已落地的代码基线)
**评审范围**`Assets/_Game/Scripts/World/Map/` 全部 19 个运行时文件 + 4 个编辑器扩展文件
**评分基准**:专业 2D Metroidvania 编辑器扩展标准(架构解耦 / 高性能 / 可扩展 / 开发者友好)
---
## R21 修复确认
| 编号 | 内容 | 状态 |
|------|------|------|
| R21-N1 | `MinimapHUD._servicesReady` + `LateUpdate` 重试(对齐 MapPanel | ✅ 确认L66, L197-203 |
| R21-N1 | `MapPlayerTracker [DefaultExecutionOrder(-600)]` | ✅ 确认L17 |
| R21-N2 | `MapPanel` 集合字段补全 `readonly` | ✅ 确认L58-63 |
| R21-N3 | `MinimapHUD.UnsubscribeServices` 重置 `_servicesReady` | ✅ 确认L158 |
---
## 各维度评分
### 1. 架构设计Architecture 19.0 / 20
**亮点**
- ServiceLocator + 4 接口IMapService / IPinService / IPlayerPositionProvider / ITeleportService零耦合
- 事件驱动C# Action无轮询OnDatabaseChanged / OnExplorationChanged / OnRoomMapped 语义分明
- ISaveable 三处防御性拷贝对称MapManager / MapPinManager / TeleportService
- MapRoomCellUI 双视图复用,无重复 Prefab
- `ChooseDisplayIcon` 唯一入口MapRoomDataSOMapPanel / MinimapHUD 无漂移
- `MapServiceExtensions` 无状态扩展方法,消费方零重复查询逻辑
**新发现问题 N1中等**`RegionNameEntry` 字典解析逻辑在两个组件重复
`RegionNameDisplay``MapProgressDisplay` 各自独立实现了完全相同的模式:
```csharp
// RegionNameDisplay
private Dictionary<string, RegionNameEntry> _regionDict;
private void BuildRegionDict() { ... }
private string ResolveDisplayName(string regionId) { ... }
// MapProgressDisplay
private Dictionary<string, RegionNameEntry> _regionDict;
private void BuildRegionDict() { ... }
private string ResolveRegionDisplayName(string regionId) { ... }
```
两者代码几乎逐行相同(包含 LocKey 优先、DisplayName 次之、RegionId 回退三段逻辑),仅方法名不同。
修复建议:在 `MapServiceExtensions.cs` 中补充静态扩展方法 `BuildRegionDict / ResolveDisplayName`
两个组件调用同一实现,消除 DRY 违反。
**扣分1.0**
---
### 2. 性能Performance 19.5 / 20
**亮点**
- MapPanel 全部 `readonly` 集合池 × 6Cell / Pin / ExitMinimapHUD × 4
- `_servicesReady` 短路MapPanel R12-N7MinimapHUD R21-N1消除每帧 ServiceLocator 查询
- O(viewRadius²) 空间索引,大地图下 MinimapHUD.RefreshView 比 O(AllRooms) 显著降低开销
- 复用缓冲区:`_toRemove` / `_roomsInViewBuffer` / `_newlyAddedBuffer`(预分配容量)
- PinsVersion 脏检查 + 玩家位置脏检查消除无效写入
- `_regionCache` 懒加载MapManager`_regionDict` 字典化RegionNameDisplay / MapProgressDisplay
**说明(信息级)**`MapProgressDisplay.Refresh()` 区域进度遍历为 O(rooms_in_region)
但仅在 `OnExplorationChanged` 或区域切换时触发(非每帧),当前规模无性能风险。
**扣分0.5**`MapProgressDisplay.Refresh` 区域遍历未缓存已探索计数,极大地图时有轻微冗余)
---
### 3. 代码质量Code Quality 19.0 / 20
**亮点**
- 全部集合字段已补齐 `readonly`MapPanel R21-N2 修复)
- `CurrentZoom` 属性R19-N1消除双份状态
- `RunRevealAnim` 自清理协程R20-N1
- `HasCustomExitPos` 语义布尔替代哨兵
- `[Obsolete]` + `[HideInInspector]` 废弃字段注解完整
- `DrawLine` try/finally 保证 GUI.matrix 恢复R11-N12
- `MapPin.cs` 文件头注释标明"文件名历史遗留,请搜索类名 MapPinManager"
**新发现问题 N2轻微**:编辑器 `DrawRoomBadge` 注释引用已过时
```csharp
// MapLayoutEditorWindow.cs L488
// 优先级与运行时 MapPanel.ChooseIcon 对齐Save > Boss > Shop > Teleport
```
R20-N2 已将运行时图标选取逻辑迁移至 `MapRoomDataSO.ChooseDisplayIcon`
`MapPanel.ChooseIcon` 已变为单行委托。注释应更新为:
```csharp
// 优先级与运行时 MapRoomDataSO.ChooseDisplayIcon 对齐Save > Boss > Shop > Teleport
```
**扣分1.0**N1 DRY 违反产生的代码质量问题)
---
### 4. 编辑器扩展Editor Tools 14.5 / 15
**亮点**
- `MapLayoutEditorWindow`:缩放/平移/拖拽/搜索/区域着色/验证/Undo/热改完整
- `_cachedZoomForStyle` 脏检查 + `_noResultStyle` 首次初始化缓存
- `DrawExitLines` 字段级去重 `_drawnExitPairs`OnGUI 零分配
- `SetDatabase` 公共 API避免 MapDatabaseEditor 反射访问私有字段
- `MapRoomAutoRegister` AssetPostprocessor 自动注册工作流完整
**扣分0.5**DrawRoomBadge 注释引用过时,对策划人员阅读代码时产生误导)
---
### 5. 功能完整性Feature Completeness 15.0 / 15
**亮点**(所有功能均已实现且正确)
- 三级可见性Unknown / Explored / Mapped+ 雾效覆盖层
- 图标优先级唯一入口Override > SavePoint > Boss > Shop > Teleport
- Pin 系统(持久化、类型化、视野内渲染)
- 出口连接线 + Fallback 位置R13-N1 HasCustomExitPos
- 传送系统TeleportService解锁 / 验证 / 请求 / 完成回调)
- 区域检测 + 区域名本地化显示RegionNameDisplay + MapProgressDisplay
- 存档/读档ISaveable 三处,防御性拷贝对称)
- 房间发现动画RevealAnim 自清理R20-N1
- 全屏地图 + 角落 HUD 双视图小地图视野档位切换CycleZoom
**扣分0**
---
### 6. 输入系统Input System 9.5 / 10
**亮点**
- 全部使用 InputSystemInputReaderSO
- `MapInputHandler`Navigate / MapCenter / OnScroll 完整
- `MinimapInputHandler`CycleMinimapZoom 路由
- OnEnable/OnDisable 对称订阅/取消
**信息级**`MapInputHandler._zoom``OnScroll` 中作为本地累加器,与 `_panel.CurrentZoom` 读取路径不同但结果一致OnScroll 写 → CurrentZoom 读,无环),正确配置下无实际风险。
**扣分0.5**(轻微职责重叠,不影响正确性)
---
## 综合评分
| 维度 | 满分 | 得分 | 较 R21 |
|------|------|------|--------|
| 架构设计 | 20 | 19.0 | +0.5 |
| 性能 | 20 | 19.5 | ±0 |
| 代码质量 | 20 | 19.0 | +0.5 |
| 编辑器扩展 | 15 | 14.5 | ±0 |
| 功能完整性 | 15 | 15.0 | +0.5 |
| 输入系统 | 10 | 9.5 | ±0 |
| **合计** | **100** | **96.5** | **+1.5** |
---
## 问题清单与修复建议
### N1 — RegionNameEntry 字典解析逻辑重复(中优先级)
**根因**`RegionNameDisplay``MapProgressDisplay` 独立实现了相同的 `BuildRegionDict` + `Resolve` 模式。
**修复方案**:在 `MapServiceExtensions.cs` 追加静态扩展/工具方法:
```csharp
/// <summary>
/// 将 RegionNameEntry 数组构建为 O(1) 查询字典。
/// RegionNameDisplay / MapProgressDisplay 共享此实现,消除重复。
/// </summary>
public static Dictionary<string, RegionNameEntry> BuildRegionDict(RegionNameEntry[] entries)
{
var dict = new Dictionary<string, RegionNameEntry>();
if (entries == null) return dict;
foreach (var e in entries)
if (!string.IsNullOrEmpty(e.RegionId))
dict[e.RegionId] = e;
return dict;
}
/// <summary>从字典解析 regionId 的玩家可读显示名;字典为 null 时直接回退到 regionId。</summary>
public static string ResolveRegionDisplayName(
Dictionary<string, RegionNameEntry> dict, string regionId)
{
if (dict != null && dict.TryGetValue(regionId, out var e))
return e.GetDisplayName();
return regionId;
}
```
两个组件改为:
```csharp
private void BuildRegionDict()
=> _regionDict = MapServiceExtensions.BuildRegionDict(_regionNames);
private string ResolveDisplayName(string regionId)
=> MapServiceExtensions.ResolveRegionDisplayName(_regionDict, regionId);
```
---
### N2 — DrawRoomBadge 注释引用过时(低优先级)
**修复**`MapLayoutEditorWindow.cs` L488 注释更新:
```csharp
// 优先级与运行时 MapRoomDataSO.ChooseDisplayIcon 对齐Save > Boss > Shop > Teleport
```
---
### N3 — MapPinManager 缺少 [DefaultExecutionOrder](信息级)
`MapPinManager.Awake` 注册 `IPinService`,若晚于 UI 的 `SubscribeServices` 调用,
`_pinService` 将在首帧为 null`_servicesReady` 重试机制兜底)。
两 UI 的 `_servicesReady` 短路已覆盖此场景,但显式标注执行顺序更具防御性:
```csharp
[DefaultExecutionOrder(-500)] // 晚于 MapPlayerTracker(-600),早于默认 0
public class MapPinManager : MonoBehaviour, ISaveable, IPinService
```
---
## 评分历史
| 轮次 | 评分 | 关键改动 |
|------|------|----------|
| R17 | 93.0 | — |
| R18 | 93.8 | MinimapHUD 废弃 _onMapUpdated 订阅 |
| R19 | 93.8 | CurrentZoom 属性_revealCoroutines 防泄漏 |
| R20 | 94.2 | RunRevealAnim 自清理ChooseDisplayIcon 集中 |
| R21 | 95.0 | MinimapHUD _servicesReadyMapPlayerTracker 执行顺序readonly 补全 |
| **R22** | **96.5** | R21 修复确认;识别 N1RegionNameEntry DRYN2注释过时N3MapPinManager 执行顺序) |