Files
zeling_v2/Docs/Review/Minimap_Review_Round12_Independent.md
Joywayer f74d7f1877 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.
2026-05-25 23:15:12 +08:00

12 KiB
Raw Permalink Blame History

Minimap 独立评估报告 — Round 12

评估基线: R11 全部 12 项修复N1N12已实现并验证InputSystem 迁移已完成
前轮得分: Round 11 — 85.6/100 (B+,含 12 项已知 findings)
本轮目标: 基于修复后的最新代码重新全面审查,发现新遗留问题并给出综合评分


评分总览

维度 权重 得分 上轮
架构与解耦 15% 9.0 8.5
数据设计 15% 8.0 8.0
运行时性能 20% 8.8 8.5
编辑器工具 15% 8.5 8.5
游戏功能完整性 15% 7.5 7.5
代码质量 10% 8.5 8.5
可扩展性 10% 8.0 7.5
加权总分 100% 86.2 / 100 85.6

评级B+R11 修复带来了小幅提升,当前剩余问题均为 P2/P3无 P1 阻断性缺陷)


维度详评

1. 架构与解耦 (9.0/10) ↑

优点:

  • Interface-based IoCIMapService / IPlayerPositionProvider / IPinService,运行时零具体类耦合
  • ServiceLocator 延迟获取,支持启动顺序不确定场景
  • 事件语义分离:OnDatabaseChanged结构重建vs OnExplorationChanged(轻量刷新)
  • R11-N1 修复后 MinimapHUD 双服务独立订阅守卫,避免重复注册
  • MapServiceExtensions 扩展方法,对外暴露高层 API 而不污染接口定义
  • MapGridConstants 统一共享常量,避免魔法数字分散

遗留问题:

  • N7 (P3) MapPanel.LateUpdate 每帧调用 SubscribeServices() 直到三个服务都获取完毕,之后仍无法跳出该分支(缺少 _servicesReady 标志)。对热路径略有冗余
  • N8 (P3) MapPanel 同时订阅 _onMapUpdated EventChannel 和 IMapService.OnExplorationChanged,两者功能部分重叠(单个房间发现时两者都会触发,导致 OnExplorationChanged → RefreshAllCellsOnMapUpdated → cell.SetVisibility 连续对同一格子执行两次刷新)

2. 数据设计 (8.0/10) →

优点:

  • 三层可见度Unknown / Explored / Mapped标准 Metroidvania 分级
  • MapDatabaseSO 双索引:string→room (O(1)) + cell→roomId 空间索引 (O(1))
  • RoomExitData 字段完整ExitGridPos / Direction / TransitionType
  • R11-N2/N11 修复了 OnValidate 延迟调用去重 + RoomId 自动 Trim + 特殊字符校验

遗留问题:

  • N5 (P2) RoomExitData.ExitGridPosVector2Int.zero 作"未配置"哨兵,而 (0,0) 同时是合法格子坐标,语义二义性。编辑器中未配置出口位置时 DrawExitLines 回退到目标房间中心,但 (0,0 房间角落坐标) 与"未设置"无法区分,可能产生误判
    建议:增加 bool HasCustomExitPos 字段,或改用 Vector2Int? nullable明确区分
  • N9 (P3) MapRoomDataSO 用三个独立 bool 字段(IsBossRoom / IsSavePoint / IsShop)描述房间类型,每新增一类(如商人房、挑战房)需要改动 SO 类定义,扩展成本高
    建议:改为 [Flags] enum RoomType 或支持多值选择的枚举,单字段表达复合属性

3. 运行时性能 (8.8/10) ↑

优点:

  • R11-N5 MinimapHUD 新增 Stack<MapRoomCellUI> _cellPoolClearAllCells 回收、RefreshView 复用,彻底消除频繁 Instantiate/Destroy
  • R11-N6 MapManager.GetRoomsByRegion 引入 _regionCacheO(N) 全扫变 O(1)NotifyDatabaseChanged 时清缓存
  • O(1) 空间索引用于玩家房间检测(GetRoomIdAtCell
  • PinsVersion 脏检查避免无效 RenderPins
  • MapInputHandler 缓存 _navInputUpdate 零轮询
  • _roomsInViewBuffer / _newlyAddedBuffer / _toRemove 避免 MinimapHUD 刷新时分配

遗留问题:

  • N1 (P2) MapPanel.RebuildAllOnDestroy 对格子调用 Destroy(cell.gameObject)ClearExits 对出口连接线调用 Destroy(img.gameObject)。与 MinimapHUD_cellPool 模式不对称RebuildAll 在地图数据库变更时被调用,会产生 GC 脉冲
    建议:为 MapPanel 补充 Stack<MapRoomCellUI> _cellPoolStack<Image> _exitPoolClearExits/RebuildAll 回收而非销毁
  • N6 (P3) RegionNameDisplay.ResolveDisplayName_regionNames 数组做 foreach 线性搜索O(N))。每次进入新区域触发,通常 N 不超过 20 影响不大,但可在 Awake 预建 Dictionary<string, RegionNameEntry> 一劳永逸
  • N7 (P3) 见架构章节LateUpdate 的 SubscribeServices 每帧空转

