(client) feat:技能树节点及其素材

This commit is contained in:
m0_75251201
2025-09-11 11:19:34 +08:00
parent d1c0387df0
commit bb691f9622
79 changed files with 7904 additions and 364 deletions

View File

@ -0,0 +1,111 @@
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;
}
}
}