using System; using System.Collections.Generic; using TH1_Core.Events; using TH1_Core.Managers; using TMPro; using UI.HintUI; using UnityEngine; // 确保引用了事件命名空间 namespace TH1_UI.HintUI { public class HintUI { // 视图引用 private readonly GameObject ROHintWindow; private readonly RectTransform _rectTransform; private TextMeshProUGUI _hintTextComponent; private readonly Canvas _rootCanvas; // HeroHintPanel 引用 private readonly GameObject _heroHintPanelGO; private readonly HeroHintPanel _heroHintPanel; private readonly RectTransform _heroHintPanelRt; // 缓存委托以用于取消订阅 private readonly Action _onShowHintAction; private readonly Action _onHideHintAction; private readonly Action _onTriggerDisabledAction; private readonly Action _onShowHeroHintAction; private readonly Action _onHideHeroHintAction; #region --- 状态管理 --- private HintDataProvider _currentActiveDataProvider; #endregion public HintUI(GameObject hintWindowRoot, GameObject heroHintPanelRoot = null) { if (hintWindowRoot == null) { Debug.LogError("HintWindowUI的构造函数收到了一个空的GameObject引用!"); return; } this.ROHintWindow = hintWindowRoot; this._rectTransform = ROHintWindow.GetComponent(); this._rootCanvas = ROHintWindow.GetComponentInParent(); if (this._rootCanvas == null) { Debug.LogError("在HintWindow的父级中找不到Canvas组件!坐标转换将失败。", ROHintWindow); } // 初始化 HeroHintPanel if (heroHintPanelRoot != null) { _heroHintPanelGO = heroHintPanelRoot; _heroHintPanel = heroHintPanelRoot.GetComponent(); _heroHintPanelRt = heroHintPanelRoot.GetComponent(); _heroHintPanelGO.SetActive(false); } // 缓存Action委托 _onShowHintAction = OnShowHint; _onHideHintAction = OnHideHint; _onTriggerDisabledAction = OnTriggerDisabled; _onShowHeroHintAction = OnShowHeroHintPanel; _onHideHeroHintAction = OnHideHeroHintPanel; init(); } private void init() { Transform textTransform = ROHintWindow.transform.Find("Text"); if (textTransform != null) _hintTextComponent = textTransform.GetComponent(); if (_hintTextComponent == null) return; // 订阅所有事件 EventManager.Subscribe(_onShowHintAction); EventManager.Subscribe(_onHideHintAction); EventManager.Subscribe(_onTriggerDisabledAction); EventManager.Subscribe(_onShowHeroHintAction); EventManager.Subscribe(_onHideHeroHintAction); ROHintWindow.SetActive(false); } public void Dispose() { EventManager.Unsubscribe(_onShowHintAction); EventManager.Unsubscribe(_onHideHintAction); EventManager.Unsubscribe(_onTriggerDisabledAction); EventManager.Unsubscribe(_onShowHeroHintAction); EventManager.Unsubscribe(_onHideHeroHintAction); } #region --- 事件处理器 --- private void OnShowHint(ShowHintEvent e) { if (ROHintWindow == null || _hintTextComponent == null || _rectTransform == null || e.DataProvider == null) { HideAndResetState(); // 使用重构后的方法 return; } string textToShow = e.DataProvider.GetHintText(); if (string.IsNullOrEmpty(textToShow)) { HideAndResetState(); // 使用重构后的方法 return; } ROHintWindow.SetActive(true); _hintTextComponent.text = textToShow; var controller = ROHintWindow.GetComponent(); // 根据多语言 SubId 匹配 Skill,动态决定是否显示 SubHintArea controller.SetSubHint(e.DataProvider.GetSubHintProviders()); controller.RefreshSize(); RectTransformUtility.ScreenPointToLocalPointInRectangle( _rectTransform.parent as RectTransform, e.Position, _rootCanvas.worldCamera, out Vector2 localPoint ); controller.Present(e.Position); //_rectTransform.localPosition = localPoint; _rectTransform.SetAsLastSibling(); // 在成功显示提示后,记录下它的来源 _currentActiveDataProvider = e.DataProvider; } private void OnHideHint(HideHintEvent e) { // 由OnPointerExit触发的通用隐藏请求 HideAndResetState(); } // ---【新增】--- /// /// 处理来自HintTrigger的禁用事件 /// private void OnTriggerDisabled(HintTriggerDisabledEvent e) { // 核心逻辑:检查被禁用的Trigger是否就是当前正在显示提示的那个 if (e.DataProvider != null && e.DataProvider == _currentActiveDataProvider) { // 如果是,则隐藏提示框并重置状态 Debug.Log($"Hint is hiding because its trigger ({e.DataProvider}) was disabled."); HideAndResetState(); } // 如果不是(例如,另一个不相关的UI元素被禁用了),则什么也不做 } #endregion #region --- HeroHintPanel 事件处理 --- private void OnShowHeroHintPanel(ShowHeroHintPanelEvent e) { if (_heroHintPanelGO == null || _heroHintPanel == null) return; // 固定期间忽略所有新的触发 if (HeroHintPanel.IsPinned) return; _heroHintPanel.SetHeroInfo(e.GiantType); _heroHintPanelGO.SetActive(true); HeroHintPanel.IsPinned = e.Pinned; _heroHintPanel.UpdatePinState(e.Pinned); ClampPanelToScreen(_heroHintPanelRt, e.Position); _heroHintPanelRt.SetAsLastSibling(); } private void OnHideHeroHintPanel(HideHeroHintPanelEvent e) { if (_heroHintPanelGO == null) return; // Force=true(Close按钮): 无条件关闭 // Force=false(鼠标移出): 仅在未固定时关闭 if (!e.Force && HeroHintPanel.IsPinned) return; _heroHintPanelGO.SetActive(false); HeroHintPanel.IsPinned = false; } /// /// 通用的面板 ClampToScreen,复用 HintWindowController 的屏幕边缘限制逻辑 /// private void ClampPanelToScreen(RectTransform panelRt, Vector2 mouseScreenPos) { if (panelRt == null || _rootCanvas == null) return; UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(panelRt); Canvas.ForceUpdateCanvases(); float scaleFactor = _rootCanvas.scaleFactor; if (scaleFactor <= 0) scaleFactor = 1f; float windowW = panelRt.rect.width * scaleFactor; float windowH = panelRt.rect.height * scaleFactor; Vector2 anchorOffset = new Vector2(16, 16); Vector2 desiredTopLeft = mouseScreenPos + anchorOffset; const float margin = 150f; float clampedX = Mathf.Clamp(desiredTopLeft.x, margin, Screen.width - windowW - margin); float clampedY = Mathf.Clamp(desiredTopLeft.y, windowH + margin, Screen.height - margin); Vector2 pivot = panelRt.pivot; Vector2 pivotScreenPos = new Vector2( clampedX + pivot.x * windowW, clampedY - (1 - pivot.y) * windowH ); RectTransform canvasRt = _rootCanvas.GetComponent(); RectTransformUtility.ScreenPointToLocalPointInRectangle( canvasRt, pivotScreenPos, _rootCanvas.worldCamera, out Vector2 localPos); panelRt.localPosition = localPos; } #endregion #region --- 辅助方法 --- /// /// 隐藏窗口并清空当前状态,确保系统干净。 /// private void HideAndResetState() { if (ROHintWindow != null) { ROHintWindow.SetActive(false); } _currentActiveDataProvider = null; } #endregion } }