- Summarized the evolution of scores across five review rounds - Detailed the status of each evaluation dimension post-fixes - Highlighted remaining issues and recommended future work for further enhancements - Compared current system against industry benchmarks
157 lines
6.6 KiB
C#
157 lines
6.6 KiB
C#
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 后强制重建索引
|
||
|
||
// ── 配置验证 ──────────────────────────────────────────────────────────
|
||
|
||
/// <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;
|
||
}
|
||
}
|
||
}
|