4. 编辑器工具 (8.5/10) →

优点:

  • MapLayoutEditorWindow:全功能格子预览(缩放/平移/搜索/图例/Play Mode 玩家点)
  • R11-N7 OnProjectChange() 清缓存 + Repaint资产刷新后立即同步
  • MapRoomDataEditorScene View 双角控制点拖拽 + Undo 支持
  • MapRoomAutoRegister:新建房间 SO 自动注册到默认 Database不再需要策划手动拖入
  • MapDatabaseEditor:一键 ValidateAll带 Ping 导航的房间列表

遗留问题:

  • N2 (P2) MapLayoutEditorWindow.DrawExitLines 遍历每个房间的所有出口并各画一条线A→B 和 B→A 均被绘制,导致相同连线段出现双重叠画。虽然 R11-N10 修复了端点准确性,但未消除重复渲染
    建议:用 HashSet<(string,string)> 对每条连接对去重(规范化 key小 ID 在前),仅绘制一条
  • N4 (P2) MapRoomAutoRegister 未处理 deletedAssets:删除一个 MapRoomDataSO 后,其 null 引用仍留在 MapDatabaseSO.AllRooms 数组中,累积脏数据,需手动 ValidateAll 才能发现
    建议:在 OnPostprocessAllAssets 中遍历 deletedAssets,从所有 Database 清除匹配路径的 null 条目
  • MapLayoutEditorWindow 不支持在窗口内直接编辑出口数据ExitGridPos / Direction / TransitionType仍需切换到房间 Inspector在大型地图编辑时来回切换效率较低

5. 游戏功能完整性 (7.5/10) →

已实现的核心功能(与行业标准对齐):

  • 三层可见度(未知 / 已探索 / 已标记)
  • 玩家位置图标(房间内归一化插值定位)
  • 自定义 Pin 标记(多类型 Sprite 可配)
  • 区域名称渐显动画 + 本地化支持
  • 存档/读档整合MapSaveData
  • 当前房间高亮
  • 面板打开时自动居中到当前房间
  • 全屏地图滚动/缩放 + 出口连接线
  • 角落 HUD 小地图(视角范围内增量渲染)

