using System; using System.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; namespace BaseGames.World.Map { /// 房间可见性三级状态:未知 / 已踏入 / 已标注(购买地图碎片)。 public enum RoomVisibility { Unknown, Explored, Mapped } /// /// 地图面板中每个房间对应的格子 UI 组件(架构 15_MapShopModule §1.3)。 /// 同时被 MapPanel(全屏地图)和 MinimapHUD(角落小地图)复用。 /// 颜色通过 从外部注入,不在此处硬编码。 /// 属性在 Awake 中缓存,避免调用方反复 GetComponent。 /// public class MapRoomCellUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler { [SerializeField] private Image _bg; [SerializeField] private Image _icon; [SerializeField] private RawImage _outlineImage; // 可选:房间非矩形轮廓纹理 [SerializeField] private Image _highlight; // 可选:当前房间高亮描边(玩家所在时激活) [SerializeField] private Image _fogOverlay; // 可选:未知房间雾效覆盖层(R12-FD) [SerializeField] private Image _teleportMarker;// 可选:可传送站点标记(CanTeleportTo 为真时激活) // 实例颜色(默认值与原硬编码保持一致);可通过 SetColors 统一覆盖 private Color _colExplored = Color.white; private Color _colMapped = new Color(0.45f, 0.45f, 0.45f, 1f); private Color _colUnknown = Color.black; private RoomVisibility _currentVisibility; private string _displayName; private string _roomId; // 供点击回调携带(传送选择) private Action _onHover; private Action _onHoverExit; private Action _onClick; // 点击回调(传送选择),由 MapPanel 注入 /// 格子的 RectTransform(Awake 中缓存,外部直接访问无需 GetComponent)。 public RectTransform RT { get; private set; } private void Awake() => RT = GetComponent(); /// /// 初始化格子(可见性、图标、Tooltip 回调)。 /// R11-N8:不再在 Setup 中设置位置/尺寸,调用方按需调用 /// 或直接操作 /// public void Setup(MapRoomDataSO room, RoomVisibility visibility, Sprite icon, Action onHover = null, Action onHoverExit = null) { _displayName = room.DisplayName; _roomId = room.RoomId; _onHover = onHover; _onHoverExit = onHoverExit; // 房间轮廓纹理(非矩形形状,覆盖在矩形背景上方) if (_outlineImage != null) { _outlineImage.texture = room.RoomOutlineTex; _outlineImage.enabled = room.RoomOutlineTex != null; } SetVisibility(visibility); if (_icon != null) { _icon.sprite = icon; _icon.enabled = icon != null; } } /// /// R11-N8 独立布局接口:根据房间格子坐标与单格像素数设定位置和尺寸。 /// MapPanel.BuildGrid 与 MinimapHUD.PlaceCell 均通过此接口定位, /// 两者互不干扰,消除 Setup 中的重复赋值。 /// public void SetGridLayout(MapRoomDataSO room, float pixelsPerCell) { RT.anchoredPosition = new Vector2(room.GridPosition.x * pixelsPerCell, room.GridPosition.y * pixelsPerCell); RT.sizeDelta = new Vector2(room.GridSize.x * pixelsPerCell, room.GridSize.y * pixelsPerCell); } /// 覆盖此格子的三级可见性颜色(通常由 MapPanel / MinimapHUD 在创建后统一调用)。 public void SetColors(Color explored, Color mapped, Color unknown) { _colExplored = explored; _colMapped = mapped; _colUnknown = unknown; SetVisibility(_currentVisibility); // 用新颜色重新渲染当前状态 } public void SetVisibility(RoomVisibility v) { _currentVisibility = v; if (_bg == null) return; _bg.color = v switch { RoomVisibility.Explored => _colExplored, RoomVisibility.Mapped => _colMapped, _ => _colUnknown, }; // R12-FD 雾效覆盖层:仅在完全未知时显示 if (_fogOverlay != null) _fogOverlay.enabled = v == RoomVisibility.Unknown; } /// 向后兼容:直接传 bool 时等同于 Explored / Unknown。 public void SetDiscovered(bool v) => SetVisibility(v ? RoomVisibility.Explored : RoomVisibility.Unknown); /// 激活/取消当前房间高亮描边。 public void SetHighlight(bool v) { if (_highlight != null) _highlight.enabled = v; } /// 注入点击回调(携带 RoomId),由 MapPanel 在创建格子时设置;MinimapHUD 不设置即不可点击。 public void SetClickHandler(Action onClick) => _onClick = onClick; /// 设置"可传送站点"标记显隐(CanTeleportTo 为真时由 MapPanel 调用)。 public void SetTeleportable(bool v) { if (_teleportMarker != null) _teleportMarker.enabled = v; } /// /// 新发现房间时播放闪白淡出动画(R12-FC)。 /// 由 MapPanel.OnRoomMappedAnim 调用;协程安全:组件被销毁后 Unity 自动终止。 /// public IEnumerator PlayRevealAnim(Color flashColor, float duration) { if (_bg == null) yield break; var original = _bg.color; _bg.color = flashColor; float elapsed = 0f; while (elapsed < duration) { _bg.color = Color.Lerp(flashColor, original, elapsed / duration); elapsed += Time.unscaledDeltaTime; yield return null; } _bg.color = original; } public void OnPointerEnter(PointerEventData _) { if (!string.IsNullOrEmpty(_displayName)) _onHover?.Invoke(_displayName); } public void OnPointerExit(PointerEventData _) => _onHoverExit?.Invoke(); /// 点击格子:转发 RoomId 给注入的回调(MapPanel 据 CanTeleportTo 决定是否发起传送选择)。 public void OnPointerClick(PointerEventData _) => _onClick?.Invoke(_roomId); } }