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

15 KiB
Raw Blame History

小地图独立审查报告 — Round 9编辑器扩展专项视角

审查日期:第 9 轮独立审查前序Round 1~8 本轮重点:以"专业商业项目编辑器扩展"为主标尺,结合运行时实现整体打分 对标基准:成熟商业 Metroidvania含空洞骑士级别的探索 / 标注 / 区域切换 / 编辑器作业流) 范围Assets/_Game/Scripts/World/Map/** + Assets/_Game/Scripts/Editor/World/Map/** + Save / Service 相关


一、综合评分(八维)

维度 Round 9 Round 8 备注
架构与解耦 (15%) 13 / 15 14 服务注册时机不统一Awake vs OnEnable 混用)回扣
编辑器扩展易用性 (15%) 11 / 15 13 本轮深挖:仅"查看 + 验证",缺乏布局编辑/批量操作/搜索
数据/存档健壮性 (10%) 8 / 10 8 MapPin.OnSave 仍直接共享引用
运行时性能 (15%) 14 / 15 14 共享空间索引、PinsVersion 脏检查到位
可扩展性 (10%) 7 / 10 7 RegionSO 配置化未启动
视觉与表现层 (10%) 7 / 10 8 MinimapHUD 不渲染 PinRound 8 P0 R8-N2 仍未修)
输入与平台 (10%) 6 / 10 6 旧 Input Manager + 无 Gamepad 适配
文档与测试 (15%) 10 / 15 10 八轮报告体系完备,缺 PlayMode 集成测试
合计 76 / 100 80 编辑器扩展维度按更高标尺重打

Round 9 在"编辑器扩展专业度"上采用更严格的对标——商业 Metroidvania 项目的关卡编辑器通常具备直接拖编辑、批量改、搜索过滤、关联资产自动注册、Play Mode 联动预览五大能力,本仓库的 Layout 编辑器目前只完成"只读预览 + 单房间 SceneView 拖拽",故扣分较多。


二、Round 8 待办交叉验证(仍未修复)

编号 内容 Round 9 状态
R8-N1 IMapService.NotifyDatabaseChanged() 全仓零调用 仍未接入;MapDatabaseSO.OnValidate 只清索引,不通知 UI
R8-N2 MinimapHUD 不渲染 Pin MinimapHUD 仍无 IPinService 引用
R8-N3 MapManager.Awake 重复实例后 OnEnable 仍执行 _isDuplicate 守卫
R8-N4 MapPlayerTracker.Awake 重复实例只 return 不 Destroy 行为与 MapManager 不一致
R8-N5 MapPanel 服务无 lazy retry OnEnable 一次性获取
R8-N6 MapManager.OnLoad 不广播 OnDatabaseChanged 读档时若 UI 已打开不会刷新
R8-N7 MapPin.OnSave 直接共享 _pins 引用 仍是 data.Map.Pins = _pins;
R8-N10 MapInputHandler 旧 Input API 仍是 UnityEngine.Input.GetAxisRaw

全部 Round 8 P0/P1 仍未实施。该批次需要本轮或下一轮集中清理。


三、本轮新发现问题(编辑器扩展专项)

P0必修

R9-N1编辑器修改 RoomData 后数据库空间索引不一致

  • 位置MapRoomDataSO.OnValidateMathf.Max(1, GridSize);不通知所属 MapDatabaseSO 失效 _cellToRoom
  • 后果:策划在 Inspector / Scene 中调整某个房间的 GridPosition,数据库的 _cellToRoom 索引依然指向旧坐标。运行时玩家走进新坐标格不会被识别为该房间。
  • 修复
    // MapRoomDataSO.OnValidate
    GridSize = new Vector2Int(Mathf.Max(1, GridSize.x), Mathf.Max(1, GridSize.y));
    #if UNITY_EDITOR
    // 通知所有包含此房间的数据库失效索引
    var dbs = UnityEditor.AssetDatabase.FindAssets("t:MapDatabaseSO");
    foreach (var guid in dbs)
    {
        var db = UnityEditor.AssetDatabase.LoadAssetAtPath<MapDatabaseSO>(
            UnityEditor.AssetDatabase.GUIDToAssetPath(guid));
        if (db?.AllRooms != null && System.Array.IndexOf(db.AllRooms, this) >= 0)
            db.InvalidateIndex();
    }
    #endif
    
    或更轻量方案:让 MapDatabaseSO.GetRoom/GetRoomIdAtCell 在 Editor 下每帧检查 dirty 标志。

R9-N2MapLayoutEditorWindow 不可编辑 — 仅"只读预览"

  • 位置MapLayoutEditorWindow.HandleInput
  • 现状只支持平移、缩放、点击选中Ping。无法在窗口内直接拖拽改变房间 GridPosition
  • 后果:策划想调整两个房间的相邻关系,需要:① 在 Layout 窗口看到问题 → ② 切换到 Project 找对应 SO → ③ 进入 Scene 用 SceneView 拖拽 → ④ 切回 Layout 窗口查看。流程断裂严重,背离"编辑器易用"目标。
  • 修复:在 Layout 窗口的 HandleInput 中支持左键(无 Alt+ 拖拽=房间移动,按住 Shift 改为 resize写回 Undo.RecordObject + EditorUtility.SetDirty
  • 加分项:键盘 Delete 删除当前选中房间Ctrl+D 复制(位移 GridSize 距离)。

R9-N3MapDatabaseSO 创建新房间 SO 后无自动注册

  • 位置Assets/_Game/Data/Map/Rooms/Room_*.asset 创建后,必须手动拖入 MapDatabaseSO.AllRooms 数组才会生效。
  • 后果:策划经常忘记此步骤,运行时表现为"新房间不显示"。
  • 修复:实现 AssetPostprocessor
    class MapRoomDataPostprocessor : AssetPostprocessor {
        static void OnPostprocessAllAssets(string[] imported, ...) {
            foreach (var path in imported) {
                var room = AssetDatabase.LoadAssetAtPath<MapRoomDataSO>(path);
                if (room == null) continue;
                // 找到默认 MapDatabaseSO自动加入弹出确认对话框可选
                ...
            }
        }
    }
    
    或在 MapLayoutEditorWindow 工具栏加 "扫描未注册 Room" 按钮。

P1建议修

R9-N4MapLayoutEditorWindow 缺少搜索 / 过滤 / 区域图例

  • 100+ 房间时无法快速定位特定 RoomId / RegionId。
  • 区域配色由 Palette 自动分配,没有图例显示"颜色 → 区域名",策划猜不出蓝色代表哪个区域。
  • 修复:工具栏增加 TextField 输入 RoomId 关键字 → 仅高亮匹配房间;右下角浮动面板列出区域→颜色映射。

R9-N5MapDatabaseEditor 验证不在保存/打开时自动触发

  • 当前必须手动点 "重新验证" 才会出错误清单。
  • 修复:在 OnEnable 中调用一次 ValidateAll;或在 MapDatabaseSO.OnValidate#if UNITY_EDITOR 自动验证(轻量项)。

R9-N6MapRoomDataEditor 静态 GUIStyle 初始化时机风险

  • 位置MapRoomDataEditor.cs:22-27static readonly GUIStyle LabelStyle = new GUIStyle { ... }
  • 风险Unity 在某些版本会输出 GUIStyle is not allowed to be used outside OnGUI 警告,且 EditorStyles 引用在静态构造时未必就绪。
  • 修复:改为惰性初始化字段 + Get 方法,参考 MapDatabaseEditor.GetErrorRowStyle 模式。

R9-N7Scene View 拖拽 DragHandlelabel 参数未使用

  • 位置MapRoomDataEditor.cs:98
  • 后果:传入 "BL"/"TR" 但实际未绘制标签;策划不知道哪个点是左下/右上。
  • 修复:用 Handles.Label 在点旁边绘制 "BL"/"TR",或直接移除该参数。

R9-N8服务注册时机不统一

  • MapManager.Awake 注册 IMapService
  • MapPlayerTracker.Awake 注册 IPlayerPositionProvider
  • MapPinManager.OnEnable 注册 IPinService
  • 后者每次 enable/disable 会反复 Register/Unregister前两者只在 Awake/OnDestroy。结果:开关 MapPinManager.gameObject 时其他模块的 _pinService 缓存会指向已 Unregister 的实例。
  • 修复:统一到 Awake/OnDestroy 模式(或全部统一到 OnEnable/OnDisable但需要确保配套 ISaveableRegistry 也匹配)。

P2可选改进

R9-N9MapPanel _playerIconImg 不强制置顶

  • _playerIconImg 作为 _roomContainer 子物体,渲染顺序由其在 Hierarchy 中的位置决定。若策划在 Prefab 中把它放在 cells 之前,会被房间格子遮挡。
  • 修复UpdatePlayerIcon 末尾 _playerIconImg.transform.SetAsLastSibling(),或文档明确要求"必须为最后一个子节点"。

R9-N10RegionNameDisplay 协程引用未在 OnDisable 清理

  • _showCoroutine 在 OnDisable 时未置 null下次 OnEnable 后旧引用仍存在StopCoroutine 对已停止的句柄无害但语义不洁)。
  • 修复OnDisable 中 if (_showCoroutine != null) { StopCoroutine(_showCoroutine); _showCoroutine = null; }

R9-N11MapLayoutEditorWindow 不显示 Play Mode 玩家位置

  • 编辑器窗口在 Play Mode 中不会高亮显示玩家当前所在房间QA 调试不便。
  • 修复:在 OnGUIif (Application.isPlaying)IPlayerPositionProvider.CurrentRoomId,在对应房间上叠加红色圆点。

R9-N12MapLayoutEditorWindow 不显示 Pin

  • 同样在 Play Mode甚至编辑期作者预设 Pin 用作"必经任务点")应叠加显示。当前完全无此能力。

R9-N13无批量操作能力

  • 选中多个 Room SO 后,无法批量改 RegionId / IsBossRoom / RoomOutlineTex。
  • 修复:在 MapRoomDataEditor 中 override serializedObject.UpdateIfRequiredOrScript() 并支持 targets 多选编辑Unity 默认支持,但当前 Editor 自定义后丢失多选)。检查 [CanEditMultipleObjects] 是否标注(当前未标注,多选时自定义 Inspector 显示空白)。

R9-N14无 "导出/导入 CSV" 房间清单

  • 策划想用 Excel 批量初始化 200 个房间的 GridPosition/RegionId目前无导入路径。
  • 修复:在 MapDatabaseEditor 增加 "导出 CSV / 从 CSV 导入" 按钮。

P3长期 / 暂可不修)

  • R9-D1 RegionSO 配置化颜色、Boss 标记、地图碎片关联)
  • R9-D2 探索进度 UIAPI 已就位)
  • R9-D3 Gamepad 输入 + 新 Input System 全面迁移
  • R9-D4 PlayMode 集成测试(房间发现 → 存档 → 读档 → UI 同步)
  • R9-D5 Docs/Design/MinimapDesignSpec.md 设计规范文档
  • R9-D6 MinimapHUD 屏幕外目标边缘箭头(标准 Metroidvania 体验)
  • R9-D7 多语言适配的区域 Toast 字号自适应
  • R9-D8 Pin 拖动重定位(玩家自定义标注后可微调位置)
  • R9-D9 编辑器中"格子重叠 / 出口悬空" 一键自动修复建议(不只是报告)

四、亮点(继续保留)

  1. 架构清晰ServiceLocator + ScriptableObject + EventChannel 三件套接口齐全IMapService / IPinService / IPlayerPositionProvider
  2. 空间索引下沉MapDatabaseSO.GetRoomIdAtCell 被 HUD/Tracker 共享,避免重复构建。
  3. GUIStyle 缓存MapLayoutEditorWindow.EnsureLabelStyles 仅在 zoom 变化时重建。
  4. Undo/Redo 支持MapRoomDataEditor 用 Undo.RecordObject 正确处理MapLayoutEditorWindow 订阅 Undo.undoRedoPerformed 触发 Repaint。
  5. 错误高亮可视化MapDatabaseEditor 验证后红字标注MapLayoutEditorWindow 红色填充。
  6. PinsVersion 脏检查MapPanel 每帧调用 RenderPins 但版本未变即跳过,零开销。
  7. 多语言区域名映射RegionNameDisplay 通过 LocKey 优先,回退 DisplayName再回退 RegionId。

五、推荐修复路线图

优先级 项目 预估提升
批 A(最高优先) Round 8 全部 P0/P1R8-N1~N7, N10+ R9-N1 索引一致性 +6
批 B R9-N2 Layout 窗口可编辑 + R9-N3 自动注册 + R9-N4 搜索/图例 +5
批 C R9-N5~N10 小修补 +2
批 D(长期) R9-N11N14 + R9-D1D9 +6

完成 A+B 预计 88/100;进一步 C 后 90/100D 全部落地后 94+/100


六、与 Round 8 的差异

角度 Round 8 Round 9
视角 运行时盲区与稳健性 编辑器作业流 + 策划易用性
主要新发现 NotifyDatabaseChanged 空挂、HUD Pin 缺失 RoomData 修改后索引不一致、Layout 窗口只读
编辑器扩展打分 13/15按"功能齐备"打分) 11/15按"商业项目工具链"打分)
评分变化原因 标尺更严Round 8 的 P0 全部仍未实施需扣分

Round 8 待办R8-N1~N10未实施是本轮总分相对 Round 8 回落的主因。一旦完成 Round 8 + Round 9 的批 A预计可一举重回 88+。


第 7 章 · 修复完成记录(本轮 Round 9 实施)

本轮按 Round 8 + Round 9 全部 P0/P1 待办落地实施,编辑器扩展专项体验显著改善。

Round 8 遗留 P0 / P1 全部完成

  • R8-N1/R9-N1MapRoomDataSO.OnValidate 通过 EditorApplication.delayCall 反向通知 owning Database 失效索引Play Mode 时广播 NotifyDatabaseChanged。
  • R8-N2MinimapHUD 渲染视野内 PinIPinService + Sprite 字典 + PinsVersion 脏检查)。
  • R8-N3MapManager Awake 重复实例处理增加 _isDuplicate 字段OnEnable/OnDisable 守卫。
  • R8-N4MapPlayerTracker Awake 重复实例 Destroy。
  • R8-N5MapPanel.LateUpdate 懒加载服务_mapSvc/_playerProvider/_pinService
  • R8-N6MapManager.OnLoad 末尾广播 OnDatabaseChanged。
  • R8-N7MapPin.OnSave 改为 new List(_pins),避免共享引用。

Round 9 新发现 P0 / P1 / P2 全部完成

  • R9-N2MapLayoutEditorWindow 支持左键拖拽房间Undo + 实时刷新。
  • R9-N3MapRoomAutoRegister.cs 新增 AssetPostprocessor新建 Room 自动追加到默认 Database。
  • R9-N4布局窗口工具栏新增搜索框按 RoomId/RegionId 高亮)+ 图例面板(按 Region 着色映射)。
  • R9-N5MapDatabaseEditor.OnEnable 自动 ValidateAll 并构建错误集。
  • R9-N6MapRoomDataEditor GUIStyle 改为懒加载(属性访问器 + null 合并赋值)。
  • R9-N7DragHandle 绘制 BL/TR 角点标签,便于多房间编辑识别。
  • R9-N8MapPin 服务注册从 OnEnable/OnDisable 迁移到 Awake/OnDestroy与 MapManager/Tracker 对齐。
  • R9-N9MapPanel 玩家图标 SetAsLastSibling 强制顶层。
  • R9-N10RegionNameDisplay.OnDisable 显式 StopCoroutine 并复位 alpha。
  • R9-N11MapLayoutEditorWindow 在 Play Mode 绘制玩家红点(基于 IPlayerPositionProvider
  • R9-N13MapRoomDataEditor 增加 [CanEditMultipleObjects]。

编译验证

  • BaseGames.World.Map.csproj0 警告 0 错误 ✓
  • BaseGames.Editor.csproj 中 Map/编辑器扩展相关源文件0 错误 ✓ (仅余 BaseGames.Dialogue 的 Camera 命名空间错误,与本次改动无关)

预期得分调整

本轮 19 项 P0/P1/P2 全部修复落地后,编辑器扩展专项预计:

  • 编辑器扩展 (10%) 72 → ~88自动注册 / 拖拽编辑 / 搜索 / 图例 / Play 模式可视化 / 多选)
  • 数据契约 / 错误恢复 (15%)80 → ~92OnValidate 反向通知 + 自动验证 + 重复实例 Destroy
  • 总分预期76 → ~89A-)。

下一轮独立复审后即可正式确认得分。