unity雷达图和蛛网图在游戏中的应用非常广泛,很多游戏都会用到雷达图来直观显示英雄的属性,或者在战斗结束后生成对局的表现。
1.1.绘制蛛网图
通过Mesh绘制蛛网图雷达图对应组件上必须要挂上(画布渲染器)CanvasRenderer组件,因为雷达图是在UI上显示的。可以直接在游戏对象上手动挂载,也可以像我一样用RequireComponent特性在脚本上挂载。
1.2.蛛网图脚本:DrawSpiderWeb
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class DrawSpiderWeb : MaskableGraphic
{
[SerializeField, Header("颜色")]
Color backgroundColor;
[SerializeField, Header("边数")]
int n = 8;
[SerializeField, Header("内半径")]
float r;//内径
[SerializeField, Header("线宽")]
float lineWide;
[SerializeField, Header("层数")]
int tier;//层数
[SerializeField, Header("线距")]
float space;//线与线之间的间距
float angle;//角度
float radius;//整个图的半径
/// <summary>
/// 获取半径的方法
/// </summary>
/// <returns></returns>
public float GetRadius()
{
//半径 从内向外,内半径 +(层数-1)*(线宽+间距)
radius = (tier - 1) * (space + lineWide) + r;
return radius;
}
protected override void Start()
{
base.Start();
angle = 2 * Mathf.PI / n;
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
for (int j = 0; j < tier; j++)
{
int count = j * n * 2; //顶点数量
for (int i = 0; i < n; i++)
{
//线内的点
float intx = Mathf.Sin(angle * i) * (r + j * (lineWide + space));
float inty = Mathf.Cos(angle * i) * (r + j * (lineWide + space));
vh.AddVert(new Vector3(intx, inty, 0), backgroundColor, Vector4.zero);
//线外的点
float outx = Mathf.Sin(angle * i) * (r + lineWide + j * (lineWide + space));
float outy = Mathf.Cos(angle * i) * (r + lineWide + j * (lineWide + space));
vh.AddVert(new Vector3(outx, outy, 0), backgroundColor, Vector4.zero);
if (i == n - 1)
{
vh.AddTriangle(2 * i + 1 + count, 0 + count, 1 + count);
vh.AddTriangle(2 * i + 1 + count, 2 * i + count, 0 + count);
}
else
{
vh.AddTriangle(2 * i + 1 + count, 2 * i + count, 2 * (i + 1) + count);
vh.AddTriangle(2 * i + 1 + count, 2 * (i + 1) + count, 2 * (i + 1) + 1 + count);
}
}
//垂直部分
if (j == tier - 1)
{
//计算之前的下标总数 得出现在下标的起始点
int sum = 2 * n * tier;
for (int i = 0; i < n; i++)
{
float x = Mathf.Sin(angle * i) * (r + lineWide + j * (lineWide + space));
float y = Mathf.Cos(angle * i) * (r + lineWide + j * (lineWide + space));
//找到最外面的顶点位置
Vector3 dir = new Vector3(x, y, 0);
//计算最外面的顶点到中心点的方向
Vector3 width = (Quaternion.AngleAxis(90, Vector3.forward) * dir).normalized;
//计算最外面的顶点到中心的连线 求出连线的四个点
vh.AddVert(-width * 10f + dir.normalized, backgroundColor, Vector4.zero);
vh.AddVert(-width * 10f + dir, backgroundColor, Vector4.zero);
vh.AddVert(width * 10f + dir, backgroundColor, Vector4.zero);
vh.AddVert(width * 10f + dir.normalized, backgroundColor, Vector4.zero);
vh.AddTriangle(4 * i + sum, 4 * i + 1 + sum, 4 * i + 2 + sum);
vh.AddTriangle(4 * i + sum, 4 * i + 2 + sum, 4 * i + 3 + sum);
}
}
}
}
}
这里是可以自行设置蛛网图的相关属性的。
1.3.蛛网图效果:
1.4.思路分析
在这里我主要通过画图,然后计算所需要的变量之间的联系找到每层的顶点位置,以及半径的变化,不难发现,每一层有内外两层顶点,通过三角函数和分割数可以计算出每个顶点的位置,每一层可以通过实际半径进行一个偏移。一层是不需要间距的,后面每层都需要添加间距,所以我们不难算出蛛网图的实时半径就是:内径+线宽+(线宽+间距)*(层数 - 1)。
垂直方向的线可以考虑最外层顶点到(圆心)中心点的距离的线,可以看成一个矩形。通过垂直的向量可以求出四个点,在通过Mesh三角形连线绘制。
2.1绘制雷达图
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class DrawRadar : MaskableGraphic
{
[SerializeField]
Button btn;
int n = 5; //分割数
float angle; //角度
float r ; //半径
[SerializeField]
Color backgroundColor; //颜色
[SerializeField]
[Range(10, 100)]//设置范围
float[] radius;//属性半径
[SerializeField]
DrawSpiderWeb drawSpiderWeb;
protected override void Start()
{
base.Start();
angle = 2 * Mathf.PI / n;
//获取蛛网图的半径限制雷达图的最大半径
r = drawSpiderWeb.GetRadius();
string.Format("最大半径为{0}", r);
radius = new float[n];
SetRandomBelongs(n);
btn.onClick.AddListener(() =>
{
SetRandomBelongs(n);
//重建所有顶点
SetAllDirty();
});
}
/// <summary>
/// 随机属性
/// </summary>
/// <param name="n"></param>
private void SetRandomBelongs(int n)
{
for (int i = 0; i < n; i++)
{
radius[i] = Random.Range(10, 101);
}
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加顶点
vh.AddVert(new Vector3(0, 0, 0), backgroundColor, Vector4.zero);
for (int i = 0; i < n; i++)
{
float x = Mathf.Sin(angle * i) * r * radius[i] / 100;
float y = Mathf.Cos(angle * i) * r * radius[i] / 100;
vh.AddVert(new Vector3(x, y, 0), backgroundColor, Vector4.zero);
if (i == 0)
{
vh.AddTriangle(0, 1, n);
}
else
{
vh.AddTriangle(0, i, i + 1);
}
}
}
}
一般的雷达图都是五个属性,所以我们需要五个属性,就相当于有一个半径数组,属性值就是控制每个角的位置的值,可以在属性面板里任意更改查看效果。
2.2.最终效果:
可以点击按钮随机属性值。