摄像机区域的架构改动
This commit is contained in:
19
Assets/_Game/Scripts/World/Map/BaseGames.World.Map.asmdef
Normal file
19
Assets/_Game/Scripts/World/Map/BaseGames.World.Map.asmdef
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"precompiledReferences": [],
|
||||
"name": "BaseGames.World.Map",
|
||||
"defineConstraints": [],
|
||||
"noEngineReferences": false,
|
||||
"versionDefines": [],
|
||||
"rootNamespace": "BaseGames.World.Map",
|
||||
"references": [
|
||||
"BaseGames.World",
|
||||
"BaseGames.Core",
|
||||
"BaseGames.Core.Save",
|
||||
"BaseGames.Core.Events"
|
||||
],
|
||||
"autoReferenced": true,
|
||||
"overrideReferences": false,
|
||||
"includePlatforms": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae09ef3fe95109847963c055501f16bc
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Assets/_Game/Scripts/World/Map/IMapService.cs
Normal file
17
Assets/_Game/Scripts/World/Map/IMapService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Assets/Scripts/World/Map/IMapService.cs
|
||||
// 地图服务接口,通过 ServiceLocator 注册与查询。
|
||||
// MapManager 实现此接口;MapPanel 等调用方通过接口解耦。
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
public interface IMapService
|
||||
{
|
||||
bool IsExplored(string roomId);
|
||||
bool IsMapped(string roomId);
|
||||
void SetMapped(string roomId);
|
||||
MapDatabaseSO Database { get; }
|
||||
|
||||
/// <summary>玩家当前所在区域 ID(最近一次 EVT_RegionChanged 对应的值)。</summary>
|
||||
string CurrentRegionId { get; }
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/IMapService.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/IMapService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce82de7829d7e0141b6811c5f70373b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
107
Assets/_Game/Scripts/World/Map/MapManager.cs
Normal file
107
Assets/_Game/Scripts/World/Map/MapManager.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Core.Events;
|
||||
using BaseGames.Core.Save;
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行时地图管理器(架构 15_MapShopModule §1.2)。
|
||||
/// 挂在 Persistent 场景 [GameManagers] 下,通过事件驱动记录已探索/已完整地图的房间。
|
||||
/// 实现 ISaveable 持久化探索进度。
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-700)]
|
||||
public class MapManager : MonoBehaviour, ISaveable, IMapService
|
||||
{
|
||||
[SerializeField] private MapDatabaseSO _database;
|
||||
|
||||
[Header("Event Channels")]
|
||||
[SerializeField] private StringEventChannelSO _onRoomEntered; // 订阅 EVT_RoomEntered
|
||||
[SerializeField] private StringEventChannelSO _onMapUpdated; // 发布:房间发现时
|
||||
[SerializeField] private StringEventChannelSO _onRegionChanged; // 发布:玩家首次进入新区域时(EVT_RegionChanged)
|
||||
|
||||
// 三级可见性:
|
||||
// Unknown → 未进入过(默认)
|
||||
// Explored → 进入过(显示轮廓/格子)
|
||||
// Mapped → 完整地图信息(购买 MapFragment 或存档点揭示)
|
||||
private HashSet<string> _exploredRooms = new();
|
||||
private HashSet<string> _mappedRooms = new();
|
||||
private string _currentRegionId;
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (ServiceLocator.GetOrDefault<IMapService>() != null) { Destroy(gameObject); return; }
|
||||
ServiceLocator.Register<IMapService>(this);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_onRoomEntered?.Subscribe(OnRoomEntered).AddTo(_subs);
|
||||
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_subs.Clear();
|
||||
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
|
||||
}
|
||||
|
||||
// ── ISaveable ─────────────────────────────────────────────────────────
|
||||
|
||||
public void OnSave(SaveData data)
|
||||
{
|
||||
data.Map.ExploredRooms ??= new List<string>();
|
||||
data.Map.ExploredRooms.Clear();
|
||||
data.Map.ExploredRooms.AddRange(_exploredRooms);
|
||||
data.Map.MappedRooms ??= new List<string>();
|
||||
data.Map.MappedRooms.Clear();
|
||||
data.Map.MappedRooms.AddRange(_mappedRooms);
|
||||
}
|
||||
|
||||
public void OnLoad(SaveData data)
|
||||
{
|
||||
_exploredRooms = new HashSet<string>(data.Map.ExploredRooms ?? new System.Collections.Generic.List<string>());
|
||||
_mappedRooms = new HashSet<string>(data.Map.MappedRooms ?? new System.Collections.Generic.List<string>());
|
||||
}
|
||||
|
||||
// ── 事件驱动房间发现 ──────────────────────────────────────────────────
|
||||
|
||||
private void OnRoomEntered(string roomId)
|
||||
{
|
||||
bool changed = _exploredRooms.Add(roomId);
|
||||
if (changed) _onMapUpdated?.Raise(roomId);
|
||||
|
||||
// 区域变化检测:RegionId 非空且与上一次不同时广播 EVT_RegionChanged
|
||||
var regionId = _database?.GetRoom(roomId)?.RegionId;
|
||||
if (!string.IsNullOrEmpty(regionId) && regionId != _currentRegionId)
|
||||
{
|
||||
_currentRegionId = regionId;
|
||||
_onRegionChanged?.Raise(regionId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>标记为已完整获取地图信息(购买 MapFragment SO 触发)。</summary>
|
||||
public void SetMapped(string roomId)
|
||||
{
|
||||
_exploredRooms.Add(roomId);
|
||||
if (_mappedRooms.Add(roomId))
|
||||
_onMapUpdated?.Raise(roomId);
|
||||
}
|
||||
|
||||
// ── 查询 API ──────────────────────────────────────────────────────────
|
||||
|
||||
public bool IsExplored(string roomId) => _exploredRooms.Contains(roomId);
|
||||
public bool IsMapped(string roomId) => _mappedRooms.Contains(roomId);
|
||||
public string CurrentRegionId => _currentRegionId;
|
||||
|
||||
public MapDatabaseSO Database => _database;
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
ServiceLocator.Unregister<IMapService>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/MapManager.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/MapManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a752b1e0e60f8e41a3b5f7483894d5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
144
Assets/_Game/Scripts/World/Map/MapPanel.cs
Normal file
144
Assets/_Game/Scripts/World/Map/MapPanel.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Core.Events;
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
/// <summary>
|
||||
/// 全屏地图 UI 面板(架构 15_MapShopModule §1.3)。
|
||||
/// 由 UIManager PanelStack 管理开关;OnEnable 时重建格子并订阅更新事件。
|
||||
/// </summary>
|
||||
public class MapPanel : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private MapDatabaseSO _database;
|
||||
[SerializeField] private RectTransform _roomContainer; // 格子图放置根节点
|
||||
[SerializeField] private MapRoomCellUI _cellPrefab; // 地图格子预制
|
||||
|
||||
[Header("图标 Sprites")]
|
||||
[SerializeField] private Sprite _iconSavePoint;
|
||||
[SerializeField] private Sprite _iconBossRoom;
|
||||
[SerializeField] private Sprite _iconShop;
|
||||
[SerializeField] private Sprite _iconPlayerPos;
|
||||
|
||||
[Header("颜色")]
|
||||
[SerializeField] private Color _colorDiscovered = Color.white;
|
||||
[SerializeField] private Color _colorUndiscovered = Color.black;
|
||||
|
||||
[Header("Event Channels")]
|
||||
[SerializeField] private StringEventChannelSO _onMapUpdated; // 房间发现时刷新
|
||||
|
||||
private Dictionary<string, MapRoomCellUI> _cells = new();
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// 首次打开时建立格子;后续打开只刷新探索状态,跳过 N 次 Instantiate
|
||||
if (_cells.Count == 0)
|
||||
BuildGrid();
|
||||
else
|
||||
RefreshAllCells();
|
||||
|
||||
_onMapUpdated?.Subscribe(OnMapUpdated).AddTo(_subs);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_subs.Clear();
|
||||
// 格子保留,不销毁——随面板 GameObject 一同隐藏
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 面板真正销毁时才清理格子
|
||||
foreach (var cell in _cells.Values)
|
||||
if (cell != null) Destroy(cell.gameObject);
|
||||
_cells.Clear();
|
||||
}
|
||||
|
||||
// 面板重新打开时同步关闭期间积累的探索进度
|
||||
private void RefreshAllCells()
|
||||
{
|
||||
var mapManager = ServiceLocator.GetOrDefault<IMapService>();
|
||||
foreach (var (roomId, cell) in _cells)
|
||||
{
|
||||
if (cell == null) continue;
|
||||
bool discovered = mapManager != null && mapManager.IsExplored(roomId);
|
||||
cell.SetDiscovered(discovered);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 内部 ──────────────────────────────────────────────────────────────
|
||||
|
||||
private void BuildGrid()
|
||||
{
|
||||
if (_database == null || _database.AllRooms == null) return;
|
||||
|
||||
var mapManager = ServiceLocator.GetOrDefault<IMapService>();
|
||||
foreach (var room in _database.AllRooms)
|
||||
{
|
||||
if (room == null) continue;
|
||||
var cell = Instantiate(_cellPrefab, _roomContainer);
|
||||
bool discovered = mapManager != null && mapManager.IsExplored(room.RoomId);
|
||||
cell.Setup(room, discovered, ChooseIcon(room));
|
||||
_cells[room.RoomId] = cell;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMapUpdated(string roomId)
|
||||
{
|
||||
if (_cells.TryGetValue(roomId, out var cell))
|
||||
cell.SetDiscovered(true);
|
||||
}
|
||||
|
||||
private Sprite ChooseIcon(MapRoomDataSO room)
|
||||
{
|
||||
if (room.MapIconOverride != null) return room.MapIconOverride;
|
||||
if (room.IsSavePoint) return _iconSavePoint;
|
||||
if (room.IsBossRoom) return _iconBossRoom;
|
||||
if (room.IsShop) return _iconShop;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 单个地图格子 UI ─────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>地图面板中每个房间对应的格子 UI 组件。</summary>
|
||||
public class MapRoomCellUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Image _bg;
|
||||
[SerializeField] private Image _icon;
|
||||
|
||||
private static readonly Color Discovered = Color.white;
|
||||
private static readonly Color Undiscovered = Color.black;
|
||||
|
||||
/// <summary>初始化格子(位置、颜色、图标)。</summary>
|
||||
public void Setup(MapRoomDataSO room, bool discovered, Sprite icon)
|
||||
{
|
||||
// 根据 GridPosition/GridSize 设置 RectTransform 位置与大小
|
||||
if (TryGetComponent<RectTransform>(out var rt))
|
||||
{
|
||||
rt.anchoredPosition = new Vector2(
|
||||
room.GridPosition.x * 32f,
|
||||
room.GridPosition.y * 32f);
|
||||
rt.sizeDelta = new Vector2(
|
||||
room.GridSize.x * 32f,
|
||||
room.GridSize.y * 32f);
|
||||
}
|
||||
|
||||
SetDiscovered(discovered);
|
||||
|
||||
if (_icon != null)
|
||||
{
|
||||
_icon.sprite = icon;
|
||||
_icon.enabled = icon != null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDiscovered(bool v)
|
||||
{
|
||||
if (_bg != null) _bg.color = v ? Discovered : Undiscovered;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/MapPanel.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/MapPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9677e71b6b3d4d43aa3680aa8990a83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
Assets/_Game/Scripts/World/Map/MapPin.cs
Normal file
52
Assets/_Game/Scripts/World/Map/MapPin.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Core.Save;
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
/// <summary>
|
||||
/// 地图自定义标记管理器(架构 15_MapShopModule §1.5)。
|
||||
/// 实现 ISaveable,通过 SaveManager 持久化玩家地图标记。
|
||||
/// MapPin/PinType 数据类定义在 SaveData.cs(BaseGames.Core.Save)中,避免循环依赖。
|
||||
/// </summary>
|
||||
public class MapPinManager : MonoBehaviour, ISaveable
|
||||
{
|
||||
private List<MapPin> _pins = new();
|
||||
|
||||
public IReadOnlyList<MapPin> Pins => _pins;
|
||||
|
||||
private void OnEnable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
|
||||
private void OnDisable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
|
||||
|
||||
// ── 公共 API ──────────────────────────────────────────────────────────
|
||||
|
||||
public void AddPin(MapPin pin)
|
||||
{
|
||||
if (pin != null) _pins.Add(pin);
|
||||
}
|
||||
|
||||
public void RemovePin(MapPin pin) => _pins.Remove(pin);
|
||||
|
||||
/// <summary>便捷方法:用枚举类型创建并添加标记。</summary>
|
||||
public MapPin CreatePin(string roomId, float normX, float normY,
|
||||
PinType type = PinType.Marker, string note = "")
|
||||
{
|
||||
var pin = new MapPin
|
||||
{
|
||||
RoomId = roomId,
|
||||
NormalizedPosX = normX,
|
||||
NormalizedPosY = normY,
|
||||
PinTypeInt = (int)type,
|
||||
Note = note,
|
||||
};
|
||||
AddPin(pin);
|
||||
return pin;
|
||||
}
|
||||
|
||||
// ── ISaveable ─────────────────────────────────────────────────────────
|
||||
|
||||
public void OnSave(SaveData data) => data.Map.Pins = _pins;
|
||||
public void OnLoad(SaveData data) => _pins = data.Map.Pins ?? new List<MapPin>();
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/MapPin.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/MapPin.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d5b16698a16d38428ae6c836d5c4536
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
Assets/_Game/Scripts/World/Map/MapPlayerTracker.cs
Normal file
55
Assets/_Game/Scripts/World/Map/MapPlayerTracker.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
/// <summary>
|
||||
/// 将玩家世界坐标转换为地图格子坐标,供 MapPanel 显示玩家位置图标(架构 15_MapShopModule §1.4)。
|
||||
/// 挂在 Player GameObject 上(LateUpdate 每帧计算)。
|
||||
/// </summary>
|
||||
public class MapPlayerTracker : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform _playerTransform;
|
||||
[SerializeField] private MapDatabaseSO _database;
|
||||
|
||||
[Header("世界坐标 → 格子坐标换算参数")]
|
||||
[SerializeField] private float _worldUnitsPerCell = 18f; // 1 格 = N 世界单位
|
||||
|
||||
/// <summary>玩家当前所在房间 ID(用于地图高亮当前房间)。</summary>
|
||||
public string CurrentRoomId { get; private set; }
|
||||
|
||||
/// <summary>玩家在当前格子房间内的归一化坐标(0~1)。</summary>
|
||||
public Vector2 NormalizedPositionInRoom { get; private set; }
|
||||
|
||||
// 缓存上一帧的格子坐标;格子不变则跳过 O(N) 搜索
|
||||
private Vector2Int _lastCellPos = new Vector2Int(int.MinValue, int.MinValue);
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_playerTransform == null || _database?.AllRooms == null) return;
|
||||
|
||||
Vector2Int cellPos = WorldToCell(_playerTransform.position);
|
||||
if (cellPos == _lastCellPos) return; // 格子未变,无需重新搜索
|
||||
_lastCellPos = cellPos;
|
||||
|
||||
foreach (var room in _database.AllRooms)
|
||||
{
|
||||
if (room == null) continue;
|
||||
var rect = new RectInt(room.GridPosition, room.GridSize);
|
||||
if (rect.Contains(cellPos))
|
||||
{
|
||||
CurrentRoomId = room.RoomId;
|
||||
Vector2 inRoom = (Vector2)(cellPos - room.GridPosition);
|
||||
NormalizedPositionInRoom = new Vector2(
|
||||
inRoom.x / Mathf.Max(1, room.GridSize.x),
|
||||
inRoom.y / Mathf.Max(1, room.GridSize.y));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2Int WorldToCell(Vector2 worldPos)
|
||||
=> new(
|
||||
Mathf.FloorToInt(worldPos.x / _worldUnitsPerCell),
|
||||
Mathf.FloorToInt(worldPos.y / _worldUnitsPerCell));
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/MapPlayerTracker.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/MapPlayerTracker.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f3715a3378c2004a89bc0ee56ca25c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
72
Assets/_Game/Scripts/World/Map/MapRoomDataSO.cs
Normal file
72
Assets/_Game/Scripts/World/Map/MapRoomDataSO.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.World.Map
|
||||
{
|
||||
/// <summary>
|
||||
/// 单个房间的地图数据 SO(架构 15_MapShopModule §1.1)。
|
||||
/// 资产路径: Assets/ScriptableObjects/Map/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 自动选择图标
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct RoomExitData
|
||||
{
|
||||
public string TargetRoomId; // 连接的目标房间 ID
|
||||
public Vector2Int ExitGridPos; // 出口在格子地图上的位置
|
||||
public ExitDirection Direction; // 出口方向
|
||||
}
|
||||
|
||||
public enum ExitDirection { Up, Down, Left, Right }
|
||||
|
||||
// ─── 全局地图数据库 ──────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 全局地图数据库 SO(编辑器配置一次;架构 15_MapShopModule §1.1)。
|
||||
/// 资产路径: Assets/ScriptableObjects/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)
|
||||
_index = AllRooms.Where(r => r != null)
|
||||
.ToDictionary(r => r.RoomId);
|
||||
_index.TryGetValue(roomId, out var r);
|
||||
return r;
|
||||
}
|
||||
|
||||
private void OnDisable() => _index = null; // SO 卸载时清理缓存
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/World/Map/MapRoomDataSO.cs.meta
Normal file
11
Assets/_Game/Scripts/World/Map/MapRoomDataSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00cffb59dd3827e41acf0e7697861b11
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user