248 lines
8.9 KiB
C#
248 lines
8.9 KiB
C#
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<ShowHintEvent> _onShowHintAction;
|
||
private readonly Action<HideHintEvent> _onHideHintAction;
|
||
private readonly Action<HintTriggerDisabledEvent> _onTriggerDisabledAction;
|
||
private readonly Action<ShowHeroHintPanelEvent> _onShowHeroHintAction;
|
||
private readonly Action<HideHeroHintPanelEvent> _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<RectTransform>();
|
||
this._rootCanvas = ROHintWindow.GetComponentInParent<Canvas>();
|
||
if (this._rootCanvas == null)
|
||
{
|
||
Debug.LogError("在HintWindow的父级中找不到Canvas组件!坐标转换将失败。", ROHintWindow);
|
||
}
|
||
|
||
// 初始化 HeroHintPanel
|
||
if (heroHintPanelRoot != null)
|
||
{
|
||
_heroHintPanelGO = heroHintPanelRoot;
|
||
_heroHintPanel = heroHintPanelRoot.GetComponent<HeroHintPanel>();
|
||
_heroHintPanelRt = heroHintPanelRoot.GetComponent<RectTransform>();
|
||
_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<TextMeshProUGUI>();
|
||
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<HintWindowController>();
|
||
// 根据多语言 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();
|
||
}
|
||
|
||
// ---【新增】---
|
||
/// <summary>
|
||
/// 处理来自HintTrigger的禁用事件
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通用的面板 ClampToScreen,复用 HintWindowController 的屏幕边缘限制逻辑
|
||
/// </summary>
|
||
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<RectTransform>();
|
||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||
canvasRt,
|
||
pivotScreenPos,
|
||
_rootCanvas.worldCamera,
|
||
out Vector2 localPos);
|
||
|
||
panelRt.localPosition = localPos;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region --- 辅助方法 ---
|
||
|
||
/// <summary>
|
||
/// 隐藏窗口并清空当前状态,确保系统干净。
|
||
/// </summary>
|
||
private void HideAndResetState()
|
||
{
|
||
if (ROHintWindow != null)
|
||
{
|
||
ROHintWindow.SetActive(false);
|
||
}
|
||
_currentActiveDataProvider = null;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|