圆形图片常用于游戏中,常见的场景如王者荣耀技能图标,但是Unity发动机本身没有提供类似的组件,需要开发人员自己实现。本文主要介绍了两种简单的圆形图片实现方法,并提供了一种实现技能CD以及精确的技能响应方法。
一、Mask遮罩实现
过程:创建一个父物,添加到父物中Mask和Image组件,并为Image添加圆形镂空图片,创建子物体添加Image组件,给Image添加想要实现圆形效果的图片。
可见锯齿效果明显,这是因为我给父物添加的背景图比较拉跨,是的Unity自带的Knob,可以去选择其他圆形背景来优化一下锯齿效果。
二、实现自定义
任何物体的显示过程都是通过的CPU首先计算顶点信息GPU绘制并最终显示在屏幕上,因此我们可以改变需要绘制的顶部信息以修改显示效果。首先需要了解以下预先信息:
1、OnPopulateMesh
该方法是Image中的一个可重写的方法protectedoverridevoidOnPopulateMesh(VertexHelper toFill)VectexHelper是存储绘图顶点信息的载体,GPU图形将根据参数中的信息绘制。我们可以自定义继承Image并重新实现该方法VertexHelper 只存储我们想要显示的顶点。
2、UV
UV它是一种二维坐标信息,可以简单地看作是四位向量(x,y,z,w)
可以使用上述矩形位置信息x,y,z,w由于需要使用四个数字来表示系统底层UV而在Unity世界坐标被用来将图片的位置信息转换为UV坐标就可以了。
3、坐标转换
如何将图片的位置信息转换为相应的UV坐标呢?比如一张图4000。*400,我们可以通过工具类获得图片UV比如坐标长度是(0、0、1、1),那么原始图片上的点是如何映射到的呢?UV在坐标上,它们之间有一个比例转换系数。
宽高对应比例缩放,计算出缩放系数后,那么对于原始图片上的任一点,我们都能得到在UV相应的坐标信息。
4.圆是怎么显示的?
我们知道在计算机底层根本不知道圆圈,圆是由多个三角形、三角形、四边形、五边形、六边形、十边形、N边形,它们的形状越来越接近圆形。
当图中有足够的三角形时,我们看到的形状越接近圆,当给定圆半径时R,当给定该圆由多少三角形组成时,我们可以计算每个三角形的弧度Radian,根据勾股定理不难得出A,B与圆心O坐标相比。
5、代码实现
为了方便理解,我尽量添加注释。如果只是想实现功能,请直接copy可以挂载脚本。
-
外层P:实际图片对应的矩形
-
内层Circle:想要图片显示的样子
-
任务:计算点A坐标赋值uvTemp.position 并将点A在UV相应的坐标赋值uvTemp.uv0
-
第一步:1、我们需要先确定O点的坐标,可以先记(0,0),A点击实际坐标即可记录
uvTemp.position = (0,0) (X,Y)
2.最后,按比例转换UV坐标
uvTemp.uv0 = new Vector2(xy.x * convertRatio.x uvCenter.x, xy.y * convertRatio.y uvCenter.y);
6、完整代码
using System.Collections.Generic; using UnityEngine; using UnityEngine.Sprites; using UnityEngine.UI; public class CircleImage : Image { [SerializeField] private float showPercent = 1f; [SerializeField] private int segments = 100;protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); float width = rectTransform.rect.width; float height = rectTransform.rect.height; Vector2 uv = GetUV(overrideSprite); Vector2 convertRatio = GetConvetRatio(uv.x, uv.y, width, height); Vector2 uvCenter = GetUvCenter(uv.x, uv.y); Vector2 originPos = GetOriginPos(width, height); UIVertex origin = new UIVertex(); ///设置原始颜色渐变 byte c = (byte) (showPercent * 255); origin.color = new Color32(c, c, c, 255); origin.position = originPos; origin.uv0 = new Vector2(Vector2.zero.x * convertRatio.x uvCenter.x, Vector2.zero.y * convertRatio.y uvCenter.y); vh.AddVert(origin); float radian = Mathf.PI * 2 / segments; float curRadian = 0; float radius = width * 0.5f; int realSegment = (int) (showPercent * segments); for (int i = 0; i < segments 1; i ) { float x = Mathf.Cos(curRadian) * radius; float y = Mathf.Sin(curRadian) * radius; curRadian = radian; Vector2 xy = new Vector2(x, y); UIVertex uvTemp = new UIVertex(); if (i < realSegment) { uvTemp.color = color; } else { if (realSegment == segments) { uvTemp.color = color; } else { uvTemp.color = new Color32(60, 60, 60, 255); } } uvTemp.position = xy originPos; uvTemp.uv0 = new Vector2(xy.x * convertRatio.x uvCenter.x, xy.y * convertRatio.y uvCenter.y); vh.AddVert(uvTemp); } int id = 1; for (int i = 0; i < segments; i ) { vh.AddTriangle(id, 0, id 1); id ; } } private Vector2 GetConvetRatio(float uvWidth, float uvHeight, float width, float height) { Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height); return convertRatio; } private Vector2 GetUvCenter(float uvWidth, float uvHeight) { Vector2 center = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f); return center; } private Vector2 GetOriginPos(float width, float height) { Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, ((0.5f - rectTransform.pivot.y) * height)); return originPos; } private Vector2 GetUV(Sprite sprite) { Vector4 temp = sprite!= null ? DataUtility.GetOuterUV(sprite) : Vector4.zero;
float uvHeight = temp.w - temp.y;
float uvWidth = temp.z - temp.x;
Vector2 uv = new Vector2(uvWidth, uvHeight);
return uv;
}
}
7、视频效果
8、总结
实现圆形图片还是比较简单的,特别是CD效果,也是控制三角形定点实现的。
欢迎搜索关注微信公众号,这里有 一只会Coding的柴柴等你哦~