Files
zeling_v2/Docs/Review/Minimap_Review_Round14_Independent.md
T
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.0 KiB
Raw Blame History

小地图系统 独立审查报告 Round 14

审查范围Assets/_Game/Scripts/World/Map/Runtime 19 文件)+
Assets/_Game/Scripts/Editor/World/Map/Editor 4 文件)

对标标准:成熟 2D Metroidvania 类型游戏的专业编辑器扩展级别,
面向开发人员和策划人员,要求架构解耦、高性能、高可扩展性。


总评分(修复前)

维度 满分 得分 说明
架构解耦 10 9.0 接口 + ServiceLocator 完整;MapPin.cs 文件名历史遗留
性能 10 9.0 对象池完整、dirty check 完整;DrawExitLines 每帧 new HashSet
编辑器 UX 10 9.0 可视化布局编辑器成熟;DrawExitLines HashSet GC 小问题
数据模型 10 8.5 RoomType [Flags] 完善;缺少 TeleportStation 类型
输入系统 10 8.5 InputSystem 软绑定完整;MinimapInputHandler R13 已加
功能完整性 10 6.5 TeleportService 存在但 MapPanel 无传送 UI 集成;SaveKey 模式错误
代码质量 10 8.5 注释质量高;TeleportService 含死代码字段
存档系统 10 5.0 TeleportService.ISaveable 签名错误(编译错误)
可扩展性 10 9.0 SO 驱动、Event Channel 解耦、Region 机制完善
总分 90 73.0 换算 100 分:81.1 / 100B

相比 R1385.0/100R13 N1–N4 + FA 修复提升了输入系统与 Bug 修复维度,
但 TeleportService 的 ISaveable 签名引入了编译错误(N1),使存档分大幅下降。
所有修复后预计 92+


Bug 发现

N1(致命 — 编译错误):TeleportService 实现了错误的 ISaveable 签名

文件TeleportService.csR13-FA 新增),SaveData.cs

问题
ISaveable 接口(BaseGames.Core.Save)定义为:

public interface ISaveable
{
    void OnSave(SaveData saveData);
    void OnLoad(SaveData saveData);
}

TeleportService 实现的是:

public string SaveKey => "TeleportService";  // ❌ 接口中不存在此成员
public string Serialize() { ... }            // ❌ 接口中不存在此方法
public void Deserialize(string data) { ... } // ❌ 接口中不存在此方法
// ❌ 缺少 OnSave(SaveData) / OnLoad(SaveData)

这导致 BaseGames.World.Map 程序集无法编译,整个地图系统全部失效。
此外,MapSaveDataSaveData.cs)中没有 UnlockedTeleportRoomIds 字段,
即使签名正确,传送数据也无处存储。

同时TeleportServiceISaveableRegistry 注册自身(OnEnable 中),
ISaveableRegistry 期望的是 ISaveable 对象,
TeleportService 未正确实现该接口,注册调用将在运行时无效。

修复方案

  1. SaveData.cs — 在 MapSaveData 中添加:

    public HashSet<string> UnlockedTeleportRoomIds = new();
    
  2. TeleportService.cs — 替换 SaveKey/Serialize/Deserialize 为:

    public void OnSave(SaveData saveData)
    {
        saveData.Map.UnlockedTeleportRoomIds = new HashSet<string>(_unlockedRoomIds);
    }
    public void OnLoad(SaveData saveData)
    {
        _unlockedRoomIds.Clear();
        if (saveData.Map.UnlockedTeleportRoomIds != null)
            foreach (var id in saveData.Map.UnlockedTeleportRoomIds)
                _unlockedRoomIds.Add(id);
    }
    

    移除 ISaveableRegistry 手动注册(OnSave/OnLoadSaveManager 直接调用,无需 Registry)。


N2(高优先级):RoomType 缺少 TeleportStation 标志位

文件MapRoomDataSO.csMapPanel.cs

问题
RoomType [Flags] 枚举目前有 BossRoom / SavePoint / Shop / Merchant / Challenge
但没有 TeleportStationTeleportService 的解锁状态存储于运行时,
策划无法在 SO 上标记"此房间有传送站"MapPanel 也无法据此渲染传送图标。

// 当前
public enum RoomType
{
    None      = 0,
    BossRoom  = 1 << 0,
    SavePoint = 1 << 1,
    Shop      = 1 << 2,
    Merchant  = 1 << 3,
    Challenge = 1 << 4,
    // ❌ 缺少 TeleportStation
}

修复

  1. RoomType 添加 TeleportStation = 1 << 5
  2. MapPanel 添加 [SerializeField] private Sprite _iconTeleport; 字段
  3. MapPanel.ChooseIcon() 中补充传送站图标逻辑
  4. MapPanel 获取 ITeleportService,在 BuildGrid / RefreshCell 时区分
    "已解锁传送站"和"未解锁传送站"的颜色/图标

N3(中等):TeleportService._pendingSourceRoomId 是死代码

文件TeleportService.cs,第 108 行

问题

_pendingSourceRoomId = sourceRoomId;  // ← 赋值后从未读取
OnTeleportRequested?.Invoke(sourceRoomId, targetRoomId);  // sourceRoomId 已直接传入

_pendingSourceRoomId 只被写入,永远不被读取,是无用的私有字段。

修复:删除 _pendingSourceRoomId 字段及赋值语句。


N4(低优先级):MapLayoutEditorWindow.DrawExitLines 每帧 new HashSet

文件MapLayoutEditorWindow.csDrawExitLines() 方法(约第 453 行)

问题

private void DrawExitLines(MapDatabaseSO db, ...)
{
    var drawn = new HashSet<(string, string)>();  // ❌ 每次 OnGUI 都分配新对象
    ...
}

编辑器 OnGUI 以每秒多次频率调用,持续产生 GC 分配,可能导致编辑器卡顿。

修复:将 drawn 提升为类字段 _drawnExitPairs,在方法内仅调用 Clear()


N5(低优先级):MapPanel.OnMapUpdated 未标注 [Obsolete]

文件MapPanel.cs,第 313 行

问题

private void OnMapUpdated(string roomId) { /* R12-N8 已废弃 */ }

方法已废弃但未加 [Obsolete] 标注,后续开发者可能误以为该方法仍有业务逻辑。

修复:添加 [Obsolete("R12-N8: 由 OnExplorationChanged 统一处理,仅保留序列化兼容性。")]


架构亮点(保持优秀)

以下设计在本轮审查中仍被评定为业界优秀水平:

亮点 说明
接口 + ServiceLocator 4 个服务接口完全解耦,UI 层零具体类型依赖
O(1) 空间索引 MapDatabaseSO.GetRoomIdAtCell 惰性构建,MinimapHUD + MapPlayerTracker 共享
三重对象池 MapPanelcell/pin/exit+ MinimapHUDcell/pin)零 GC 渲染
Dirty Flag 模式 面板关闭期间收到事件,OnEnable 时应用——无事件遗漏
_servicesReady 短路 三服务就绪后跳过 LateUpdate 的 ServiceLocator 查询
PinsVersion 脏检查 无需事件订阅,整数比较即可判断 Pin 集合是否变化
可视化布局编辑器 MapLayoutEditorWindow:拖拽/吸附/缩放/搜索/Play 模式覆盖层
MapRoomAutoRegister AssetPostprocessor 自动注册新房间 SO,零手动操作
InputSystem 软绑定 throwIfNotFound: false 防 InputActionAsset 缺失崩溃
HasCustomExitPos 标志 消除 Vector2Int.zero 哨兵值歧义(R12-N5R13-N1 已修复)

修复优先级总表

编号 严重程度 文件 说明
N1 ★★★★★ 致命 TeleportService.cs + SaveData.cs ISaveable 签名错误导致编译失败
N2 ★★★★ 高 MapRoomDataSO.cs + MapPanel.cs 缺少 TeleportStation RoomType + MapPanel 传送 UI 集成
N3 ★★★ 中 TeleportService.cs _pendingSourceRoomId 死代码
N4 ★★ 低 MapLayoutEditorWindow.cs DrawExitLines HashSet 每帧分配
N5 ★ 极低 MapPanel.cs OnMapUpdated 缺 [Obsolete]

修复后预估评分

维度 修复前 修复后
架构解耦 9.0 9.0
性能 9.0 9.5N4 修复)
编辑器 UX 9.0 9.0
数据模型 8.5 9.5N2 TeleportStation
输入系统 8.5 8.5
功能完整性 6.5 9.0N2 传送 UI
代码质量 8.5 9.0N3/N5
存档系统 5.0 9.5N1 修复)
可扩展性 9.0 9.0
总分 81.1 ≈ 92.3