Unity绘制圆和缓动雷达图
Unity绘制圆和缓动雷达图
之前在做UI模块的时候遇到过需要做雷达图的效果,所以简单复习了一下
关于网格绘制
我们都知道Unity绘制图形是通过Mesh网格添加顶点进行绘制,那么知道顶点信息后如何实现图形的绘制,就是由Graphic
类来帮助我们实现。因此我们需要自定义一个类继承Graphic
,然后重写其OnPopulateMesh
方法,将其挂载到UI物体上。
public class RadarMap : Graphic { protected override void OnPopulateMesh(VertexHelper vh) { } }
注:若想要支持RectMask2D功能,则改为继承MaskableGraphic
即可
在OnPopulateMesh
方法中提供了VertexHelper
参数,这是Unity的顶点辅助类,通过它我们可以轻松实现添加顶点和绘制等操作了。
添加顶点
//参数是顶点坐标,颜色以及uv坐标 new VertexHelper().AddVert(Vector3 position, Color32 color, Vector2 uv0)
顶点的绘制
new VertexHelper().AddTriangle(int idx0, int idx1, int idx2);
绘制圆
对于Unity中的网格,我们只能通过一个个三角形拼接成不同的形状,包括Unity本身的物体网格也是如此,因此,画圆可以通过弧度和半径,以及圆的边长去绘制多个三角形,拼接而成一个圆
这是对画圆的一些总结
画圆的代码如下:
using UnityEngine; using UnityEngine.UI; public class RadarMap : Graphic { public Texture2D texture; public Color _color = Color.white; public int n; public float r; public override Texture mainTexture//赋值UI图片 { get { if (texture != null) { return texture;//如果有外部精灵则返回外部精灵的texture } if (material != null && material.mainTexture != null) { return material.mainTexture;//如果有材质则返回材质上的texture } return s_WhiteTexture;//什么都没有的情况返回默认的texture } } protected override void OnPopulateMesh(VertexHelper vh) { Rect rect = rectTransform.rect; r = rect.width < rect.height ? rect.width / 2 : rect.height / 2;//取当前最小的宽或高,取一半获得半径 if (n >= 3) { vh.Clear(); vh.AddVert(Vector3.zero, color, new Vector2(0.5f, 0.5f));//添加圆心点 float ang = 2 * Mathf.PI / n; for (int i = 0; i < n; i++) { float x = Mathf.Sin(i * ang) * r; float y = Mathf.Cos(i * ang) * r; float uvx = (x + r) / (2 * r);//通过圆上点+半径/直径求出uv坐标 float uvy = (y + r) / (2 * r); vh.AddVert(new Vector3(x, y, 0), color, new Vector3(uvx, uvy));//添加顶点 if (i == 0) { vh.AddTriangle(0, n, 1);//第一次绘制最后一部分 } else { vh.AddTriangle(0, i, i + 1);//依次绘制 } } } } }
画出圆的效果
绘制雷达图
根据绘制圆我们可以发现,绘制雷达图是同理的,同样是添加一个圆心点并根据半径和弧度求出圆上的顶点,只是雷达图每个顶点的位置都跟雷达图中的数值有关。因此,我们只需要添加一个数组,并将画圆的代码稍作修改就可以了
以下是雷达图的绘制代码:
using UnityEngine; using UnityEngine.UI; public class RadarMap : Graphic { public Texture2D texture; public Color _color = Color.white; public float[] arr = new float[0]; public float r; public override Texture mainTexture { get { if (texture != null) { return texture;//如果有外部精灵则返回外部精灵的texture } if (material != null && material.mainTexture != null) { return material.mainTexture;//如果有材质则返回材质上的texture } return s_WhiteTexture;//什么都没有的情况返回默认的texture } } //生成无背景雷达图 这里的生成方法和生成圆的方法是一致的 protected override void OnPopulateMesh(VertexHelper vh) { Rect rect = rectTransform.rect; int n = arr.Length; //取当前最小的宽或高,取一半获得半径 r = rect.width < rect.height ? rect.width / 2 : rect.height / 2; if (n >= 3) { vh.Clear(); //添加圆心点 vh.AddVert(Vector3.zero, color, new Vector2(0.5f, 0.5f)); float ang = 2 * Mathf.PI / n; for (int i = 0; i < n; i++) { //通过数组中数据的值为雷达图赋值,最大值为半径 float x = Mathf.Sin(i * ang) * (arr[i] < r ? arr[i] : r); float y = Mathf.Cos(i * ang) * (arr[i] < r ? arr[i] : r); //通过圆上点+半径/直径求出uv坐标 float uvx = (x + r) / (2 * r); float uvy = (y + r) / (2 * r); //添加顶点 vh.AddVert(new Vector3(x, y, 0), color, new Vector3(uvx, uvy)); if (i == 0) { //第一次绘制最后一部分 vh.AddTriangle(0, n, 1); } else { //依次绘制 vh.AddTriangle(0, i, i + 1); } } } } }
最后的效果如下
缓动则通过Mathf.Lerp
的差值函数实现,也可以直接使用公式( max - min ) * p + min
代码如下:
//缓动代码块,这里的数组和集合已经赋值过 public RadarMap radarMap; bool isDrow = false; List<float> arr = new List<float>(); float[] arry; float MaxTime = 3f;//缓动最大时间 float nowTime = 0f;//缓动开始时间 private void Update() { if (isDrow) { nowTime += Time.deltaTime; for (int i = 0; i < arr.Count; i++) { //差值函数,始终在当前点和目标点中间取一个参数 arry[i] = Mathf.Lerp(0, arr[i], nowTime / MaxTime); //当达到了这个值以后,循环结束,清空缓存原始数据的集合 if (i == arr.Count - 1 && arr[i] - arry[i] <= 0.1f) { Mathf.Round(arry[i]); arr.Clear(); isDrow = false; nowTime = 0f; } } //清除脏数据 radarMap.SetAllDirty(); //将每次算出的差值赋给RadarMap radarMap.arr = arry; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!