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.
This commit is contained in:
@@ -30,6 +30,8 @@ namespace BaseGames.World.Map
|
||||
[SerializeField] private Sprite _iconBossRoom;
|
||||
[SerializeField] private Sprite _iconShop;
|
||||
[SerializeField] private Sprite _iconPlayerPos;
|
||||
[Tooltip("传送站图标;房间含 TeleportStation 标志时显示。")]
|
||||
[SerializeField] private Sprite _iconTeleport;
|
||||
|
||||
[Header("颜色")]
|
||||
[SerializeField] private Color _colorExplored = Color.white;
|
||||
@@ -40,79 +42,137 @@ namespace BaseGames.World.Map
|
||||
[SerializeField] private Image _playerIconImg; // _roomContainer 内的玩家图标
|
||||
|
||||
[Header("地图标记")]
|
||||
[SerializeField] private Image _pinPrefab;
|
||||
[SerializeField] private PinSpriteEntry[] _pinSprites; // PinType → 对应 Sprite(在 Inspector 中配置)
|
||||
[SerializeField] private Image _pinPrefab;
|
||||
[SerializeField] private MapPinConfigSO _pinConfig; // R12-N3 集中 PinType→Sprite 映射,替代旧的 PinSpriteEntry[]
|
||||
|
||||
[Header("房间解锁动画")]
|
||||
[SerializeField] private Color _revealFlashColor = Color.white; // R12-FC 新房间发现时的闪光颜色
|
||||
[SerializeField] private float _revealDuration = 0.4f; // R12-FC 淡出动画持续时间(秒)
|
||||
|
||||
[Header("Tooltip")]
|
||||
[SerializeField] private GameObject _tooltipPanel;
|
||||
[SerializeField] private TMP_Text _tooltipText;
|
||||
|
||||
[Header("Event Channels")]
|
||||
[SerializeField] private StringEventChannelSO _onMapUpdated; // 房间发现/标注时刷新
|
||||
[HideInInspector, SerializeField] private StringEventChannelSO _onMapUpdated; // 已废弃,仅保留序列化兼容性(R12-N8)
|
||||
|
||||
private Dictionary<string, MapRoomCellUI> _cells = new();
|
||||
private List<Image> _pinImages = new();
|
||||
private List<Image> _exitImages= new();
|
||||
private readonly Dictionary<string, MapRoomCellUI> _cells = new();
|
||||
private readonly List<Image> _pinImages = new();
|
||||
private readonly Stack<Image> _pinPool = new(); // R10-N3 Pin 对象池,回收而非销毁
|
||||
private readonly Stack<MapRoomCellUI> _cellPool = new(); // R12-N1 Cell 对象池,BuildGrid/OnDestroy 共用
|
||||
private readonly Stack<Image> _exitPool = new(); // R12-N1 Exit connector 对象池
|
||||
private readonly List<Image> _exitImages= new();
|
||||
private readonly Dictionary<string, Coroutine> _revealCoroutines = new(); // R19-N2 跟踪进行中的发现动画协程
|
||||
private string _highlightedRoomId;
|
||||
private string _lastIconRoomId; // LateUpdate 脏标记
|
||||
private Vector2 _lastIconNormPos; // LateUpdate 脏标记
|
||||
private int _lastPinVersion = -1;
|
||||
private bool _databaseDirty; // R10-N1 关闭期间收到 OnDatabaseChanged → 下次 OnEnable 触发重建
|
||||
private bool _explorationDirty; // R10-N12 关闭期间收到 OnExplorationChanged → 下次 OnEnable RefreshAllCells
|
||||
private bool _servicesReady; // R12-N7 三个服务全部就绪后置 true,短路 LateUpdate 的每帧查询
|
||||
|
||||
private IMapService _mapSvc;
|
||||
private IPlayerPositionProvider _playerProvider;
|
||||
private IPinService _pinService;
|
||||
private Dictionary<PinType, Sprite> _pinSpriteDict;
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 预构建 PinType → Sprite 字典,将 GetPinSprite 从 O(N) 降至 O(1)
|
||||
_pinSpriteDict = new Dictionary<PinType, Sprite>();
|
||||
if (_pinSprites != null)
|
||||
foreach (var e in _pinSprites)
|
||||
_pinSpriteDict[e.PinType] = e.Sprite;
|
||||
// R10-N1 服务订阅在 Awake/OnDestroy 长期持有:即便面板关闭也能感知数据库变更,
|
||||
// 设置 dirty 标志后由 OnEnable 触发重建,避免错过事件导致下次打开仍展示陈旧布局。
|
||||
SubscribeServices();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_mapSvc = ServiceLocator.GetOrDefault<IMapService>();
|
||||
_playerProvider = ServiceLocator.GetOrDefault<IPlayerPositionProvider>();
|
||||
_pinService = ServiceLocator.GetOrDefault<IPinService>();
|
||||
// 若服务在 Awake 时还未注册(启动顺序),此处补订阅
|
||||
SubscribeServices();
|
||||
|
||||
// 首次打开时建立格子;后续打开只刷新探索状态,跳过重复 Instantiate
|
||||
if (_cells.Count == 0)
|
||||
BuildGrid();
|
||||
else
|
||||
else if (_databaseDirty)
|
||||
RebuildAll();
|
||||
else if (_explorationDirty)
|
||||
RefreshAllCells();
|
||||
|
||||
_databaseDirty = _explorationDirty = false;
|
||||
|
||||
RenderPins();
|
||||
UpdatePlayerIcon();
|
||||
CenterOnCurrentRoom();
|
||||
_onMapUpdated?.Subscribe(OnMapUpdated).AddTo(_subs);
|
||||
// R12-N8:移除 _onMapUpdated 订阅,避免与 OnExplorationChanged 双重刷新;
|
||||
// _onMapUpdated 字段保留但标记 HideInInspector,防止旧 Prefab 数据丢失。
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_subs.Clear();
|
||||
_mapSvc = null;
|
||||
_playerProvider = null;
|
||||
_pinService = null;
|
||||
_lastIconRoomId = null;
|
||||
_lastIconNormPos = Vector2.zero;
|
||||
HideTooltip();
|
||||
// R10-N1 保持 _mapSvc 等订阅引用,监听器在 Awake 已挂;不再置空
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
UnsubscribeServices();
|
||||
foreach (var cell in _cells.Values)
|
||||
if (cell != null) Destroy(cell.gameObject);
|
||||
_cells.Clear();
|
||||
ClearPins();
|
||||
foreach (var img in _pinPool)
|
||||
if (img != null) Destroy(img.gameObject);
|
||||
_pinPool.Clear();
|
||||
ClearExits();
|
||||
// R12-N1 销毁对象池中的格子和出口连接线
|
||||
foreach (var cell in _cellPool)
|
||||
if (cell != null) Destroy(cell.gameObject);
|
||||
_cellPool.Clear();
|
||||
foreach (var img in _exitPool)
|
||||
if (img != null) Destroy(img.gameObject);
|
||||
_exitPool.Clear();
|
||||
}
|
||||
|
||||
/// <summary>统一订阅服务的 OnDatabaseChanged / OnExplorationChanged / OnRoomMapped 事件。</summary>
|
||||
private void SubscribeServices()
|
||||
{
|
||||
if (_servicesReady) return; // R12-N7 三服务全部就绪后短路
|
||||
if (_mapSvc == null)
|
||||
{
|
||||
_mapSvc = ServiceLocator.GetOrDefault<IMapService>();
|
||||
if (_mapSvc != null)
|
||||
{
|
||||
_mapSvc.OnDatabaseChanged += OnDatabaseChanged;
|
||||
_mapSvc.OnExplorationChanged += OnExplorationChanged;
|
||||
_mapSvc.OnRoomMapped += OnRoomMappedAnim;
|
||||
}
|
||||
}
|
||||
_playerProvider ??= ServiceLocator.GetOrDefault<IPlayerPositionProvider>();
|
||||
_pinService ??= ServiceLocator.GetOrDefault<IPinService>();
|
||||
if (_mapSvc != null && _playerProvider != null && _pinService != null)
|
||||
_servicesReady = true;
|
||||
}
|
||||
|
||||
private void UnsubscribeServices()
|
||||
{
|
||||
// 仅在 OnDestroy 调用,生命周期末尾服务引用不需要清空(与 MinimapHUD.UnsubscribeServices 的有意差异:
|
||||
// MinimapHUD 是持久 HUD,需支持跨场景销毁/重建后重连;MapPanel 由 UIManager 管理,
|
||||
// OnDestroy 后不再重用,服务引用随对象销毁自然回收)。
|
||||
if (_mapSvc != null)
|
||||
{
|
||||
_mapSvc.OnDatabaseChanged -= OnDatabaseChanged;
|
||||
_mapSvc.OnExplorationChanged -= OnExplorationChanged;
|
||||
_mapSvc.OnRoomMapped -= OnRoomMappedAnim;
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
// R12-N7 服务懒加载:_servicesReady 置 true 后短路,消除每帧 ServiceLocator 查询
|
||||
if (!_servicesReady)
|
||||
SubscribeServices();
|
||||
|
||||
// Pin 增删响应:基于 PinsVersion 脏检查,版本未变化时 RenderPins 立即 return,无开销
|
||||
RenderPins();
|
||||
|
||||
if (_playerProvider == null || _playerIconImg == null) return;
|
||||
// 脏标记:位置/房间未变化时跳过 RectTransform 读写,消除无效每帧开销
|
||||
if (_playerProvider.CurrentRoomId == _lastIconRoomId &&
|
||||
@@ -122,6 +182,67 @@ namespace BaseGames.World.Map
|
||||
UpdatePlayerIcon();
|
||||
}
|
||||
|
||||
/// <summary>数据库结构变更:禁用状态置 dirty,启用状态立即重建。</summary>
|
||||
private void OnDatabaseChanged()
|
||||
{
|
||||
if (!isActiveAndEnabled) { _databaseDirty = true; return; }
|
||||
RebuildAll();
|
||||
}
|
||||
|
||||
/// <summary>R10-N12 探索进度变化:仅刷新格子可见性,不重建结构(轻量级)。</summary>
|
||||
private void OnExplorationChanged()
|
||||
{
|
||||
if (!isActiveAndEnabled) { _explorationDirty = true; return; }
|
||||
RefreshAllCells();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// R12-FC 房间被标 Mapped 时播放发现动画(格子存在才播放)。
|
||||
/// R19-N2 先停止该房间的旧协程,防止 RebuildAll 把格子回收后协程继续写颜色。
|
||||
/// R20-N1 通过 RunRevealAnim 包装协程,动画完成后自动从 _revealCoroutines 移除,
|
||||
/// 消除已完成协程引用在字典中积累至下次 RebuildAll 的问题。
|
||||
/// </summary>
|
||||
protected virtual void OnRoomMappedAnim(string roomId)
|
||||
{
|
||||
if (!_cells.TryGetValue(roomId, out var cell) || cell == null) return;
|
||||
|
||||
if (_revealCoroutines.TryGetValue(roomId, out var old) && old != null)
|
||||
StopCoroutine(old);
|
||||
|
||||
_revealCoroutines[roomId] = StartCoroutine(RunRevealAnim(roomId, cell));
|
||||
}
|
||||
|
||||
private IEnumerator RunRevealAnim(string roomId, MapRoomCellUI cell)
|
||||
{
|
||||
yield return cell.PlayRevealAnim(_revealFlashColor, _revealDuration);
|
||||
_revealCoroutines.Remove(roomId); // R20-N1 完成后自清理,避免过期引用积累
|
||||
}
|
||||
|
||||
private void RebuildAll()
|
||||
{
|
||||
// R19-N2 在格子回收前停止所有进行中的发现动画协程,防止协程写入已入池的格子
|
||||
foreach (var c in _revealCoroutines.Values)
|
||||
if (c != null) StopCoroutine(c);
|
||||
_revealCoroutines.Clear();
|
||||
|
||||
foreach (var cell in _cells.Values)
|
||||
{
|
||||
if (cell == null) continue;
|
||||
// R12-N1 入池而非销毁
|
||||
cell.gameObject.SetActive(false);
|
||||
_cellPool.Push(cell);
|
||||
}
|
||||
_cells.Clear();
|
||||
ClearExits();
|
||||
ClearPins();
|
||||
_lastPinVersion = -1;
|
||||
_highlightedRoomId = null;
|
||||
BuildGrid();
|
||||
RenderPins();
|
||||
UpdatePlayerIcon();
|
||||
CenterOnCurrentRoom();
|
||||
}
|
||||
|
||||
// 面板重新打开时同步关闭期间积累的探索进度
|
||||
private void RefreshAllCells()
|
||||
{
|
||||
@@ -141,13 +262,28 @@ namespace BaseGames.World.Map
|
||||
foreach (var room in db.AllRooms)
|
||||
{
|
||||
if (room == null) continue;
|
||||
var cell = Instantiate(_cellPrefab, _roomContainer);
|
||||
// R12-N1 优先从对象池取格子,避免高频 Instantiate/Destroy
|
||||
MapRoomCellUI cell;
|
||||
if (_cellPool.Count > 0)
|
||||
{
|
||||
cell = _cellPool.Pop();
|
||||
cell.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cell = Instantiate(_cellPrefab, _roomContainer);
|
||||
}
|
||||
cell.Setup(room, _mapSvc.GetVisibility(room.RoomId), ChooseIcon(room),
|
||||
ShowTooltip, HideTooltip);
|
||||
// R11-N8 布局单独调用 SetGridLayout,与 MinimapHUD.PlaceCell 职责对称
|
||||
cell.SetGridLayout(room, MapGridConstants.FullMapCellPixels);
|
||||
cell.SetColors(_colorExplored, _colorMapped, _colorUnknown);
|
||||
_cells[room.RoomId] = cell;
|
||||
}
|
||||
DrawExits();
|
||||
// R11-N4 格子布局改变后统一重建一次,CenterOnCurrentRoom 不再重复调用
|
||||
if (_scrollRect != null)
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(_scrollRect.content);
|
||||
}
|
||||
|
||||
/// <summary>为每条出口在格子坐标处实例化一个小矩形连接线图像。</summary>
|
||||
@@ -161,10 +297,24 @@ namespace BaseGames.World.Map
|
||||
if (room?.Exits == null) continue;
|
||||
foreach (var exit in room.Exits)
|
||||
{
|
||||
var conn = Instantiate(_exitConnectorPrefab, _roomContainer);
|
||||
// R12-N1 优先从对象池取连接线
|
||||
Image conn;
|
||||
if (_exitPool.Count > 0)
|
||||
{
|
||||
conn = _exitPool.Pop();
|
||||
conn.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
conn = Instantiate(_exitConnectorPrefab, _roomContainer);
|
||||
}
|
||||
// R13-N1 检查 HasCustomExitPos;未配置时按出口方向计算房间边缘中点,避免落在 (0,0)
|
||||
Vector2Int gridPos = exit.HasCustomExitPos
|
||||
? exit.ExitGridPos
|
||||
: GetExitFallbackGridPos(room, exit);
|
||||
conn.rectTransform.anchoredPosition = new Vector2(
|
||||
exit.ExitGridPos.x * MapGridConstants.FullMapCellPixels,
|
||||
exit.ExitGridPos.y * MapGridConstants.FullMapCellPixels);
|
||||
gridPos.x * MapGridConstants.FullMapCellPixels,
|
||||
gridPos.y * MapGridConstants.FullMapCellPixels);
|
||||
bool vertical = exit.Direction == ExitDirection.Up || exit.Direction == ExitDirection.Down;
|
||||
conn.rectTransform.sizeDelta = vertical ? new Vector2(16f, 8f) : new Vector2(8f, 16f);
|
||||
_exitImages.Add(conn);
|
||||
@@ -174,16 +324,18 @@ namespace BaseGames.World.Map
|
||||
|
||||
private void ClearExits()
|
||||
{
|
||||
// R12-N1 禁用入池而非销毁
|
||||
foreach (var img in _exitImages)
|
||||
if (img != null) Destroy(img.gameObject);
|
||||
{
|
||||
if (img == null) continue;
|
||||
img.gameObject.SetActive(false);
|
||||
_exitPool.Push(img);
|
||||
}
|
||||
_exitImages.Clear();
|
||||
}
|
||||
|
||||
private void OnMapUpdated(string roomId)
|
||||
{
|
||||
if (_cells.TryGetValue(roomId, out var cell))
|
||||
cell.SetVisibility(_mapSvc.GetVisibility(roomId));
|
||||
}
|
||||
[Obsolete("R12-N8: 由 OnExplorationChanged 统一处理,此方法仅保留序列化兼容性,请勿新增调用。")]
|
||||
private void OnMapUpdated(string roomId) { /* R12-N8 已废弃:由 OnExplorationChanged 统一处理,此方法保留避免序列化引用问题 */ }
|
||||
|
||||
// ── 玩家位置图标 ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -202,6 +354,8 @@ namespace BaseGames.World.Map
|
||||
_playerIconImg.rectTransform.anchoredPosition =
|
||||
cell.RT.anchoredPosition
|
||||
+ Vector2.Scale(_playerProvider.NormalizedPositionInRoom, cell.RT.sizeDelta);
|
||||
// 强制玩家图标渲染在所有格子/出口连线/Pin 之上,避免 Prefab 中层级配置错误导致被遮挡
|
||||
_playerIconImg.transform.SetAsLastSibling();
|
||||
UpdateCellHighlight(roomId);
|
||||
}
|
||||
|
||||
@@ -218,16 +372,22 @@ namespace BaseGames.World.Map
|
||||
next.SetHighlight(true);
|
||||
}
|
||||
|
||||
/// <summary>面板打开时将 ScrollRect 视口居中到玩家当前所在房间。</summary>
|
||||
private void CenterOnCurrentRoom()
|
||||
/// <summary>
|
||||
/// 当前地图缩放系数(从 _roomContainer.localScale.x 读取)。
|
||||
/// 供 MapInputHandler 使用以消除双份状态:MapInputHandler._zoom 写入 _roomContainer,
|
||||
/// CenterOnCurrentRoom 与 Update 均从此属性读取,保证两处始终一致。
|
||||
/// </summary>
|
||||
public float CurrentZoom => _roomContainer != null ? _roomContainer.localScale.x : 1f;
|
||||
|
||||
/// <summary>将 ScrollRect 视口居中到玩家当前所在房间。可由外部(如 MapInputHandler)调用。</summary>
|
||||
public void CenterOnCurrentRoom()
|
||||
{
|
||||
if (_scrollRect == null || _playerProvider == null) return;
|
||||
var roomId = _playerProvider.CurrentRoomId;
|
||||
if (string.IsNullOrEmpty(roomId) || !_cells.TryGetValue(roomId, out var cell)) return;
|
||||
|
||||
// 仅重建 ScrollRect.content 的布局,避免全 Canvas 树强制刷新
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(_scrollRect.content);
|
||||
|
||||
// R11-N4 不再在此调用 ForceRebuildLayoutImmediate(已移至 BuildGrid 末尾);
|
||||
// 直接从 cell.RT 读取位置——格子由 Setup 手动定位,无需 LayoutGroup 重建。
|
||||
var content = _scrollRect.content;
|
||||
var viewport = _scrollRect.viewport != null
|
||||
? _scrollRect.viewport
|
||||
@@ -243,11 +403,14 @@ namespace BaseGames.World.Map
|
||||
|
||||
Vector2 viewSize = viewport.rect.size;
|
||||
Vector2 contentSize = content.rect.size;
|
||||
float rangeX = contentSize.x - viewSize.x;
|
||||
float rangeY = contentSize.y - viewSize.y;
|
||||
// R18-N1 / R19-N1 使用 CurrentZoom 属性(读取 _roomContainer.localScale.x);
|
||||
// 缩放后实际可滚动范围 = contentSize * zoom - viewSize,同步修正 cellX/cellY 的像素偏移。
|
||||
float zoom = CurrentZoom;
|
||||
float rangeX = contentSize.x * zoom - viewSize.x;
|
||||
float rangeY = contentSize.y * zoom - viewSize.y;
|
||||
|
||||
float normX = rangeX > 0 ? Mathf.Clamp01((cellX - viewSize.x * 0.5f) / rangeX) : 0.5f;
|
||||
float normY = rangeY > 0 ? Mathf.Clamp01((cellY - viewSize.y * 0.5f) / rangeY) : 0.5f;
|
||||
float normX = rangeX > 0 ? Mathf.Clamp01((cellX * zoom - viewSize.x * 0.5f) / rangeX) : 0.5f;
|
||||
float normY = rangeY > 0 ? Mathf.Clamp01((cellY * zoom - viewSize.y * 0.5f) / rangeY) : 0.5f;
|
||||
|
||||
_scrollRect.normalizedPosition = new Vector2(normX, normY);
|
||||
}
|
||||
@@ -259,7 +422,8 @@ namespace BaseGames.World.Map
|
||||
if (_pinService == null) return;
|
||||
|
||||
// 版本号脏检查:Pin 集合未变化时跳过重绘,避免无效 Instantiate
|
||||
if (_pinService.PinsVersion == _lastPinVersion && _pinImages.Count > 0) return;
|
||||
// 初始值 -1 保证首次 RenderPins 必然执行
|
||||
if (_pinService.PinsVersion == _lastPinVersion) return;
|
||||
_lastPinVersion = _pinService.PinsVersion;
|
||||
|
||||
ClearPins();
|
||||
@@ -267,7 +431,17 @@ namespace BaseGames.World.Map
|
||||
foreach (var pin in _pinService.Pins)
|
||||
{
|
||||
if (!_cells.TryGetValue(pin.RoomId, out var cell)) continue;
|
||||
var img = Instantiate(_pinPrefab, _roomContainer);
|
||||
// R10-N3 优先复用对象池中的 Pin Image,避免高频 Instantiate
|
||||
Image img;
|
||||
if (_pinPool.Count > 0)
|
||||
{
|
||||
img = _pinPool.Pop();
|
||||
img.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
img = Instantiate(_pinPrefab, _roomContainer);
|
||||
}
|
||||
img.sprite = GetPinSprite((PinType)pin.PinTypeInt);
|
||||
img.rectTransform.anchoredPosition =
|
||||
cell.RT.anchoredPosition + new Vector2(
|
||||
@@ -279,8 +453,13 @@ namespace BaseGames.World.Map
|
||||
|
||||
private void ClearPins()
|
||||
{
|
||||
// R10-N3 禁用入池而非销毁,减少 GC 与下次创建开销
|
||||
foreach (var img in _pinImages)
|
||||
if (img != null) Destroy(img.gameObject);
|
||||
{
|
||||
if (img == null) continue;
|
||||
img.gameObject.SetActive(false);
|
||||
_pinPool.Push(img);
|
||||
}
|
||||
_pinImages.Clear();
|
||||
}
|
||||
|
||||
@@ -298,15 +477,28 @@ namespace BaseGames.World.Map
|
||||
// ── 辅助方法 ──────────────────────────────────────────────────────────
|
||||
|
||||
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;
|
||||
}
|
||||
// R20-N2 委托到 MapRoomDataSO.ChooseDisplayIcon,消除与 MinimapHUD 的重复实现
|
||||
=> room.ChooseDisplayIcon(_iconSavePoint, _iconBossRoom, _iconShop, _iconTeleport);
|
||||
|
||||
private Sprite GetPinSprite(PinType type)
|
||||
=> _pinSpriteDict.TryGetValue(type, out var s) ? s : null;
|
||||
=> _pinConfig != null ? _pinConfig.GetSprite(type) : null;
|
||||
|
||||
/// <summary>
|
||||
/// R13-N1 当出口未配置自定义坐标时,按 ExitDirection 推算房间边缘中点。
|
||||
/// 避免 ExitGridPos 默认 (0,0) 导致所有连接线渲染到容器原点。
|
||||
/// </summary>
|
||||
private static Vector2Int GetExitFallbackGridPos(MapRoomDataSO room, RoomExitData exit)
|
||||
=> exit.Direction switch
|
||||
{
|
||||
ExitDirection.Up => new Vector2Int(room.GridPosition.x + room.GridSize.x / 2,
|
||||
room.GridPosition.y + room.GridSize.y),
|
||||
ExitDirection.Down => new Vector2Int(room.GridPosition.x + room.GridSize.x / 2,
|
||||
room.GridPosition.y),
|
||||
ExitDirection.Right => new Vector2Int(room.GridPosition.x + room.GridSize.x,
|
||||
room.GridPosition.y + room.GridSize.y / 2),
|
||||
ExitDirection.Left => new Vector2Int(room.GridPosition.x,
|
||||
room.GridPosition.y + room.GridSize.y / 2),
|
||||
_ => room.GridPosition + room.GridSize / 2,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user