缺口:

  • 小地图MinimapHUD不支持玩家控制的缩放仅有固定的 _viewRadiusCells
  • 无探索进度百分比显示(全图 / 当前区域)
  • OnRoomMappedAnim 虚方法预留了但方法体为空 {} ——新发现房间时无动画过渡效果(如淡入 reveal
  • 未知房间仅为纯黑色,无雾效(纹理或渐变)处理,视觉层次略显单调
  • IPinService.CreatePin 只接受 RoomId + normalizedPos,缺少基于世界坐标自动解析的便捷 API
  • 无传送点/快速旅行 hook哪怕只是空接口预留

6. 代码质量 (8.5/10) →

优点:

  • XML 文档完整,关键方法均有 <summary>
  • 严格遵循 no-game-references 规则
  • R11-N11 ValidateAll 特殊字符检查、R11-N9 _worldOriginOffset 均有 Tooltip 说明
  • [DefaultExecutionOrder(-700)] 确保 MapManager 优先注册到 ServiceLocator
  • CompositeDisposable 模式统一管理短期订阅,避免 OnDisable 时泄漏

遗留问题:

  • N3 (P2) MapPanel._pinSpritesMinimapHUD._pinSprites 是各自独立的 [SerializeField] PinSpriteEntry[],配置分散在两个 Prefab 中。新增 PinType 必须同时修改两处 Inspector 配置,容易漏改
    建议:提取 MapPinConfigSO ScriptableObject单一资产两个 UI 组件各持 [SerializeField] MapPinConfigSO _pinConfig 引用
  • N10 (P3) MapPin.cs 文件包含 MapPinManager注释注明是历史命名遗留文件名与主类名不匹配IDE 导航和资产搜索可能混淆
    建议:重命名文件为 MapPinManager.cs 或拆分为 MapPin.cs(数据类)+ MapPinManager.cs(管理类)

7. 可扩展性 (8.0/10) ↑

优点:

  • Interface-based 全面,可无缝替换 MapManager / MapPlayerTracker / MapPinManager 实现
  • OnRoomMappedAnim protected virtual 支持 MapPanel 子类重写
  • MapServiceExtensions 扩展方法模式,新功能无需修改接口定义
  • RegionNameEntry 本地化支持LocKey 优先、DisplayName 回退

遗留问题:

  • N9 (P3) 见数据设计章节,房间类型用 3 个 bool 字段,扩展新类型需改动 SO 类定义和 ChooseIcon 方法
  • N3 (P2) PinSpriteEntry 配置未集中化,新增 PinType 涉及多处修改

R12 Findings 汇总

ID 优先级 分类 描述
N1 P2 性能 MapPanel ClearExits / RebuildAll / OnDestroy 使用 Destroy,应补充格子/出口对象池
N2 P2 编辑器 DrawExitLines 双向重复绘制需对连接对去重HashSet 规范化 key
N3 P2 代码质量 PinSpriteEntry[] 在 MapPanel 和 MinimapHUD 中各配一份,建议抽取 MapPinConfigSO
N4 P2 编辑器 MapRoomAutoRegister 未处理 deletedAssets,删除的房间 null 引用残留 Database
N5 P2 数据设计 ExitGridPos == Vector2Int.zero 哨兵与合法坐标 (0,0) 二义,建议 HasCustomExitPos bool
N6 P3 性能 RegionNameDisplay.ResolveDisplayName O(N) 线性查找,建议 Awake 预建 Dictionary
N7 P3 架构 MapPanel.LateUpdate_servicesReady 标志,服务获取后仍每帧空跑 SubscribeServices
N8 P3 架构 MapPanel 对单房间探索变更双重刷新EventChannel + OnExplorationChanged 各触发一次)
N9 P3 可扩展性 IsBossRoom / IsSavePoint / IsShop 三 bool 字段,不及 [Flags] RoomType 枚举灵活
N10 P3 代码质量 MapPin.cs 文件名与主类 MapPinManager 不匹配,建议重命名文件

P1 阻断性缺陷0
P2 重要缺陷5
P3 次要缺陷5


R11 vs R12 对比

项目 R11 评估时 R12 评估时
P1 缺陷数 4 0
P2 缺陷数 5 5
P3 缺陷数 3 5
MinimapHUD 格子池 Stack<MapRoomCellUI>
MapPanel 格子池 仍使用 Destroy
输入系统 旧版 Input InputSystem (InputReaderSO)
出口线端点精度 目标中心 ExitGridPos + 反向查找
编辑器缓存刷新 缺 OnProjectChange OnProjectChange() 实现
RoomId 验证 基础 Trim + 特殊字符检查

改进建议优先级

立即执行P2

  1. [N1]MapPanel 补充格子与出口对象池,消除 RebuildAll GC 峰值
  2. [N2] MapLayoutEditorWindow.DrawExitLinesHashSet<(string,string)> 去重,消除重复线段
  3. [N3] 提取 MapPinConfigSO,统一 Pin 图标配置入口
  4. [N4] MapRoomAutoRegister 处理 deletedAssets,自动清除 Database 中的 null 引用
  5. [N5] RoomExitData 增加 HasCustomExitPos bool 字段,消除 zero 哨兵歧义

计划执行P3

  1. [N6] RegionNameDisplay.Awake 预建 Dictionary<string, RegionNameEntry>
  2. [N7] MapPanel 增加 _servicesReady 标志跳过已就绪后的 LateUpdate 查询
  3. [N8] 审查 MapPanel 双重刷新路径,决策是否移除 _onMapUpdated EventChannel 依赖
  4. [N9]IsBossRoom / IsSavePoint / IsShop 重构为 [Flags] RoomType 枚举
  5. [N10] 重命名 MapPin.csMapPinManager.cs(或拆分数据/管理两个文件)

综合评价

经过 R11 的 12 项修复,系统已消除所有 P1 阻断性缺陷,架构层面趋于稳定。当前版本在 InputSystem 集成、对象池、编辑器工具完整性、服务解耦等核心维度均达到商业标准。

剩余 R12 的 10 项 findings 均为 P2/P3 改善项不影响功能正确性主要涉及配置中心化N3/N9、编辑器视觉质量N2、运行时 GC 一致性N1、数据语义清晰度N5

最终评分86.2/100B+

达到可发布的商业 Metroidvania 小地图实现标准,剩余工作为进一步打磨的优化项,非阻断项。