Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/UI/SkillTreeNodeUI.cs

132 lines
5.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.Collections.Generic;
using Data;
using UnityEngine;
using UnityEditor;
using TMPro;
namespace UI
{
/// <summary>
/// 技能树节点的用户界面组件。
/// </summary>
public class SkillTreeNodeUI : MonoBehaviour
{
/// <summary>
/// 节点的RectTransform组件。
/// </summary>
public RectTransform rectTransform;
/// <summary>
/// 节点的最小高度。
/// </summary>
[SerializeField] private float NODE_MIN_HEIGHT = 39.0122f * 2;
/// <summary>
/// 两条连接线结束点之间的最小垂直间距。
/// </summary>
[SerializeField]private float MIN_VERTICAL_SPACING = 12.9447f;
/// <summary>
/// 技能节点入口线UI组件。
/// </summary>
public SkillNodeEnterLineUI skillNodeEnterLineUI;
/// <summary>
/// 输出线连接点的参考或容器。
/// </summary>
public RectTransform outputHead;
/// <summary>
/// 文本显示组件。
/// </summary>
public TMP_Text text;
public SkillTreeDef skillTreeDef;
/// <summary>
/// 初始化技能树节点UI。
/// </summary>
/// <param name="linkLinePoints">连接线的点数组。</param>
/// <param name="label">节点显示的文本标签。</param>
public void Init(Vector2[] linkLinePoints, string label)
{
text.text = label;
if (linkLinePoints is { Length: > 0 })
{
var height = skillNodeEnterLineUI.GetRequiredHeight(linkLinePoints.Length);
height = Mathf.Max(height + NODE_MIN_HEIGHT / 2 + 10, NODE_MIN_HEIGHT);
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, height);
skillNodeEnterLineUI.Init(linkLinePoints);
}
}
/// <summary>
/// 预先计算技能树节点在初始化后所需的最小高度。
/// 此方法可以在调用 Init 之前用于布局计算。
/// </summary>
/// <param name="linkLineCount">连接线(入口线)的数量。</param>
/// <returns>节点所需的最小高度。</returns>
public float GetRequiredNodeHeight(int linkLineCount)
{
// 如果没有连接线或 skillNodeEnterLineUI 组件为空,则高度为最小高度
if (linkLineCount <= 0 || skillNodeEnterLineUI == null)
{
return NODE_MIN_HEIGHT;
}
// 获取 SkillNodeEnterLineUI 根据连接线数量计算出的所需高度
var calculatedLineHeight = skillNodeEnterLineUI.GetRequiredHeight(linkLineCount);
// 结合最小节点高度和额外的填充,确保节点有足够的空间
// 逻辑与 Init() 方法中的高度计算保持一致
var finalHeight = Mathf.Max(calculatedLineHeight + NODE_MIN_HEIGHT / 2 + 10, NODE_MIN_HEIGHT);
return finalHeight;
}
/// <summary>
/// 查询出口位置。
/// </summary>
/// <param name="totalCount">总数量。</param>
/// <param name="index">位置从上往下0-based。</param>
/// <returns>世界坐标。</returns>
public Vector2 GetOutputPosition(int totalCount, int index)
{
// 输入验证防止无效的totalCount或index导致错误
if (totalCount <= 0 || index < 0 || index >= totalCount)
{
Debug.LogWarning($"获取输出位置时,总数 ({totalCount}) 或索引 ({index}) 无效。返回outputHead的默认位置。");
// 返回outputHead的中心位置作为备用或者Vector2.zero取决于具体需求
return outputHead.position;
}
// 1. 计算 X 坐标outputHead 的右边界
var corners = new Vector3[4];
outputHead.GetWorldCorners(corners);
// corners[2] 是右上角的世界坐标点
var worldX = corners[2].x;
// 2. 计算 Y 坐标:以 outputHead 的中心Y坐标为基准进行偏移
var worldY = outputHead.position.y;
if (totalCount == 2)
{
// 特殊情况当输出点为2个时点1为(x,y+d)点2为(x,y-d)d为MIN_VERTICAL_SPACING
if (index == 0) // 第一个点 (最上面的点)
{
worldY += MIN_VERTICAL_SPACING;
}
else // 第二个点 (最下面的点)
{
worldY -= MIN_VERTICAL_SPACING;
}
}
else
{
// 一般情况多个点均匀纵向排列以outputHead的Y为中心
// 计算最顶部的点 (index=0) 相对于中心点Y的偏移量
// 总共有 (totalCount - 1) 个 MIN_VERTICAL_SPACING 的间距
// 索引为 index 的点的偏移量为:
// ( (totalCount - 1) / 2.0f - index ) * MIN_VERTICAL_SPACING
var halfTotalSpacing = (totalCount - 1) / 2.0f;
var yOffset = (halfTotalSpacing - index) * MIN_VERTICAL_SPACING;
worldY += yOffset;
}
return new Vector2(worldX, worldY);
}
}
}