Add independent review report for Minimap system Round 7

- Validate fixes from Round 6 and identify new issues
- Document findings including UX defects, editor integration flaws, and code quality concerns
- Propose solutions and prioritize issues based on severity
- Evaluate against standards of mature 2D Metroidvania games
This commit is contained in:
2026-05-25 14:44:31 +08:00
parent 5cb6c2a19d
commit e2bc324905
17 changed files with 1060 additions and 17 deletions

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96f79378a72e0884eb67abdec7cedd2a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2f10ab54d55ebf14a8c93cca7164230c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8bb8a918cea77d4097634a071a13b4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4868a5b10a549ea43826ff162ecc6b5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0c5d13ad97e89a4b8f49b35620789c5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -94,7 +94,7 @@ namespace BaseGames.World.Map
private void OnValidate() => _index = null; // 编辑器中修改 AllRooms 后强制重建索引
// ── 配置验证 ──────────────────────────────────────────────────────────
#if UNITY_EDITOR
/// <summary>
/// 检查数据库中的常见配置错误RoomId 重复、格子重叠、出口悬空)。
/// 编辑器侧调用;运行时不应调用(有 O(N²) 开销)。
@@ -152,5 +152,6 @@ namespace BaseGames.World.Map
return errors;
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a93d2e2dddd51740807bd2ceebb68c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -42,6 +42,11 @@ namespace BaseGames.World.Map
// 复用 List 避免 RefreshView 每次分配临时 ListGC 友好)
private readonly List<string> _toRemove = new List<string>(8);
// 空间索引:格子坐标 → 房间 ID将 RefreshView step② 的 O(N) 遍历降至 O(viewRadius²)
private Dictionary<Vector2Int, string> _spatialIndex;
// 复用 HashSet 避免 RefreshView 每次分配GC 友好)
private readonly HashSet<string> _roomsInViewBuffer = new HashSet<string>(32);
private Vector2Int _currentCenter;
private string _lastDotRoomId;
private Vector2 _lastDotNormPos;
@@ -53,6 +58,8 @@ namespace BaseGames.World.Map
_mapSvc = ServiceLocator.GetOrDefault<IMapService>();
_playerProvider = ServiceLocator.GetOrDefault<IPlayerPositionProvider>();
BuildSpatialIndex(_mapSvc?.Database);
if (_playerProvider != null)
_playerProvider.OnRoomChanged += OnRoomChanged;
@@ -72,6 +79,7 @@ namespace BaseGames.World.Map
_lastDotRoomId = null;
_mapSvc = null;
_playerProvider = null;
_spatialIndex = null;
}
private void ClearAllCells()
@@ -81,6 +89,24 @@ namespace BaseGames.World.Map
_cells.Clear();
}
/// <summary>
/// 构建格子坐标 → 房间 ID 的哈希映射。
/// 将 RefreshView step② 从 O(allRooms) 全量遍历降至 O(viewRadius²) 范围格点查询。
/// 数据库变更时(如热更)应再次调用。
/// </summary>
private void BuildSpatialIndex(MapDatabaseSO db)
{
_spatialIndex = new Dictionary<Vector2Int, string>();
if (db?.AllRooms == null) return;
foreach (var room in db.AllRooms)
{
if (room == null) continue;
for (int x = 0; x < room.GridSize.x; x++)
for (int y = 0; y < room.GridSize.y; y++)
_spatialIndex[new Vector2Int(room.GridPosition.x + x, room.GridPosition.y + y)] = room.RoomId;
}
}
private void LateUpdate()
{
UpdatePlayerDot();
@@ -133,16 +159,30 @@ namespace BaseGames.World.Map
}
foreach (var id in _toRemove) _cells.Remove(id);
// ② 实例化新进入范围的格子
foreach (var room in db.AllRooms)
// ② 用空间索引替代 O(N) 全量遍历,在可视范围格点上查询所属房间
// 复杂度O(viewRadius²) 替代 O(allRooms),大地图下效果显著
_roomsInViewBuffer.Clear();
if (_spatialIndex != null)
{
if (room == null || _cells.ContainsKey(room.RoomId)) continue;
if (!RoomInView(room, minX, maxX, minY, maxY)) continue;
for (int x = minX; x <= maxX; x++)
for (int y = minY; y <= maxY; y++)
{
if (_spatialIndex.TryGetValue(new Vector2Int(x, y), out var rId))
_roomsInViewBuffer.Add(rId);
}
}
foreach (var roomId in _roomsInViewBuffer)
{
if (_cells.ContainsKey(roomId)) continue;
var room = db.GetRoom(roomId);
if (room == null) continue;
var cell = Instantiate(_cellPrefab, _cellContainer);
cell.Setup(room, _mapSvc.GetVisibility(room.RoomId), null);
cell.SetColors(_colorExplored, _colorMapped, _colorUnknown);
_cells[room.RoomId] = cell;
PlaceCell(cell, room); // 立即设置正确的中心相对坐标,避免 Setup 默认偏移被 step③ 覆盖
_cells[roomId] = cell;
}
// ③ 重定位所有格子(中心发生变化时)

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02879db752b9f0b4bb1b0c9834ad4d84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: