# Conflicts:
#	Unity/Assets/Resources/Prefab/UI/Hint/HeroHintPanel.prefab
This commit is contained in:
kawagiri 2026-04-10 00:20:13 +08:00
commit d7a9825515
13 changed files with 480 additions and 58 deletions

View File

@ -15,6 +15,7 @@ GameObject:
- component: {fileID: 5807998997809292401}
- component: {fileID: 4241220189165106054}
- component: {fileID: 342233832484256721}
- component: {fileID: 3830294856549829557}
m_Layer: 5
m_Name: SubHintTextPrefab
m_TagString: Untagged
@ -39,7 +40,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 180.01, y: 51.33401}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2870544636936615796
CanvasRenderer:
@ -222,3 +223,16 @@ MonoBehaviour:
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!114 &3830294856549829557
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3351264476285914592}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7029d9e11c13f9d469d79aee5c03a07e, type: 3}
m_Name:
m_EditorClassIdentifier:
_text: {fileID: 3613577018714949851}

View File

@ -4836,6 +4836,140 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 662942483}
m_CullTransparentMesh: 1
--- !u!1 &663108815
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 663108816}
- component: {fileID: 663108818}
- component: {fileID: 663108817}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &663108816
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 663108815}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1953942540}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0.000030518, y: -11.54}
m_SizeDelta: {x: 640, y: 23.09}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &663108817
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 663108815}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u4EE5\u4E0B\u4E3A\u5EF6\u4F38\u8BF4\u660E"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8e119f168f1a6b745be02ef19f51610f, type: 2}
m_sharedMaterial: {fileID: -8081454072124122709, guid: 8e119f168f1a6b745be02ef19f51610f, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4291940817
m_fontColor: {r: 0.8207547, g: 0.8207547, b: 0.8207547, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 12
m_fontSizeBase: 12
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 1
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &663108818
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 663108815}
m_CullTransparentMesh: 1
--- !u!1 &677869773
GameObject:
m_ObjectHideFlags: 0
@ -12060,7 +12194,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 30, y: -190.01001}
m_AnchoredPosition: {x: 30, y: -200.01001}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1693722417
@ -12092,7 +12226,7 @@ MonoBehaviour:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Top: 20
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 10
@ -13407,13 +13541,14 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Children:
- {fileID: 663108816}
m_Father: {fileID: 8388287723112321989}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 4}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1953942541
MonoBehaviour:
@ -14580,7 +14715,7 @@ MonoBehaviour:
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 1
m_ChildControlHeight: 1
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
@ -14752,7 +14887,7 @@ MonoBehaviour:
_anchorOffset: {x: 16, y: 16}
_line: {fileID: 1953942539}
_subHintArea: {fileID: 1693722416}
_subHintItemPrefab: {fileID: 0}
_subHintItemPrefab: {fileID: 3830294856549829557, guid: 8a9dfdca8e7989c41975b28c7398bfea, type: 3}
--- !u!224 &6730593547922559431
RectTransform:
m_ObjectHideFlags: 0

View File

@ -27,6 +27,18 @@ namespace TH1_Core.Events
/// </summary>
public HintDataProvider DataProvider;
}
public struct ShowHeroHintPanelEvent
{
public GiantType GiantType;
public Vector2 Position;
public bool Pinned; // true = 点击固定, false = 悬浮预览
}
public struct HideHeroHintPanelEvent
{
public bool Force; // true = 强制关闭(Close按钮), false = 仅关闭未固定的
}
//---------------------------------------- UIAnnounce 相关的事件 -----------------------------
public enum UIAnnounceMajorEventType

View File

@ -106,7 +106,8 @@ namespace TH1_Core.Managers
AIPlayingHint = ROUIManager.transform.Find("AIPlayingHint").gameObject;
//GameUI = new GameUI(_main,_mapData);
ROHintWindow = ROUIManager.transform.Find("HintWindow").gameObject;
HintUI = new HintUI(ROUIManager.transform.Find("HintWindow").gameObject);
var heroHintPanelGO = ROUIManager.transform.Find("HeroHintPanel")?.gameObject;
HintUI = new HintUI(ROHintWindow, heroHintPanelGO);
//BoardingUI = new BoardingUI(ROUIManager.transform.Find("BoardingPanel")?.gameObject,ROUIManager.transform.Find("BoardingPanel/CloseButton")?.gameObject);
ViewControllerManager.OnMatchStart();
//GameUI.Init();

View File

@ -164,6 +164,25 @@ public class SkillDataAssets : ScriptableObject
return true;
}
/// <summary>
/// 根据多语言 Name ID 查找对应的 SkillType。
/// </summary>
public bool TryGetSkillTypeByNameId(uint nameId, out SkillType skillType)
{
Init();
string nameIdStr = nameId.ToString();
foreach (var kvp in _skillDict)
{
if (kvp.Value.SkillName == nameIdStr)
{
skillType = kvp.Key;
return true;
}
}
skillType = default;
return false;
}
public Color GetBGColor(SkillViewType skillViewType,bool HasTimeLimit)
{
if (HasTimeLimit && skillViewType != SkillViewType.Negative)

View File

@ -334,6 +334,12 @@ public class UnitTypeInfo
public bool ForceMelee;
//全场同时能存在多少个
public int SameUnitCountLimit;
[Tooltip("是否激活关联的Action")]
public bool EnableAction;
[Tooltip("激活的ActionId列表")]
public List<CommonActionId> EnableActions = new List<CommonActionId>();
}
public struct UnitTypeKey

View File

@ -434,7 +434,8 @@ namespace TH1Renderer
var newSprite = Table.Instance.GridAndResourceDataAssets.GetTerrainSprite(_gridData);
// LayLine地块特殊处理只有SatoriIndian阵营的玩家才显示特殊外观
if (_gridData.HasSpType(GridSpType.LeyLine))
// RemiliaGrid 优先级高于 LeyLine同时存在时不降级
if (_gridData.HasSpType(GridSpType.LeyLine) && !_gridData.HasSpType(GridSpType.RemiliaGrid))
{
var selfPlayer = Main.MapData.PlayerMap.SelfPlayerData;
if (selfPlayer.CivEnum != CivEnum.Indian)

View File

@ -2,6 +2,8 @@ using System.Collections.Generic;
using Logic.Multilingual;
using Logic.Skill;
using RuntimeData;
using TH1_Core.Events;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1Resource;
using TMPro;
@ -15,6 +17,14 @@ namespace TH1_UI.HintUI
/// </summary>
public class HeroHintPanel : MonoBehaviour
{
/// <summary>
/// 当前是否处于固定状态,固定期间其他 HeroHintPanel 触发器不响应
/// </summary>
public static bool IsPinned { get; set; }
[Header("关闭按钮")]
public Button CloseButton;
[Header("Part 1: 等级选择栏")]
public Button Level1Button;
public Button Level2Button;
@ -63,6 +73,11 @@ namespace TH1_UI.HintUI
Level2Button?.onClick.AddListener(() => SwitchLevel(1));
Level3Button?.onClick.AddListener(() => SwitchLevel(2));
Level4Button?.onClick.AddListener(() => SwitchLevel(3));
CloseButton?.onClick.AddListener(() =>
{
EventManager.Publish(new HideHeroHintPanelEvent { Force = true });
});
}
/// <summary>
@ -169,8 +184,25 @@ namespace TH1_UI.HintUI
return;
}
// 过滤:只保留 ViewType 不是 Normal 且不是 Special 的技能
var filteredSkills = new List<SkillType>();
foreach (var skill in skillList)
{
if (Table.Instance.SkillDataAssets.GetSkillInfo(skill, out var sInfo))
{
if (sInfo.SkillViewType != SkillViewType.Normal && sInfo.SkillViewType != SkillViewType.Special)
filteredSkills.Add(skill);
}
}
if (filteredSkills.Count == 0)
{
HideAllSkillCircles();
return;
}
// 确保有足够数量的 SkillCircle
while (_skillCircleList.Count < skillList.Count)
while (_skillCircleList.Count < filteredSkills.Count)
{
var go = Instantiate(SkillCirclePrefab, SkillGridContainer);
var circleMono = go.GetComponent<HeroHintPanelCommonCircleMono>();
@ -182,10 +214,10 @@ namespace TH1_UI.HintUI
// 设置每个技能圆圈的内容
for (int i = 0; i < _skillCircleList.Count; i++)
{
if (i < skillList.Count)
if (i < filteredSkills.Count)
{
_skillCircleList[i].gameObject.SetActive(true);
_skillCircleList[i].SetContent(skillList[i], unitFullType);
_skillCircleList[i].SetContent(filteredSkills[i], unitFullType);
}
else
{

View File

@ -1,5 +1,7 @@
using Logic.Action;
using Logic.Skill;
using RuntimeData;
using TH1_Logic.Action;
using TH1_UI.HintUI;
using TH1Resource;
using UI.HintUI;
@ -38,6 +40,26 @@ namespace TH1_UI.HintUI
HintTrigger.DataProvider.UnitFullType = unitFullType;
}
/// <summary>
/// 设置 Action 显示内容
/// </summary>
public void SetContent(CommonActionId actionId)
{
if (!Table.Instance.ActionDataAssets.GetActionInfo(actionId, out var actionInfo))
return;
// 设置 Action 图标
SkillIcon.sprite = actionInfo.Icon;
// Action 没有 SkillViewType使用默认背景色
SkillIconBG.color = Color.white;
// 设置 HintTrigger 数据
HintTrigger.DataProvider.HintDataType = HintDataType.ActionHintData;
HintTrigger.DataProvider.ActionIdData = actionId;
HintTrigger.DataProvider.locked = false;
}
/// <summary>
/// 重置内容
/// </summary>

View File

@ -172,18 +172,88 @@ namespace UI.HintUI
return MultilingualManager.Instance.GetMultilingualTextSafe(ret);
}
/// <summary>
/// 当 HintDataType 为 SkillHintData 时,返回 SubHint 区域需要显示的 DataProvider 列表。
/// 每个 DataProvider 会驱动一个 SubHintItemMono。其他类型返回 null。
/// 获取当前 Hint 描述对应的原始多语言 ID。
/// 返回 true 表示该类型支持 SubId 展开descId 为有效的多语言 ID。
/// 返回 false 表示该类型不需要展开TextData / GeoData 等)。
/// </summary>
public bool GetDescId(out uint descId)
{
descId = 0;
switch (HintDataType)
{
case HintDataType.SkillHintData:
if (Table.Instance.SkillDataAssets.GetSkillInfo(SkillTypeData, out var skillInfo))
return uint.TryParse(skillInfo.SkillDesc, out descId);
return false;
case HintDataType.ActionHintData:
if (Table.Instance.ActionDataAssets.GetActionInfo(ActionIdData, out var actionInfo))
return uint.TryParse(locked && actionInfo.NeedLockDesc ? actionInfo.LockDesc : actionInfo.Desc, out descId);
return false;
case HintDataType.TechHintData:
if (Table.Instance.TechDataAssets.GetTechInfo(TechTypeData, out var techInfo))
return uint.TryParse(techInfo.Description, out descId);
return false;
case HintDataType.TextDataGiantUpgrate:
foreach (var g in Table.Instance.TextDataAssets.GiantUpgradeTextList)
if (g.GiantType == UnitFullType.GiantType)
return uint.TryParse(g.UpgradeText, out descId);
return false;
case HintDataType.TechAtomHintData:
if (Table.Instance.TechDataAssets.GetTechAtomInfo(TechAtom, out var atomInfo))
return uint.TryParse(atomInfo.Desc, out descId);
return false;
case HintDataType.UnitHintData:
if (Table.Instance.UnitTypeDataAssets.GetUnitDesc(UnitFullType, out var unitDesc))
return uint.TryParse(unitDesc, out descId);
return false;
case HintDataType.PlayerTaskData:
if (Table.Instance.PlayerTaskDataAssets.GetPlayerTaskData(PlayerTaskType, out var ptData))
return uint.TryParse(ptData.HintDesc, out descId);
return false;
// TextData / GeoData 不需要展开 SubId
case HintDataType.TextData:
case HintDataType.GeoData:
default:
return false;
}
}
/// <summary>
/// 通过 GetDescId 获取多语言 Desc ID再用 GetMultilingualSubIdList 提取 SubId
/// 如果 SubId 能匹配到 SkillDataAssets 中的 SkillName
/// 则为每个匹配项创建一个 SkillHintData 类型的 HintDataProvider。
/// 无匹配时返回 null。
/// </summary>
public List<HintDataProvider> GetSubHintProviders()
{
if (HintDataType != HintDataType.SkillHintData) return null;
// TODO: 替换为实际的技能子提示 DataProvider
return new List<HintDataProvider>
if (!GetDescId(out var descId)) return null;
var subIds = MultilingualManager.Instance.GetMultilingualSubIdList(descId);
if (subIds == null || subIds.Count == 0) return null;
var result = new List<HintDataProvider>();
foreach (var subId in subIds)
{
new HintDataProvider { HintDataType = HintDataType.TextData, Text = "1" },
new HintDataProvider { HintDataType = HintDataType.TextData, Text = "2" },
};
if (Table.Instance.SkillDataAssets.TryGetSkillTypeByNameId(subId, out var skillType))
{
result.Add(new HintDataProvider
{
HintDataType = HintDataType.SkillHintData,
SkillTypeData = skillType,
UnitFullType = this.UnitFullType,
SkillParam = null,
});
}
}
return result.Count > 0 ? result : null;
}
public string TmpGetBigClassType(GeoSmallClass smallClass)

View File

@ -11,13 +11,13 @@ namespace TH1_UI.HintUI
/// 此组件内部包含一个可配置的数据提供者(DataProvider),用于生成提示内容。
/// </summary>
[RequireComponent(typeof(RectTransform))]
public class HintTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
public class HintTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
[Tooltip("提示窗口相对于鼠标位置的偏移量。")]
[SerializeField]
private Vector2 positionOffset = new Vector2(15f, -15f);
[SerializeField]
[SerializeField]
[Tooltip("hinttext数据来源")]
public HintDataProvider DataProvider;
@ -26,17 +26,22 @@ namespace TH1_UI.HintUI
public void OnPointerEnter(PointerEventData eventData)
{
// 检查数据提供者是否已配置
if (DataProvider == null)
if (DataProvider == null) return;
// TextDataGiantUpgrate 类型走 HeroHintPanel悬浮预览
if (DataProvider.HintDataType == HintDataType.TextDataGiantUpgrate)
{
EventManager.Publish(new ShowHeroHintPanelEvent
{
GiantType = DataProvider.UnitFullType.GiantType,
Position = (Vector2)eventData.position + this.positionOffset,
Pinned = false
});
return;
}
// 如果提供者有效,但它生成了空内容,也不显示
// (这一步也可以移到HintUI里做但在这里提前判断可以避免无效的事件发布)
if (string.IsNullOrEmpty(DataProvider.GetHintText()))
{
return;
}
if (string.IsNullOrEmpty(DataProvider.GetHintText())) return;
// 创建并填充请求显示提示的事件
ShowHintEvent showHintEvent = new ShowHintEvent
@ -49,10 +54,28 @@ namespace TH1_UI.HintUI
EventManager.Publish(showHintEvent);
}
public void OnPointerClick(PointerEventData eventData)
{
if (DataProvider == null) return;
if (eventData.button != PointerEventData.InputButton.Left) return;
// TextDataGiantUpgrate 类型左键点击 → 固定 HeroHintPanel
if (DataProvider.HintDataType == HintDataType.TextDataGiantUpgrate)
{
EventManager.Publish(new ShowHeroHintPanelEvent
{
GiantType = DataProvider.UnitFullType.GiantType,
Position = (Vector2)eventData.position + this.positionOffset,
Pinned = true
});
}
}
public void OnPointerExit(PointerEventData eventData)
{
// 发布隐藏提示的事件
EventManager.Publish(new HideHintEvent());
// 鼠标移出时仅关闭未固定的 HeroHintPanel
EventManager.Publish(new HideHeroHintPanelEvent { Force = false });
}
private void OnDisable()

