- 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.
12 KiB
12 KiB
Minimap 独立评估报告 — Round 12
评估基线: R11 全部 12 项修复(N1–N12)已实现并验证,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 IoC:
IMapService/IPlayerPositionProvider/IPinService,运行时零具体类耦合 - ServiceLocator 延迟获取,支持启动顺序不确定场景
- 事件语义分离:
OnDatabaseChanged(结构重建)vsOnExplorationChanged(轻量刷新) - R11-N1 修复后
MinimapHUD双服务独立订阅守卫,避免重复注册 MapServiceExtensions扩展方法,对外暴露高层 API 而不污染接口定义MapGridConstants统一共享常量,避免魔法数字分散
遗留问题:
- N7 (P3)
MapPanel.LateUpdate每帧调用SubscribeServices()直到三个服务都获取完毕,之后仍无法跳出该分支(缺少_servicesReady标志)。对热路径略有冗余 - N8 (P3)
MapPanel同时订阅_onMapUpdatedEventChannel 和IMapService.OnExplorationChanged,两者功能部分重叠(单个房间发现时两者都会触发,导致OnExplorationChanged → RefreshAllCells和OnMapUpdated → 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.ExitGridPos用Vector2Int.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> _cellPool,ClearAllCells 回收、RefreshView 复用,彻底消除频繁 Instantiate/Destroy - R11-N6
MapManager.GetRoomsByRegion引入_regionCache,O(N) 全扫变 O(1),NotifyDatabaseChanged时清缓存 - O(1) 空间索引用于玩家房间检测(
GetRoomIdAtCell) - PinsVersion 脏检查避免无效 RenderPins
MapInputHandler缓存_navInput,Update 零轮询_roomsInViewBuffer/_newlyAddedBuffer/_toRemove避免 MinimapHUD 刷新时分配
遗留问题:
- N1 (P2)
MapPanel.RebuildAll和OnDestroy对格子调用Destroy(cell.gameObject),ClearExits对出口连接线调用Destroy(img.gameObject)。与MinimapHUD的_cellPool模式不对称,RebuildAll 在地图数据库变更时被调用,会产生 GC 脉冲
建议:为MapPanel补充Stack<MapRoomCellUI> _cellPool和Stack<Image> _exitPool,ClearExits/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,资产刷新后立即同步 MapRoomDataEditor:Scene 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 优先注册到 ServiceLocatorCompositeDisposable模式统一管理短期订阅,避免 OnDisable 时泄漏
遗留问题:
- N3 (P2)
MapPanel._pinSprites和MinimapHUD._pinSprites是各自独立的[SerializeField] PinSpriteEntry[],配置分散在两个 Prefab 中。新增 PinType 必须同时修改两处 Inspector 配置,容易漏改
建议:提取MapPinConfigSOScriptableObject(单一资产),两个 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 实现
OnRoomMappedAnimprotected 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)
- [N1] 为
MapPanel补充格子与出口对象池,消除 RebuildAll GC 峰值 - [N2]
MapLayoutEditorWindow.DrawExitLines加HashSet<(string,string)>去重,消除重复线段 - [N3] 提取
MapPinConfigSO,统一 Pin 图标配置入口 - [N4]
MapRoomAutoRegister处理deletedAssets,自动清除 Database 中的 null 引用 - [N5]
RoomExitData增加HasCustomExitPosbool 字段,消除 zero 哨兵歧义
计划执行(P3)
- [N6]
RegionNameDisplay.Awake预建Dictionary<string, RegionNameEntry> - [N7]
MapPanel增加_servicesReady标志跳过已就绪后的 LateUpdate 查询 - [N8] 审查 MapPanel 双重刷新路径,决策是否移除
_onMapUpdatedEventChannel 依赖 - [N9] 将
IsBossRoom / IsSavePoint / IsShop重构为[Flags] RoomType枚举 - [N10] 重命名
MapPin.cs为MapPinManager.cs(或拆分数据/管理两个文件)
综合评价
经过 R11 的 12 项修复,系统已消除所有 P1 阻断性缺陷,架构层面趋于稳定。当前版本在 InputSystem 集成、对象池、编辑器工具完整性、服务解耦等核心维度均达到商业标准。
剩余 R12 的 10 项 findings 均为 P2/P3 改善项,不影响功能正确性,主要涉及:配置中心化(N3/N9)、编辑器视觉质量(N2)、运行时 GC 一致性(N1)、数据语义清晰度(N5)。
最终评分:86.2/100(B+)
达到可发布的商业 Metroidvania 小地图实现标准,剩余工作为进一步打磨的优化项,非阻断项。