Files
zeling_v2/Docs/Review/Minimap_Review_Round8_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

9.9 KiB
Raw Blame History

小地图独立审查报告 — Round 8

审查日期:第 8 轮独立审查前序Round 1~7Round 7 评分 82/100 + 修复后预估 ~88 对标基准:成熟商业 Metroidvania含空洞骑士级别的探索 / 标注 / 区域切换 / 编辑器工作流) 范围Assets/_Game/Scripts/World/Map/** + 相关 Save / Editor / ServiceLocator 审查方式:完全独立重读全部 17 个文件,不预设结论;对 Round 7 修复项做交叉验证


一、综合评分(八维)

维度 评分 较 Round 7 (修复后)
架构与解耦 (15%) 14 / 15 ↑(共享空间索引 + DB 事件接口齐备)
编辑器扩展易用性 (15%) 13 / 15 ↑(双窗口 + Validate 已成熟)
数据/存档健壮性 (10%) 8 / 10 LastRegionId、CreatePin 校验落地)
运行时性能 (15%) 14 / 15 空间索引复用、PinsVersion 脏检查)
可扩展性 (10%) 7 / 10 =RegionSO/进度 UI 仍缺)
视觉与表现层 (10%) 8 / 10 =(区域名提示已就位,但 Pin 限于全屏)
输入与平台 (10%) 6 / 10 =Input System 迁移仍未启动)
文档与测试 (15%) 10 / 15 ↑(七轮报告体系完善,仍缺 PlayMode 集成测试)
合计 80 / 100

说明本轮在更高标尺下重新刻度。Round 7 的"修复后预估 88"是基于自身基线Round 8 引入 NotifyDatabaseChanged 入口空挂 等结构性新发现,整体分数回落到 80。修复完 P0/P1 后预计 8891。


二、Round 7 修复交叉验证

Round 7 编号 内容 Round 8 验证
N1 MapPanel 在 LateUpdate 中 RenderPins + 监听 OnDatabaseChanged MapPanel.cs:124/136 已落地
N2 IMapService 增加 OnDatabaseChanged 事件 接口与实现齐备
N3 空间索引下沉到 MapDatabaseSO GetRoomIdAtCell + Invalidate 已就位HUD/Tracker 均使用共享索引
N4 CreatePin 校验 roomId / clamp 归一化 MapPin.cs:60~94
N5 SaveData.LastRegionId + OnLoad 恢复 MapManager.cs:60/67
N6 MinimapHUD step③ 跳过新增格 _newlyAddedBuffer 去重
N7 MapInputHandler 命名空间冲突 UnityEngine.Input.GetAxisRaw
N8 _worldUnitsPerCell [Min(0.01f)] MapPlayerTracker.cs

结论Round 7 所有修复均稳定在仓库中,未发生回归。


三、本轮新发现问题

P0必修

R8-N1IMapService.NotifyDatabaseChanged() 全仓零调用 — API 空挂

  • 位置Assets/_Game/Scripts/World/Map/MapManager.cs:127,全文检索 NotifyDatabaseChanged 仅出现于"声明"与"实现"两处。
  • 后果Round 7 N2 修复在接口层补齐了 DB 热更新通知通道,但调用端缺失
    • 编辑器中通过 Inspector 修改某个 MapRoomDataSOGridPosition、新增/删除 MapDatabaseSO.AllRooms 数组元素,运行时不会触发任何 UI 重建。
    • MapPanel/MinimapHUD 继续渲染过期布局,直到玩家进入新房间或重开面板。
  • 修复:在 MapDatabaseSO.OnValidate 中(#if UNITY_EDITOR && Application.isPlaying)回调 ServiceLocator.GetOrDefault<IMapService>()?.NotifyDatabaseChanged();同时让 MapRoomDataSO.OnValidate 也对所属 Database 反向通知(或在数据库一侧做差量比较)。可选:暴露给编辑器窗口的 "Apply" 按钮显式调用。

R8-N2MinimapHUD 完全不渲染玩家 Pin

  • 位置MinimapHUD.cs 未引用 IPinService,仅 MapPanel 渲染图钉。
  • 后果:玩家在全屏地图上标注的图钉无法在角落小地图上可见,违反主流 Metroidvania 体验HUD 应给出最近的目标提示,避免反复打开大地图)。
  • 修复:在 MinimapHUD 中订阅 IPinService.PinsVersion,在可视范围内挑选最近的 N 个 Pin屏幕外用边缘箭头表示。最小化实现仅渲染当前视野单元格范围内的 Pin。

P1建议修

R8-N3MapManager.Awake 重复实例 Destroy 后 OnEnable 仍会执行

  • 位置MapManager.cs:36-46
  • 分析Destroy(gameObject) 在 Awake 中调用,但 Unity 生命周期中 Awake → OnEnable 同帧仍会触发OnEnable 会订阅事件 + 注册 ISaveable本帧末才被销毁后 OnDisable 取消订阅。期间若发生 OnSave极少但存在会写入"将被销毁"的实例。
  • 修复:增加 private bool _isDuplicate; 在 Awake 中标记OnEnable/OnDisable 提前 return。

R8-N4MapPlayerTracker 重复实例只 return 不 Destroy

  • 位置MapPlayerTracker.Awake(与 MapManager 模式不一致)。
  • 后果:场景中若意外存在两个 MapPlayerTracker第二个不会被销毁仍消耗 LateUpdate虽然不注册服务_database 依然在 Start 中赋值)。
  • 修复:与 MapManager 对齐 — 检测到已注册时 Destroy(gameObject); return;

R8-N5服务获取没有"懒加载/重试"机制

  • 位置MapPanel.OnEnable(行 79~80一次性获取 _playerProvider / _pinService / _mapSvc
  • 后果:若 MapPanel 比 MapPinManager / MapManager 早 OnEnable场景启动顺序未严格保证时后续不会再尝试。用户必须关闭再打开面板。
  • 修复:在 LateUpdate 起始位置增加 lazy 解析:
    if (_pinService == null) _pinService = ServiceLocator.GetOrDefault<IPinService>();
    
    或采用"DefaultExecutionOrder + GameServiceRegistrar"统一保证启动顺序(已部分落实,但 Panel 是 UI 子物体,启动顺序更脆弱)。

R8-N6MapManager.OnLoad 不广播 EVT_MapUpdated / EVT_RegionChanged

  • 位置MapManager.OnLoad(行 63~69
  • 后果:若读档时 MapPanel 已打开(例如从设置菜单读档),探索状态、区域名提示不会即时刷新。RefreshAllCells 仅在 OnEnable 触发。
  • 修复:在 OnLoad 末尾通过 IMapService.OnDatabaseChanged 通知 UI 全量重建(语义略宽,但成本可接受);或为 IMapService 增加 OnSaveLoaded 专用事件。

P2可选改进

R8-N7MapPin.OnSave 直接共享 _pins 引用,与 MapManager 拷贝模式不一致

  • 位置MapPin.cs:98
  • 风险:若未来 SaveSystem 引入异步序列化或重试,运行时 CreatePin/RemovePin 修改集合可能与序列化冲突。
  • 修复data.Map.Pins = new List<MapPin>(_pins);(与 MapManager 的 new HashSet<> 风格一致)。

R8-N8MapManager.GetExplorationProgress 缓存 _totalRoomCount 但无 OnDatabaseChanged 失效钩子

  • 位置MapManager.NotifyDatabaseChanged() 内已 reset _totalRoomCount = -1,但前提是有人调用 NotifyDatabaseChanged见 R8-N1。需要联动确认。
  • 修复:随 R8-N1 一并解决。

R8-N9MapPin Save 字段命名考虑前向兼容

  • MapPin 是同时充当运行时模型 + 存档结构[Serializable] class。若未来字段重构(例如增加 IsCompleted 标志),旧存档反序列化可能在 BinaryFormatter 下损坏。
  • 建议:要么用 JSON 存档(已部分使用?需确认 SaveSystem 序列化器),要么显式提供 [OnDeserialized] migrations。

R8-N10MapInputHandler 仍使用 UnityEngine.Input.GetAxisRaw(旧 Input Manager

  • 与项目其他模块(推测使用新 Input System不一致。
  • 建议:迁移到 IInputService项目内已有的抽象。Round 7 已标记,本轮再次确认为待办。

P3长期/暂可不修)

  • R8-D1RegionSO 配置化区域颜色、地图碎片关联、Boss 标记)仍未启动,目前 RegionId 仅是字符串。
  • R8-D2:探索进度 UIGetExplorationProgress API 已存在)未在面板上呈现。
  • R8-D3:手柄缩放 / 平移热键尚未对齐 PC + Gamepad 双输入。
  • R8-D4PlayMode 集成测试(房间发现 → 存档 → 读档 → UI 同步)尚未编写。
  • R8-D5Docs/Design/MinimapDesignSpec.md 设计文档(约束格子语义、颜色、图层)仍未补齐。

四、设计亮点(继续保留)

  1. 架构ServiceLocator + ScriptableObject + EventChannel 三件套清晰分层;IMapService / IPinService / IPlayerPositionProvider 抽象到位。
  2. 共享空间索引MapDatabaseSO.GetRoomIdAtCell 统一了 HUD 与 Tracker 的查询路径,避免双份索引内存与同步开销。
  3. 编辑器扩展MapLayoutEditorWindow(俯视图拖拽)+ MapRoomDataEditorScene 句柄两点确定矩形)+ MapDatabaseEditor(一键 Validate形成完整作业流。
  4. 存档健壮性MapManager 复制 HashSet 防引用泄漏LastRegionId 恢复消除"读档首次进房误触发区域 Toast"。
  5. 性能保护CellPool、PinsVersion 脏检查、空间索引懒构建、Mathf.Clamp01 防御。

五、推荐修复优先级与预期得分

优先级 项目 预计提升
P0 R8-N1 NotifyDatabaseChanged 接入 + R8-N2 MinimapHUD Pin 渲染 +5
P1 R8-N3 / N4单例对齐+ N5lazy 解析)+ N6OnLoad 广播) +3
P2 R8-N7 / N8 / N9 +1
P3 R8-D1~D5 +3

完成 P0+P1 后整体预期 88/100;进一步完成 P2 后 89/100P3 全部就位(含 RegionSO + 探索进度 UI + 设计文档)后可冲击 92~93/100


六、与 Round 7 的差异说明

Round 7 报告以"接口补齐 + 局部 NRE 防御"视角给出修复后 88 的预估,但未审视已补 API 的调用闭环。Round 8 在更严标尺下:

  • 发现 NotifyDatabaseChanged 是"半完工 API"(声明 + 实现存在,但无调用方),列为 P0。
  • 发现 MinimapHUD 不渲染 Pin 的功能盲区,列为 P0属于 Round 1~7 一直未提及的功能性缺口)。
  • 重新审视单例守护、服务懒解析、读档广播这三处稳健性细节,列为 P1。

修复方向已在第三章逐项给出,等待执行授权。