Files
Gen_Hack-and-Slash-Roguelit…/Client/Assets/Scripts/UI/SkillNodeEnterLineUI.cs
2025-09-11 11:19:34 +08:00

112 lines
5.9 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 UnityEngine;
namespace UI
{
public class SkillNodeEnterLineUI : MonoBehaviour
{
[SerializeField] private SkillNodeLinkLineUI skillNodeLinkLineUIPrefab;
private const float MIN_VERTICAL_SPACING = 12.9447f; // 每条连接线的最小垂直间距
private const float UPWARD_OFFSET_FROM_BASE = 0f; // 整体结束点相对于参照点的向上偏移量
/// <summary>
/// 初始化连接线。根据传入的起始点数组创建多条连接线,
/// 这些线的结束点将围绕 transform.position - new Vector3(6,0) 并在其基础上向上偏移5
/// 纵向均匀排列至少间距12。
/// 在每次调用前,会清空所有旧的连接线以避免累积。
/// </summary>
/// <param name="startPoints">要连接的线起始点数组。</param>
/// <returns>所有连接线的结束点所占据的最小总高度。</returns>
public float Init(Vector2[] startPoints)
{
// 清空所有旧的连接线,避免重复调用时线累积。
// 从后往前遍历子对象,因为销毁子对象会改变子对象列表的索引。
for (var i = transform.childCount - 1; i >= 0; i--)
{
// 获取当前子对象。
var child = transform.GetChild(i);
// 仅销毁SkillNodeLinkLineUI类型的子对象实例避免意外删除其他非连接线的子对象。
if (child != null && child.GetComponent<SkillNodeLinkLineUI>() != null)
{
Destroy(child.gameObject);
}
}
// 预制体加载检查:确保在执行任何操作之前,预制体已经加载。
// 优先使用Inspector赋值如果 skillNodeLinkLineUIPrefab 为 null则尝试从 Resources 文件夹加载作为备用方案。
if (skillNodeLinkLineUIPrefab == null)
{
// 从Resources加载预制体。
skillNodeLinkLineUIPrefab = Resources.Load<SkillNodeLinkLineUI>("Prefab/SkillTree/linkLine");
if (skillNodeLinkLineUIPrefab == null)
{
// 打印错误日志(已本地化为中文)。
Debug.LogError(
"初始化失败SkillNodeLinkLineUI 预制体未在 Prefab/SkillTree/linkLine 路径找到。请检查路径,确保预制体存在,或直接在 Inspector 中赋值。");
return 0f; // 预制体缺失返回0高度。
}
}
// 获取起始点的数量。
var numLines = startPoints.Length;
if (numLines == 0)
{
// 没有起始点不需要绘制连接线返回0高度。
// 此时,清理旧连接线的逻辑已经执行,确保了没有残留的线。
return 0f;
}
// 计算所有连接线共享的基准结束点X坐标。
// 这是所有连接线结束点集合的垂直居中轴线。
var commonEndPointX = transform.position.x - 6f;
// 计算所有连接线结束点集合的实际垂直中心Y坐标。
// 根据需求 "有多个点时向上偏移5",这个偏移量应用于整个结束点集合的中心。
var effectiveCenterY = transform.position.y + UPWARD_OFFSET_FROM_BASE;
// 初始化所有线结束点所占据的总垂直跨度。
var requiredHeight = 0f;
if (numLines == 1)
{
// 只有一个起始点时其结束点直接放在计算出的有效中心Y坐标上。
var endPoint = new Vector2(commonEndPointX, effectiveCenterY);
// 实例化连接线预制体并设置为当前对象的子对象。
var line = Instantiate(skillNodeLinkLineUIPrefab, transform);
// 设置连接线的起始点和结束点。
line.SetConnectionPoints(startPoints[0], endPoint);
// 只有一个点时垂直高度可以认为是0因为它不形成一个跨越多个点的“总高度”。
// 这里返回0f符合“所有连接线的结束点所占据的最小总高度”的定义语义。
requiredHeight = 0f;
}
else // numLines > 1
{
// 计算所有连接线结束点所占据的总垂直跨度(从最顶端到最底端)。
// 这是从最上面一条线的结束点Y到最下面一条线的结束点Y的距离。
requiredHeight = (numLines - 1) * MIN_VERTICAL_SPACING;
// 计算最上面一条线的结束点Y坐标。
// effectiveCenterY 是所有线的垂直中心,从这个中心向上偏移 requiredHeight / 2 即可得到最顶端的Y。
var currentEndPointY = effectiveCenterY + (requiredHeight / 2f);
// 遍历起始点数组,创建并设置每条连接线。
for (var i = 0; i < numLines; i++)
{
// 为当前连接线确定结束点坐标。
var endPoint = new Vector2(commonEndPointX, currentEndPointY);
// 实例化连接线预制体。
var line = Instantiate(skillNodeLinkLineUIPrefab, transform);
// 设置连接线的起始点和结束点。
line.SetConnectionPoints(startPoints[i], endPoint);
// 为下一条线计算其结束点Y坐标向下移动一个最小间距
currentEndPointY -= MIN_VERTICAL_SPACING;
}
}
// 返回所有连接线的结束点所占据的最小总高度。
return requiredHeight;
}
}
}