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

8.5 KiB
Raw Permalink Blame History

小地图系统 R26 独立评审报告

评审轮次Round 26R25 修复后全面重审)
评审基准:成熟 2D Metroidvania 游戏商业级标准 + 专业编辑器扩展


一、各维度评分

维度 满分 得分 vs R25修复后
架构设计 & 解耦合 25 24.0 -0.5
性能 & 运行时效率 20 19.5 ±0
编辑器工具质量 15 14.5 ±0
代码质量 & 可维护性 15 13.8 -0.2
存档 & 持久化 10 9.5 ±0
可扩展性 10 9.5 ±0
功能完整性 5 5.0 ±0
综合 100 95.8 -1.7

R25修复后基准97.5 → R2695.8(发现 2 项新问题)


二、R25 修复全部落地确认

修复项 状态
C1TeleportService.CanTeleportTo _mapSvc == null || ..._mapSvc != null && ...
N1MapPanel._subs 死代码字段及 Clear() 调用全部移除
N2MapInputHandler.Awake 展开 + #if UNITY_EDITOR || DEVELOPMENT_BUILD 校验警告

三、持续表现优秀的设计

维度 设计亮点
接口解耦 IMapService / IPlayerPositionProvider / IPinService / ITeleportService 全通过 ServiceLocatorUI 层无任何具体类引用
执行顺序链 MapManager(-700)→MapPlayerTracker(-600)→MapPinManager(-500)→TeleportService(-400)→UI(0);服务注册先于所有消费方
空间索引共享 MapDatabaseSO 统一维护 _cellToRoom 字典MinimapHUD 的 O(viewRadius²) 剔除与 MapPlayerTracker 的 O(1) 房间判定共享同一索引,无重复构建
五类对象池 MapPanelCell/Exit/Pin+ MinimapHUDCell/Pin全量 Disable 入池、Enable 出池OnDestroy 销毁剩余发现动画协程自清理R20-N1
ISaveable 防御性拷贝 MapManager / MapPinManager / TeleportService 三处对称OnSave new HashSet/ListOnLoad Clear+foreach Add
_servicesReady 短路 MapPanel + MinimapHUD 均在三服务就绪后置 true消除每帧 ServiceLocator 查询
LateUpdate 脏检查 MapPanel 玩家图标RoomId + NormPos 双字段MinimapHUD 玩家圆点Pin 版本号脏检查——全部避免无效 RectTransform 读写
DRY ChooseDisplayIcon 集中在 MapRoomDataSOBuildRegionDict / ResolveRegionDisplayName 集中在 MapServiceExtensionsMapPanel + MinimapHUD 均通过委托调用
编辑器工具 拖拽/缩放/验证4类错误/搜索RoomId/RegionId/RoomType三维/图例/Play Mode 玩家叠加GUIStyle 缓存MatchesRoomType 不区分大小写
存档健壮性 OnLoad 空集合防御、空 id 过滤OnValidate 自动 Trim RoomId、迁移旧 bool 字段;delayCall -=;+= 防止 Inspector 快速操作重复触发
UnsubscribeServices 有意不对称 MapPanelOnDestroy 末尾不清空引用vs MinimapHUD置 null + 重置标志,支持跨场景重连)——均有注释说明

四、新发现问题

N1 — NormalITeleportService 接口不完整(UnlockTeleportStation / NotifyTeleportCompleted 缺失)

文件ITeleportService.cs(接口缺失),TeleportService.csL103115 公开方法)

问题

// ITeleportService 接口中存在的方法:
bool CanTeleportTo(string roomId);
void RequestTeleport(string targetRoomId);
event Action<string, string> OnTeleportRequested;
event Action<string> OnTeleportCompleted;

// ─── 缺失的两个写操作方法 ───
// TeleportService 上有 public 定义,但不在接口中:
public void NotifyTeleportCompleted(string arrivedRoomId);   // 场景加载系统须调用
public void UnlockTeleportStation(string roomId);            // 游戏触发器须调用

影响

  • 场景加载系统完成传送后需调用 NotifyTeleportCompleted,但通过 ServiceLocator.GetOrDefault<ITeleportService>() 只能拿到接口,无法访问该方法;调用方被迫使用具体类型(TeleportService)或反射,破坏接口解耦原则
  • 传送站触发器OnTriggerEnter 等)需要调用 UnlockTeleportStation,同样面临相同问题。
  • 接口 + ServiceLocator 模式在整个系统中一致使用,此处缺口会让后续维护者混淆。

