在游戏开发中,我们经常会使用多维图来表示人物的属性。比如三国志中,通过五维图,我们可以清晰地看到武将的属性。
如果我们自己的游戏需要用多边形雷达图来表示相似的属性,则需要针对UGUI进行一些处理。首先需要获取到Mesh网格和所在的CanvasRenderer渲染,以及Material材质球,从而描绘出完整的多边形。
/// <summary>
/// 设置点位
/// </summary>
void SetVertices()
{
int count = element.Length + 1;
canvas = GetComponent<CanvasRenderer>();
mesh = new Mesh();
vertices = new Vector3[count];
var uvs = new Vector2[count];
triangles = new int[count * 3];
var tangents = new Vector4[count];
Vector4 tangent = new Vector4(0, 1, 0, -1);
allAngle = (float)360 / (count - 1);
for (int i = 0; i < vertices.Length; i++) //循环顶点
{
vertices[i] = Quaternion.Euler(0, 0, allAngle * i) * Vector3.up * sideLength;
uvs[i] = Quaternion.Euler(0, 0, allAngle * i) * Vector3.up;
tangents[i] = tangent;
}
//为mesh的顶点赋值
for (int i = 0, index = 0; i < count - 1; i++, index += 3)
{
triangles[index + 0] = 0;
triangles[index + 1] = i == count - 2 ? 1 : 2 + i;//倒数第二
triangles[index + 2] = i == count - 2 ? count - 1 : 1 + i;//最后一个
}
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.tangents = tangents;
mesh.uv = uvs;
canvas.SetMesh(mesh);
canvas.SetMaterial(material, null);
}
通过求取夹角,传入不同的维度值(注意这里长度最小需要取3),我们可以得到如下不同维度的雷达图 :
最后通过调整不同的值,实现多边形雷达图的变化:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RadarMap : MonoBehaviour
{
private int[] triangles;
private Vector3[] vertices;
[Header("值域")]
public float[] element = new float[5] { 10, 10, 10, 10, 10 };
private float sideLength = 10;
private float allAngle = 0;
private CanvasRenderer canvas;
[SerializeField]
private Material material;
private Mesh mesh;
//整体缩放
public float scale;
//[Header("描边:这块暂时没开发完")]
//public bool isRander = false;
//LineRenderer lineRenderer;
void Start()
{
SetVertices();
//if (isRander)
//{
// lineRenderer = transform.gameObject.AddComponent<LineRenderer>();
// lineRenderer.material = renderMaterial;
// lineRenderer.startWidth = 1;
// lineRenderer.endWidth = 1;
// lineRenderer.positionCount = element.Length + 1;
//}
}
private void Update()
{
for (int i = 1; i < vertices.Length; i++)
{
sideLength = element[i-1] * scale;
vertices[i] = Quaternion.Euler(0, 0, allAngle * i) * Vector3.up * sideLength;
}
mesh.vertices = vertices;
canvas.SetMesh(mesh);
//if(isRander)
//{
// SetLinePositions(vertices);
//}
}
//public void SetLinePositions(Vector3[] vector3s)
//{
// Vector3[] v3 = (Vector3[])vector3s.Clone();
// v3[0] = v3[v3.Length - 1];
// //for (var i = 0; i < v3.Length; i++)
// // v3[i] += Vector3.up * 960 + Vector3.right * 540;
// lineRenderer.SetPositions(v3);
//}
/// <summary>
/// 设置点位
/// </summary>
void SetVertices()
{
int count = element.Length + 1;
canvas = GetComponent<CanvasRenderer>();
mesh = new Mesh();
vertices = new Vector3[count];
var uvs = new Vector2[count];
triangles = new int[count * 3];
var tangents = new Vector4[count];
Vector4 tangent = new Vector4(0, 1, 0, -1);
allAngle = (float)360 / (count - 1);
for (int i = 0; i < vertices.Length; i++) //循环顶点
{
vertices[i] = Quaternion.Euler(0, 0, allAngle * i) * Vector3.up * sideLength;
uvs[i] = Quaternion.Euler(0, 0, allAngle * i) * Vector3.up;
tangents[i] = tangent;
}
//为mesh的顶点赋值
for (int i = 0, index = 0; i < count - 1; i++, index += 3)
{
triangles[index + 0] = 0;
triangles[index + 1] = i == count - 2 ? 1 : 2 + i;//倒数第二
triangles[index + 2] = i == count - 2 ? count - 1 : 1 + i;//最后一个
}
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.tangents = tangents;
mesh.uv = uvs;
canvas.SetMesh(mesh);
canvas.SetMaterial(material, null);
}
}
最终实现的效果图如下:
关于该示例demo,我已经上传到我的资源中,有兴趣可以下载自己实验。