- 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.
9.1 KiB
小地图系统独立评审 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唯一入口(MapRoomDataSO),MapPanel / MinimapHUD 无漂移MapServiceExtensions无状态扩展方法,消费方零重复查询逻辑
新发现问题 N1(中等):RegionNameEntry 字典解析逻辑在两个组件重复
RegionNameDisplay 与 MapProgressDisplay 各自独立实现了完全相同的模式:
// 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集合池 × 6(Cell / Pin / Exit);MinimapHUD × 4 _servicesReady短路(MapPanel R12-N7,MinimapHUD 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]废弃字段注解完整DrawLinetry/finally 保证 GUI.matrix 恢复(R11-N12)MapPin.cs文件头注释标明"文件名历史遗留,请搜索类名 MapPinManager"
新发现问题 N2(轻微):编辑器 DrawRoomBadge 注释引用已过时
// MapLayoutEditorWindow.cs L488
// 优先级与运行时 MapPanel.ChooseIcon 对齐:Save > Boss > Shop > Teleport
R20-N2 已将运行时图标选取逻辑迁移至 MapRoomDataSO.ChooseDisplayIcon,
MapPanel.ChooseIcon 已变为单行委托。注释应更新为:
// 优先级与运行时 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 反射访问私有字段MapRoomAutoRegisterAssetPostprocessor 自动注册工作流完整
扣分:−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
亮点
- 全部使用 InputSystem(InputReaderSO)
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 追加静态扩展/工具方法:
/// <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;
}
两个组件改为:
private void BuildRegionDict()
=> _regionDict = MapServiceExtensions.BuildRegionDict(_regionNames);
private string ResolveDisplayName(string regionId)
=> MapServiceExtensions.ResolveRegionDisplayName(_regionDict, regionId);
N2 — DrawRoomBadge 注释引用过时(低优先级)
修复:MapLayoutEditorWindow.cs L488 注释更新:
// 优先级与运行时 MapRoomDataSO.ChooseDisplayIcon 对齐:Save > Boss > Shop > Teleport
N3 — MapPinManager 缺少 [DefaultExecutionOrder](信息级)
MapPinManager.Awake 注册 IPinService,若晚于 UI 的 SubscribeServices 调用,
_pinService 将在首帧为 null(由 _servicesReady 重试机制兜底)。
两 UI 的 _servicesReady 短路已覆盖此场景,但显式标注执行顺序更具防御性:
[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 _servicesReady;MapPlayerTracker 执行顺序;readonly 补全 |
| R22 | 96.5 | R21 修复确认;识别 N1(RegionNameEntry DRY)N2(注释过时)N3(MapPinManager 执行顺序) |