Archived
142 lines
5.1 KiB
C#
142 lines
5.1 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
using UnityEngine.UI;
|
|
|
|
namespace XericLibrary.Runtime.UIGraph
|
|
{
|
|
/// <summary>
|
|
/// UI上线条绘制组件
|
|
/// 支持设置线条厚度、居中显示,并为线段之间添加斜角边缘
|
|
/// 继承自 MaskableGraphic,可与 UI 遮罩系统配合使用
|
|
/// </summary>
|
|
[AddComponentMenu("Xeric Library/UI/UILineRenderer", 15)]
|
|
public class UILineRenderer : XericRendererComponent
|
|
{
|
|
// todo 根据优弧劣弧绘制线段,这么说可能不太准确,但我需要在90度以内绘制漂亮的转角,大于90度则用中心圆代替
|
|
#region 字段属性
|
|
|
|
/// <summary>
|
|
/// 线条的顶点数组,至少需要 2 个点才能绘制线条
|
|
/// 点的坐标基于本地空间,中心点由 center 属性控制
|
|
/// </summary>
|
|
public List<Vector2> points = new List<Vector2>();
|
|
private Vector2[] _points;
|
|
|
|
public float thickness = 10f;
|
|
public bool center = true;
|
|
public bool cycleLoop = false;
|
|
|
|
/// <summary>
|
|
/// 是否启用倒角功能
|
|
/// </summary>
|
|
public bool useChamfer = false;
|
|
|
|
/// <summary>
|
|
/// 倒角细分数量,控制圆弧的平滑度
|
|
/// </summary>
|
|
public int chamferSegments = 4;
|
|
|
|
/// <summary>
|
|
/// 内圆弧半径,当大于0时启用内圆弧
|
|
/// </summary>
|
|
public float innerRadius = 0f;
|
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
/// 添加顶点
|
|
/// </summary>
|
|
/// <param name="point"></param>
|
|
/// <param name="mergingRadius">合并弧度,指定一个弧度,在添加顶点时,自动合并之前的顶点为直线</param>
|
|
public void AddPoint(Vector2 point, float mergingRadius = -1)
|
|
{
|
|
if (mergingRadius > 0 && points.Count >= 2)
|
|
{
|
|
var a = points[^1];
|
|
var b = Vector3.Dot((a - points[^2]).normalized, (a - point).normalized);
|
|
|
|
if (b < mergingRadius)
|
|
points[^1] = point;
|
|
return;
|
|
}
|
|
points.Add(point);
|
|
Refresh();
|
|
}
|
|
|
|
public void RemovePoint(int index)
|
|
{
|
|
points.RemoveAt(index);
|
|
Refresh();
|
|
}
|
|
|
|
public void CleanPoint(Vector2 point)
|
|
{
|
|
points.Clear();
|
|
Refresh();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成线条网格
|
|
/// </summary>
|
|
/// <param name="vh">用于构建网格的 VertexHelper 对象</param>
|
|
protected override void OnPopulateMesh(VertexHelper vh)
|
|
{
|
|
// 清空现有的网格数据
|
|
vh.Clear();
|
|
|
|
var offset = XericRendererUtils.SwitchCenterOffset(center, rectTransform.sizeDelta);
|
|
_points = points.ToArray();
|
|
|
|
if (useChamfer)
|
|
{
|
|
vh.PopulateLineByPointsArray_CFAL(_points, thickness, cycleLoop, color, offset, chamferSegments, innerRadius);
|
|
}
|
|
else
|
|
{
|
|
vh.PopulateLineByPointsArray_DSL5(_points, thickness, cycleLoop, color, offset);
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
// 至少需要 2 个点才能绘制线条
|
|
if (_points.Length < 2)
|
|
return;
|
|
|
|
// 计算线路总长度
|
|
float totalLength = _points.CalculateTotalLength();
|
|
float currentLength = 0f;
|
|
|
|
// 遍历所有点,创建线段并添加到网格中
|
|
for (int i = 0; i < _points.Length-1; i++)
|
|
{
|
|
// 使用静态工具方法创建当前点与下一个点之间的线段
|
|
// 传递当前累积长度和总长度用于UV坐标计算
|
|
vh.CreateLineSegment_CFAL(_points[i], _points[i+1],
|
|
i > 0 ? Mathf.Acos(Vector2.Dot((_points[i] - _points[i -1]).normalized, (_points[i + 1] - _points[i]).normalized)) * Mathf.Rad2Deg : 0,
|
|
i < _points.Length-2 ? Mathf.Acos(Vector2.Dot((_points[i] - _points[i + 1]).normalized, (_points[i + 1] - _points[i +2]).normalized)) * Mathf.Rad2Deg : 0,
|
|
thickness, center, rectTransform.sizeDelta, color, currentLength, totalLength);
|
|
|
|
// 更新累积长度
|
|
currentLength += Vector2.Distance(_points[i], _points[i+1]);
|
|
|
|
// 计算当前线段的顶点索引(每个线段包含 5 个顶点)
|
|
int index = i * 5;
|
|
|
|
// 添加线段的两个三角形(构成矩形线段)
|
|
vh.AddTriangle(index, index+1, index+3);
|
|
vh.AddTriangle(index+3, index+2, index);
|
|
|
|
// 为线段之间添加斜角边缘
|
|
// 使用上一个线段的终点和当前线段的起点创建过渡三角形
|
|
if (i != 0)
|
|
{
|
|
vh.AddTriangle(index, index-1, index-3);
|
|
vh.AddTriangle(index+1, index-1, index-2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |