Files
Gen_Hack-and-Slash-Roguelit…/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs

148 lines
5.1 KiB
C#
Raw Permalink 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
{
// 需要引用 UILineRenderer 组件
[RequireComponent(typeof(UILineRenderer))]
// 允许在编辑器模式下实时更新,便于调试
[ExecuteAlways]
public class UIBezierCurveGenerator : MonoBehaviour
{
// UILineRenderer 组件的引用
[SerializeField] public UILineRenderer lineRenderer;
// 控制点
[Header("Bezier Control Points")] public Vector2 P0; // 起点
public Vector2 P1; // 第一个控制点
public Vector2 P2; // 第二个控制点
public Vector2 P3; // 终点
[Header("Curve Settings")] [Range(5, 200)] // 限制段数范围,防止过低导致不平滑,过高导致性能问题
public int segmentCount = 50; // 曲线的平滑度,即采样的线段数量
void Awake()
{
Initialize();
}
void OnValidate()
{
Initialize();
if (lineRenderer != null)
{
GenerateCurvePoints(); // 在编辑器中修改参数时实时更新曲线
}
}
/// <summary>
/// 初始化组件,获取 UILineRenderer 引用
/// </summary>
private void Initialize()
{
if (lineRenderer == null)
{
lineRenderer = GetComponent<UILineRenderer>();
if (lineRenderer == null)
{
Debug.LogError("UILineRenderer component not found on this GameObject. Please add one.", this);
enabled = false; // 禁用此组件,防止空引用错误
}
}
}
/// <summary>
/// 计算三次贝塞尔曲线上的点
/// B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + 3 * (1-t) * t^2 * P2 + t^3 * P3
/// </summary>
/// <param name="t">参数,范围 [0, 1]</param>
/// <param name="p0">起点</param>
/// <param name="p1">第一个控制点</param>
/// <param name="p2">第二个控制点</param>
/// <param name="p3">终点</param>
/// <returns>在参数 t 处的贝塞尔曲线上点</returns>
private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
Vector2 p = uuu * p0; // (1-t)^3 * P0
p += 3 * uu * t * p1; // 3 * (1-t)^2 * t * P1
p += 3 * u * tt * p2; // 3 * (1-t) * t^2 * P2
p += ttt * p3; // t^3 * P3
return p;
}
/// <summary>
/// 生成贝塞尔曲线的点并更新 UILineRenderer
/// </summary>
public void GenerateCurvePoints()
{
if (lineRenderer == null || segmentCount <= 0)
{
Debug.LogWarning("UILineRenderer is null or segmentCount is invalid. Cannot generate curve.", this);
return;
}
// 清空 UILineRenderer 的点列表,以便重新填充
lineRenderer.points.Clear();
for (int i = 0; i <= segmentCount; i++)
{
float t = i / (float)segmentCount;
Vector2 point = CalculateBezierPoint(t, P0, P1, P2, P3);
lineRenderer.points.Add(point);
}
// 通知 UILineRenderer 需要重新绘制其几何体
lineRenderer.SetAllDirty();
}
/// <summary>
/// 提供了通过代码设置控制点并刷新曲线的方法
/// </summary>
public void SetControlPoints(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
this.P0 = p0;
this.P1 = p1;
this.P2 = p2;
this.P3 = p3;
GenerateCurvePoints();
}
/// <summary>
/// 提供了通过代码设置曲线段数并刷新曲线的方法
/// </summary>
public void SetSegmentCount(int count)
{
segmentCount = Mathf.Max(5, count); // 至少保留5段保证一定平滑度
GenerateCurvePoints();
}
// 当组件首次添加或重置时调用
void Reset()
{
Initialize(); // 确保 lineRenderer 已初始化
// 根据 RectTransform 的大小设置默认点,确保在可见范围内
RectTransform rt = GetComponent<RectTransform>();
float halfWidth = rt.rect.width / 2f;
float halfHeight = rt.rect.height / 2f;
// 设置一些默认的控制点让曲线在UI区域内可见
// 这些是相对于 RectTransform 的局部坐标
P0 = new Vector2(-halfWidth * 0.8f, -halfHeight * 0.5f); // 左下
P1 = new Vector2(-halfWidth * 0.4f, halfHeight * 0.8f); // 左上控制点
P2 = new Vector2(halfWidth * 0.4f, halfHeight * 0.8f); // 右上控制点
P3 = new Vector2(halfWidth * 0.8f, -halfHeight * 0.5f); // 右下
segmentCount = 50;
GenerateCurvePoints(); // 立即生成曲线
}
}
}