2026-04-10 18:16:06 +08:00

262 lines
9.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
// 如果当前已固定新触发也是固定请求点击了另一个GiantUpgradeText trigger
// 则先关闭当前面板,再显示新的
if (HeroHintPanel.IsPinned)
{
if (e.Pinned)
{
_heroHintPanelGO.SetActive(false);
HeroHintPanel.IsPinned = false;
}
else
{
// 固定期间忽略hover预览
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=trueClose按钮: 无条件关闭
// 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
}
}