修复:在 ITeleportService 中补全两个方法:

/// <summary>解锁指定房间的传送点(游戏触发器调用)。</summary>
void UnlockTeleportStation(string roomId);

/// <summary>场景加载系统传送完成后调用,触发 OnTeleportCompleted 事件。</summary>
void NotifyTeleportCompleted(string arrivedRoomId);

N2 — NormalMapPinManager 缺少 _isDuplicate 单例保护(与 MapManager / MapPlayerTracker 不一致)

文件MapPin.csMapPinManager 类L3237

问题

// MapManager正确
private void Awake()
{
    if (ServiceLocator.GetOrDefault<IMapService>() != null) { _isDuplicate = true; Destroy(gameObject); return; }
    ServiceLocator.Register<IMapService>(this);
}

// MapPlayerTracker正确
private void Awake()
{
    if (ServiceLocator.GetOrDefault<IPlayerPositionProvider>() != null) { _isDuplicate = true; ... }
    ...
}

// MapPinManager缺少保护
private void Awake()
{
    // ← 无重复实例检测
    ServiceLocator.Register<IPinService>(this);   // 若已有注册,直接覆盖
}

影响

  • 若场景中意外存在两个 MapPinManagerPersistent 场景加载两次、DontDestroyOnLoad 重复等),第二个实例会覆盖 ServiceLocator 注册,但第一个实例的 ISaveable 仍保持注册状态(OnEnable 中加入 SaveableRegistry导致存档时 OnSave 被调用两次、集合竞争写入 SaveData.Map.Pins
  • 系统其他三处服务均有 _isDuplicate 守卫,此处缺失属于架构一致性漏洞。

修复

private void Awake()
{
    if (ServiceLocator.GetOrDefault<IPinService>() != null)
    {
        _isDuplicate = true;
        Destroy(gameObject);
        return;
    }
    ServiceLocator.Register<IPinService>(this);
}

// OnEnable / OnDisable / OnDestroy 首行加 if (_isDuplicate) return;

五、各文件评分摘要

文件 状态 备注
MapManager.cs 完整 执行顺序/ISaveable/IMapService/缓存/LINQ 仅在非热路径
MapPlayerTracker.cs 完整 O(1) 空间索引/平滑归一化/单例保护
MapPinManagerMapPin.cs ⚠️ N2 缺少 _isDuplicate 保护
TeleportService.cs ⚠️ N1 接口缺口UnlockTeleportStation/NotifyTeleportCompleted
MapPanel.cs 完整 R25-N1 _subs 死代码已移除;五层解耦;三对象池
MinimapHUD.cs 完整 O(viewRadius²) 剔除跨场景重连GC 友好缓冲区
MapInputHandler.cs 完整 R24-N2 单一 scale 状态R25-N2 配置警告
MinimapInputHandler.cs 完整 干净委托,单职责
MapRoomCellUI.cs 完整 双场景复用PlayRevealAnim 颜色恢复
MapRoomDataSO.cs / MapDatabaseSO 完整 ChooseDisplayIcon 集中空间索引共享OnValidate 含延迟通知防抖
MapServiceExtensions.cs 完整 纯静态无状态DRY 中心
RegionNameDisplay.cs 完整 CompositeDisposable 正确使用;协程 OnDisable 终止安全
ITeleportService.cs ⚠️ N1 缺少两个写操作方法声明
MapLayoutEditorWindow.cs编辑器 完整 搜索+图例+拖拽+验证+GUIStyle 缓存+✕按钮

六、修复优先级

编号 严重度 文件 影响 建议
N1 🟡 Normal ITeleportService.cs + TeleportService.cs 接口不完整导致调用方被迫使用具体类型 立即修复
N2 🟡 Normal MapPin.csMapPinManager 多实例场景存档竞争写入 立即修复

七、评分历史

轮次 综合评分 主要变化
R17 93.0 初轮重构后
R18R19 93.8 平移/缩放/协程修复
R20 94.2 DRY + 协程自清理
R21 95.0 ServicesReady 对称
R22 96.5 BuildRegionDict 集中
R23 97.5 MatchesRoomType + 执行顺序
R24 97.5 TeleportService 重建(遗留 C1
R25修复前 95.5 发现 C1 逻辑反转 + N1 死代码 + N2 无警告
R25修复后基准 97.5 三项全修复
R26 95.8 发现 N1接口不完整-1.2+ N2单例缺失-0.5

R26 评审完成时间2026-05-25