大家好!
如果你曾经尝试在Unity UI中构建分支技能树或进化树,你可能会发现原生组件(如HorizontalLayoutGroup、ScrollRect)在处理非线性路径和多个父节点时会很快失效。
在我们的怪物驯服游戏《Mokomon: Five Elements》中,我需要一个进化树,让生物能够动态分支(例如Geolam进化为Tsunodon、Terranite或Bouldox),同时避免线条交叉成难以辨认的混乱局面。
以下是关于数学计算和网格生成的工作原理详解:
1. 布局数学:重心松弛法
不采用手动锚定节点或使用僵硬的布局组:
- 水平轴(X):严格绑定到进化阶段索引(婴儿=0,幼年=1,成年=2等),乘以列间距。
- 垂直轴(Y):为了保持连接清晰,我们运行重心松弛迭代:
- 前向传递:将子节点拉向其父节点的平均Y位置。
- 后向传递:将父节点拉向其子节点的平均Y位置。
- 碰撞检查:遍历每个阶段列,将重叠的节点按最小垂直间距推开。
这能自动拉直连接线,消除视觉上的杂乱无章。
2. 单次绘制调用渲染所有线条(MaskableGraphic)
实例化拉伸的UI图像GameObject来绘制线条会产生庞大的层级结构并增加绘制调用次数。
相反,我们的连接器继承自MaskableGraphic,并通过VertexHelper将粗立方贝塞尔曲线直接生成到UI网格中:
// 1. 计算立方贝塞尔曲线点
private Vector2 CalculateCubicBezierPoint(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
{
float u = 1f - t;
float tt = t * t;
float uu = u * u;
return (uu * u * p0) + (3f * uu * t * p1) + (3f * u * tt * p2) + (tt * t * p3);
}
// 2. 直接将程序化粗线几何体生成到UI网格中
private void DrawThickLineStrip(VertexHelper vh, List<Vector2> points, float width, Color color)
{
float halfWidth = width * 0.5f;
int startIndex = vh.currentVertCount;
for (int i = 0; i < points.Count; i++)
{
Vector2 current = points[i];
Vector2 dir = (i == points.Count - 1)
? (current - points[i - 1]).normalized
: (points[i + 1] - current).normalized;
Vector2 normal = new Vector2(-dir.y, dir.x);
Vector2 vLeft = current + normal * halfWidth;
Vector2 vRight = current - normal * halfWidth;
float vNorm = (float)i / (points.Count - 1);
vh.AddVert(new Vector3(vLeft.x, vLeft.y, 0f), color, new Vector2(0f, vNorm));
vh.AddVert(new Vector3(vRight.x, vRight.y, 0f), color, new Vector2(1f, vNorm));
}
for (int i = 0; i < points.Count - 1; i++)
{
int vertIdx = startIndex + i * 2;
vh.AddTriangle(vertIdx, vertIdx + 1, vertIdx + 2);
vh.AddTriangle(vertIdx + 1, vertIdx + 3, vertIdx + 2);
}
}
评论 (0)