Files
zeling_v2/Assets/_Game/Scripts/World/Map/MapRoomDataSO.cs
Joywayer e2bc324905 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
2026-05-25 14:44:31 +08:00

158 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using BaseGames.Core.Events;
namespace BaseGames.World.Map
{
/// <summary>
/// 单个房间的地图数据 SO架构 15_MapShopModule §1.1)。
/// 资产路径: Assets/_Game/Data/Map/Rooms/Room_{RoomId}.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/World/Map/RoomData")]
public class MapRoomDataSO : ScriptableObject
{
[Header("基础信息")]
public string RoomId; // 与场景名一致,如 "Room_Forest_01"
public string RegionId; // 所属区域,如 "Forest"
public string DisplayName; // 可选,地图 Tooltip
[Header("地图布局(格子坐标,单位:格)")]
public Vector2Int GridPosition; // 左下角坐标
public Vector2Int GridSize; // 宽×高(格)
[Header("房间轮廓纹理")]
public Texture2D RoomOutlineTex; // 用于地图 UI 显示房间形状(可空,回退到矩形格子)
[Header("出口信息")]
public RoomExitData[] Exits; // 该房间所有出口定义
[Header("特殊标记")]
public bool IsBossRoom;
public bool IsSavePoint;
public bool IsShop;
public Sprite MapIconOverride; // null = 按 isXxx 自动选择图标
[Header("流式加载")]
[Tooltip("此房间场景资产的预估内存KB。\n" +
"在 Profiler 中测量场景实际内存后填入,供流式管理器执行内存预算检查使用。\n" +
"建议在关卡内容基本定型后更新此值。0 = 未填写,将跳过内存预算检查。")]
[Min(0)]
public int EstimatedMemoryKB;
private void OnValidate()
{
// 保证 GridSize 每轴最小为 1防止零尺寸房间导致碰撞和渲染异常
GridSize = new Vector2Int(Mathf.Max(1, GridSize.x), Mathf.Max(1, GridSize.y));
}
}
[Serializable]
public struct RoomExitData
{
public string TargetRoomId; // 连接的目标房间 ID
public Vector2Int ExitGridPos; // 出口在格子地图上的位置
public ExitDirection Direction; // 出口方向
[Tooltip("此出口触发的过渡类型。\n" +
"Seamless无缝切换同区域相邻房间首选\n" +
"AtmosphericFade短暂淡出 + 区域名提示(跨大区域边界首选)。")]
public TransitionType PreferredTransitionType;
}
public enum ExitDirection { Up, Down, Left, Right }
// ─── 全局地图数据库 ──────────────────────────────────────────────────────────
/// <summary>
/// 全局地图数据库 SO编辑器配置一次架构 15_MapShopModule §1.1)。
/// 资产路径: Assets/_Game/Data/Map/MapDatabase.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/World/Map/MapDatabase")]
public class MapDatabaseSO : ScriptableObject
{
public MapRoomDataSO[] AllRooms;
private Dictionary<string, MapRoomDataSO> _index;
/// <summary>运行时快速查找(首次调用时建立索引)。</summary>
public MapRoomDataSO GetRoom(string roomId)
{
if (_index == null)
{
if (AllRooms == null) return null;
_index = AllRooms.Where(r => r != null)
.ToDictionary(r => r.RoomId);
}
_index.TryGetValue(roomId, out var r);
return r;
}
private void OnDisable() => _index = null; // SO 卸载时清理缓存
private void OnValidate() => _index = null; // 编辑器中修改 AllRooms 后强制重建索引
// ── 配置验证 ──────────────────────────────────────────────────────────
#if UNITY_EDITOR
/// <summary>
/// 检查数据库中的常见配置错误RoomId 重复、格子重叠、出口悬空)。
/// 编辑器侧调用;运行时不应调用(有 O(N²) 开销)。
/// 返回错误描述列表;空列表表示无错误。
/// </summary>
public List<string> ValidateAll()
{
var errors = new List<string>();
if (AllRooms == null) return errors;
// ① null / 空 RoomId
for (int i = 0; i < AllRooms.Length; i++)
{
if (AllRooms[i] == null) { errors.Add($"AllRooms[{i}] 为 null"); continue; }
if (string.IsNullOrEmpty(AllRooms[i].RoomId))
errors.Add($"AllRooms[{i}]{AllRooms[i].name}RoomId 为空");
}
// ② RoomId 重复
var seenIds = new Dictionary<string, string>();
foreach (var room in AllRooms)
{
if (room == null || string.IsNullOrEmpty(room.RoomId)) continue;
if (seenIds.TryGetValue(room.RoomId, out var first))
errors.Add($"RoomId '{room.RoomId}' 重复({first} 与 {room.name}");
else
seenIds[room.RoomId] = room.name;
}
// ③ 格子重叠
var cellOwner = new Dictionary<Vector2Int, string>();
foreach (var room in AllRooms)
{
if (room == null) continue;
for (int x = 0; x < room.GridSize.x; x++)
for (int y = 0; y < room.GridSize.y; y++)
{
var cell = new Vector2Int(room.GridPosition.x + x, room.GridPosition.y + y);
if (cellOwner.TryGetValue(cell, out var other))
errors.Add($"'{room.RoomId}' 与 '{other}' 在格子 {cell} 重叠");
else
cellOwner[cell] = room.RoomId;
}
}
// ④ 出口目标不存在(单向验证)
var validIds = new HashSet<string>(seenIds.Keys);
foreach (var room in AllRooms)
{
if (room?.Exits == null) continue;
foreach (var exit in room.Exits)
if (!string.IsNullOrEmpty(exit.TargetRoomId) && !validIds.Contains(exit.TargetRoomId))
errors.Add($"'{room.RoomId}' 出口指向不存在的房间 '{exit.TargetRoomId}'");
}
return errors;
}
#endif
}
}