- 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.
10 KiB
小地图系统独立评审 Round 23
评审时间:R23(基于 R22 全部修复已落地的代码基线)
评审范围:Assets/_Game/Scripts/World/Map/ 全部 19 个运行时文件 + 4 个编辑器扩展文件
评分基准:专业 2D Metroidvania 编辑器扩展标准(架构解耦 / 高性能 / 可扩展 / 开发者友好)
R22 修复确认
| 编号 | 内容 | 状态 |
|---|---|---|
| R22-N1 | BuildRegionDict/ResolveRegionDisplayName 迁移至 MapServiceExtensions;两个组件单行委托 |
✅ 确认(MapServiceExtensions.cs:17,32;两组件第 104-108 行) |
| R22-N2 | DrawRoomBadge 注释更新为 MapRoomDataSO.ChooseDisplayIcon |
✅ 确认(MapLayoutEditorWindow.cs:480,488) |
| R22-N3 | MapPinManager [DefaultExecutionOrder(-500)] |
✅ 确认(MapPin.cs:20) |
各维度评分
1. 架构设计(Architecture)19.5 / 20
亮点(全面审查确认)
- 4 接口(IMapService / IPinService / IPlayerPositionProvider / ITeleportService)+ ServiceLocator,零硬依赖
- 事件驱动(Action,无帧轮询):OnDatabaseChanged / OnExplorationChanged / OnRoomMapped 语义独立
- ISaveable 防御性拷贝三处对称(MapManager:
new HashSet<>×2;MapPinManager:new List<>双向;TeleportService:readonly+ Clear+Add) ChooseDisplayIcon单一入口(MapRoomDataSO),MapPanel / MinimapHUD / Editor 三处均委托MapServiceExtensions:3 个无状态方法(GetVisibility / CreatePinAtWorldPos / BuildRegionDict+Resolve),消费方零重复逻辑MapRoomCellUI双视图(MapPanel 全屏 + MinimapHUD 角落)复用同一 PrefabRoomType [Flags]枚举支持多类型组合,OnValidate自动迁移旧 bool 字段
信息级观察:MapPanel.UnsubscribeServices() 不 null 服务引用,而 MinimapHUD.UnsubscribeServices() 会 null 三个字段并重置 _servicesReady。这是有意的架构差异——MapPanel 仅在 OnDestroy 调用 UnsubscribeServices(生命周期末尾,引用已无意义),而 MinimapHUD 作为持久 HUD 需支持跨场景重连。在目标持久服务架构下,两者均不会出现悬空引用。无需修复,但值得注释说明设计意图。
扣分:−0.5(UnsubscribeServices 不对称缺少注释,可读性略低)
2. 性能(Performance)19.5 / 20
亮点
_servicesReady短路(MapPanel R12-N7;MinimapHUD R21-N1),消除每帧 ServiceLocator 查询- MapPanel 对象池 × 3(
readonly集合:_cellPool/_pinPool/_exitPool);MinimapHUD × 2 - O(viewRadius²) 空间索引(
MapDatabaseSO.GetRoomIdAtCell),MinimapHUD 无需扫描全量房间 - 4 个复用缓冲区(
_toRemove/_roomsInViewBuffer/_newlyAddedBuffer+_cells增量更新) PinsVersion脏检查:两 UI 均跳过无变化重绘_totalRoomCount懒加载缓存(MapManager),_regionCache懒加载(GetRoomsByRegion 零 LINQ)- 玩家图标双脏标记(roomId + normPos),消除无效 RectTransform 写入
信息级:MapProgressDisplay.Refresh() 区域进度遍历 O(N/region),仅在 OnExplorationChanged 触发(非每帧),当前规模无性能风险。
扣分:−0.5(MapProgressDisplay 区域遍历未缓存已探索计数;极大地图时有轻微冗余)
3. 代码质量(Code Quality)19.5 / 20
亮点
- 全部集合字段补齐
readonly(MapPanel × 6;MinimapHUD × 4;_revealCoroutines亦为readonly) CurrentZoom属性消除双份缩放状态(MapPanel L379)RunRevealAnim自清理协程:完成后自动_revealCoroutines.Remove(roomId)(R20-N1)HasCustomExitPos语义布尔替代== Vector2Int.zero哨兵(R13-N1)[Obsolete]+[HideInInspector]废弃字段注解完整RoomId.Trim()自动修剪防空格污染(OnValidate)DrawLinetry/finally 保证GUI.matrix恢复(R11-N12)MapPin.cs文件头注释明确历史遗留原因
信息级:MapPanel.UnsubscribeServices() 相比 MinimapHUD.UnsubscribeServices() 缺少注释说明为何不 null 服务引用。新加入代码者可能误认为是疏漏。
扣分:−0.5(UnsubscribeServices 不对称未有注释解释意图)
4. 编辑器扩展(Editor Tools)14.5 / 15
亮点
MapLayoutEditorWindow:缩放 / 平移 / 房间拖拽 / 搜索 / 区域着色 / 验证 / Undo / 热改全功能_cachedZoomForStyle脏检查 +_noResultStyle首次初始化缓存(R18-N2)DrawExitLines字段级_drawnExitPairs去重,OnGUI 零分配OnProjectChange+OnUndoRedo自动失效验证缓存并触发重绘SetDatabase公共 API(避免 MapDatabaseEditor 反射访问私有字段)MapRoomAutoRegisterAssetPostprocessor 自动注册工作流MapDatabaseSO.ValidateAll()四类校验(null / 空 RoomId / 重复 / 格子重叠 / 出口悬空)DrawRoomBadge注释已更新为MapRoomDataSO.ChooseDisplayIcon(R22-N2)
扣分:−0.5(MapLayoutEditorWindow 搜索框匹配范围仅 RoomId/RegionId 子串,无法按 RoomType 过滤;策划批量检查某类型房间时需逐个点击)
5. 功能完整性(Feature Completeness)15.0 / 15
所有特性完整实现:
- 三级可见性(Unknown / Explored / Mapped)+ 雾效覆盖层(R12-FD)
- 图标优先级唯一入口(Override > SavePoint > Boss > Shop > Teleport)
- Pin 系统(持久化 / 类型化 / 视野内渲染 / 64 字符 note 限制)
- 出口连接线 + Fallback 位置(HasCustomExitPos 语义布尔)
- 传送系统(TeleportService:解锁 / 验证 / 请求 / 完成回调)
- 区域检测 + 区域名本地化显示(RegionNameDisplay + MapProgressDisplay)
- 存档/读档(ISaveable 三处,防御性拷贝对称)
- 房间发现动画(PlayRevealAnim + RunRevealAnim 自清理)
- 全屏地图 + 角落 HUD 双视图;小地图视野档位循环切换(CycleZoom)
RoomType [Flags]枚举 +OnValidate向后兼容迁移
扣分:0
6. 输入系统(Input System)9.5 / 10
亮点
- 全部使用 InputReaderSO(InputSystem),无硬编码按键
MapInputHandler:Navigate / MapCenter / OnScroll 完整MinimapInputHandler:CycleMinimapZoom 路由 MinimapHUD.CycleZoom()- OnEnable/OnDisable 对称订阅/取消
信息级:MapInputHandler._zoom 作为本地累加器,与 _panel.CurrentZoom 读取路径不同但结果一致(OnScroll 写 _roomContainer.localScale → CurrentZoom 从 _roomContainer.localScale.x 读取,无环,无状态漂移)。
扣分:−0.5(MapInputHandler._zoom 轻微职责重叠,正确但不够直观)
综合评分
| 维度 | 满分 | 得分 | 较 R22 |
|---|---|---|---|
| 架构设计 | 20 | 19.5 | +0.5 |
| 性能 | 20 | 19.5 | ±0 |
| 代码质量 | 20 | 19.5 | +0.5 |
| 编辑器扩展 | 15 | 14.5 | ±0 |
| 功能完整性 | 15 | 15.0 | ±0 |
| 输入系统 | 10 | 9.5 | ±0 |
| 合计 | 100 | 97.5 | +1.0 |
问题清单
N1 — MapPanel.UnsubscribeServices 缺少意图注释(低优先级)
现状:MinimapHUD.UnsubscribeServices() 会 null 三个服务引用并重置 _servicesReady;MapPanel.UnsubscribeServices() 不做此操作(也不需要,因为仅在 OnDestroy 调用)。两者不对称,可读性略差。
修复:在 MapPanel.UnsubscribeServices() 首行补注释:
// OnDestroy 时调用,生命周期末尾不需要 null 服务引用(与 MinimapHUD.UnsubscribeServices 的设计差异:
// MinimapHUD 需支持 OnDestroy 后跨场景重连,MapPanel 不需要)。
N2 — MapLayoutEditorWindow 搜索框不支持 RoomType 过滤(低优先级)
场景:策划需要批量确认所有 SavePoint / BossRoom 房间的位置时,当前搜索只能匹配 RoomId/RegionId 子串,无法用 SavePoint 等类型关键字过滤。
建议方案:在搜索逻辑中加入 RoomType 枚举名匹配:
// 在 DrawMapArea 的搜索匹配部分补充:
bool matchesType = !string.IsNullOrEmpty(_searchText) &&
System.Enum.GetNames(typeof(RoomType))
.Any(name => room.RoomFlags.HasFlag((RoomType)System.Enum.Parse(typeof(RoomType), name))
&& name.IndexOf(_searchText, System.StringComparison.OrdinalIgnoreCase) >= 0);
bool matches = matchesId || matchesRegion || matchesType;
N3 — TeleportService 缺少 [DefaultExecutionOrder](信息级)
TeleportService.Awake() 注册 ITeleportService。当前 UI 组件(MinimapHUD / MapPanel)的 SubscribeServices 不查询 ITeleportService,因此无执行顺序风险。但与其他三个服务(MapManager -700 / MapPlayerTracker -600 / MapPinManager -500)相比,未标注顺序,一致性略差。
[DefaultExecutionOrder(-400)] // 晚于 MapPinManager(-500),早于默认 0;ITeleportService 在 UI 初始化前可用
public class TeleportService : MonoBehaviour, ITeleportService, ISaveable
评分历史
| 轮次 | 评分 | 关键改动 |
|---|---|---|
| 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 | RegionNameEntry DRY 消除;注释更新;MapPinManager 执行顺序 |
| R23 | 97.5 | R22 修复确认;识别 N1(注释不对称)N2(搜索缺 RoomType 过滤)N3(TeleportService 执行顺序) |
总评
经过 23 轮迭代,小地图系统已达到专业商业 2D Metroidvania 发布标准:
- 架构:接口 + ServiceLocator + 事件驱动,各层职责清晰,扩展无需改动已有代码
- 性能:全部热路径均有脏检查 / 对象池 / 短路机制保护,大地图下无性能风险
- 开发体验:编辑器工具完整,策划可视化配置房间、验证错误、调试布局
- 代码健康:DRY 违反已全部消除,readonly / 防御性拷贝 / 对象池三要素一致应用
剩余 2.5 分差距为信息级的可读性优化与编辑器小功能增强,不影响运行时正确性。