View File

@ -17,22 +17,23 @@ namespace TH1_UI.HintUI
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 --- : ---
/// <summary>
/// 记录当前显示提示的数据提供者。
/// 如果没有提示在显示则为null。
/// 这是实现“精确关闭”逻辑的核心。
/// </summary>
#region --- ---
private HintDataProvider _currentActiveDataProvider;
#endregion
public HintUI(GameObject hintWindowRoot)
public HintUI(GameObject hintWindowRoot, GameObject heroHintPanelRoot = null)
{
if (hintWindowRoot == null)
{
@ -48,11 +49,21 @@ namespace TH1_UI.HintUI
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;
_onTriggerDisabledAction = OnTriggerDisabled;
_onShowHeroHintAction = OnShowHeroHintPanel;
_onHideHeroHintAction = OnHideHeroHintPanel;
init();
}
@ -66,19 +77,20 @@ namespace TH1_UI.HintUI
// 订阅所有事件
EventManager.Subscribe(_onShowHintAction);
EventManager.Subscribe(_onHideHintAction);
// ---【新增】---
EventManager.Subscribe(_onTriggerDisabledAction);
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(_onTriggerDisabledAction);
EventManager.Unsubscribe(_onShowHeroHintAction);
EventManager.Unsubscribe(_onHideHeroHintAction);
}
#region --- ---
@ -102,11 +114,8 @@ namespace TH1_UI.HintUI
_hintTextComponent.text = textToShow;
var controller = ROHintWindow.GetComponent<HintWindowController>();
// Skill 类型时显示 SubHint其他类型隐藏
if (e.DataProvider.HintDataType == HintDataType.SkillHintData)
controller.SetSubHint(e.DataProvider.GetSubHintProviders());
else
controller.SetSubHint(null);
// 根据多语言 SubId 匹配 Skill动态决定是否显示 SubHintArea
controller.SetSubHint(e.DataProvider.GetSubHintProviders());
controller.RefreshSize();
@ -149,7 +158,75 @@ namespace TH1_UI.HintUI
#endregion
#region --- : ---
#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;
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;
float clampedX = Mathf.Clamp(desiredTopLeft.x, 0, Screen.width - windowW);
float clampedY = Mathf.Clamp(desiredTopLeft.y, windowH, Screen.height);
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>
/// 隐藏窗口并清空当前状态,确保系统干净。
@ -160,7 +237,6 @@ namespace TH1_UI.HintUI
{
ROHintWindow.SetActive(false);
}
// 无论是主动隐藏还是被动隐藏,都需要清空状态
_currentActiveDataProvider = null;
}

View File

@ -50,14 +50,25 @@ public class HintWindowController : MonoBehaviour
if (!show) return;
// 确保有足够的 SubHintItemMono 子对象
while (_subHintItems.Count < providers.Count)
while (_subHintItems.Count < providers.Count && _subHintArea != null)
{
if (_subHintItemPrefab != null && _subHintArea != null)
SubHintItemMono newItem;
if (_subHintItemPrefab != null)
{
var newItem = Instantiate(_subHintItemPrefab, _subHintArea);
_subHintItems.Add(newItem);
newItem = Instantiate(_subHintItemPrefab, _subHintArea);
}
else break;
else
{
// 没有指定 Prefab 时,动态创建
var go = new GameObject($"SubHintItem_{_subHintItems.Count}", typeof(RectTransform));
go.transform.SetParent(_subHintArea, false);
var tmp = go.AddComponent<TextMeshProUGUI>();
tmp.fontSize = _text != null ? _text.fontSize : 14f;
tmp.color = _text != null ? _text.color : Color.white;
tmp.enableAutoSizing = false;
newItem = go.AddComponent<SubHintItemMono>();
}
_subHintItems.Add(newItem);
}
// 设置数据源并控制显隐