参考链接:
http://www.cnblogs.com/leoin2012/p/6425089.html
前面说过Mask组件会影响性能:https://www.cnblogs.com/lyh916/p/10587632.html
因此,尽量少使用Mask,对于类似技能图标那样的圆形图片,可以考虑用本文的方式去实现。
1.CircleImage.cs
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Sprites;
using System.Collections.Generic; public class CircleImage : Image { public float fillPercent = 1f; //填充比例
public int fillNum = ; //填充个数
private List<Vector2> outerVertexs; //圆上顶点列表 protected override void Awake()
{
base.Awake();
outerVertexs = new List<Vector2>();
} protected override void OnPopulateMesh(VertexHelper toFill)
{
if (overrideSprite == null)
{
base.OnPopulateMesh(toFill);
return;
} switch (type)
{
case Type.Simple:
GenerateSimpleSprite(toFill, preserveAspect);
break;
}
} void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
{
vh.Clear();
outerVertexs.Clear(); //计算准备
Vector4 uv = (overrideSprite != null) ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; float degreeDelta = * Mathf.PI / fillNum;
int curNum = (int)(fillNum * fillPercent);
float width = rectTransform.rect.width;
float height = rectTransform.rect.height;
float radius = width * 0.5f; float uvCenterX = (uv.x + uv.z) * 0.5f;
float uvCenterY = (uv.y + uv.w) * 0.5f;
float uvScaleX = (uv.z - uv.x) / width;
float uvScaleY = (uv.w - uv.y) / height; //添加第一个点
UIVertex uiVertex = new UIVertex();
uiVertex.color = color;
uiVertex.position = Vector2.zero;
uiVertex.uv0 = new Vector2(uvCenterX, uvCenterY);
vh.AddVert(uiVertex); //添加圆上的点
int vertNum = (fillPercent == ) ? curNum : curNum + ;
for (int i = ; i <= vertNum; i++)
{
float curDegree = (i - ) * degreeDelta;
float cosA = Mathf.Cos(curDegree);
float sinA = Mathf.Sin(curDegree);
Vector2 curVertice = new Vector2(cosA * radius, sinA * radius); uiVertex = new UIVertex();
uiVertex.color = color;
uiVertex.position = curVertice;
uiVertex.uv0 = new Vector2(uvCenterX + curVertice.x * uvScaleX, uvCenterY + curVertice.y * uvScaleY);
vh.AddVert(uiVertex); outerVertexs.Add(curVertice);
} //连接点
for (int i = ; i < vertNum; i++)
{
vh.AddTriangle(, i + , i);
}
if (fillPercent == )
{
vh.AddTriangle(, , curNum);
} //连接点击区域
if (fillPercent < )
{
outerVertexs.Add(Vector2.zero);
}
} public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Sprite sprite = overrideSprite;
if (sprite == null)
return true; Vector2 local;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local); return MathTool.IsPointInPolygon(local, outerVertexs);
}
}
效果如下:
分析:
a.顶点数据
这里以pivot为(0.5,0.5)为例。在这种情况下,图片的位置中心和uv中心重合,即都在图片的中点处。因此这时位置和uv是成比例的,即uv.z - uv.x对应width,uv.w - uv.y对应height,这样就可以根据当前点的位置计算出对应的uv坐标。
关于圆上的顶点个数,当填充比例小于1时,顶点个数=三角形个数+1;当填充比例等于1时,顶点个数=三角形个数(因为点重合)
b.顶点连接
要按顺时针连接(顺时针表示正对屏幕,逆时针表示背对屏幕)。这里使用(0, i + 1, i)的顺序。
c.点击区域
使用这个算法:https://www.cnblogs.com/lyh916/p/10633132.html
要注意的是,当填充比例小于1时,要把原点也加上去,可以考虑一下下面的情况:
2.CircleImageEditor.cs
using UnityEditor;
using UnityEditor.UI; [CustomEditor(typeof(CircleImage))]
public class CircleImageEditor : ImageEditor { SerializedProperty fillPercent;
SerializedProperty fillNum; protected override void OnEnable()
{
base.OnEnable();
fillPercent = serializedObject.FindProperty("fillPercent");
fillNum = serializedObject.FindProperty("fillNum");
} public override void OnInspectorGUI()
{
base.OnInspectorGUI(); serializedObject.Update(); fillPercent.floatValue = EditorGUILayout.Slider("填充比例", fillPercent.floatValue, , );
fillNum.intValue = EditorGUILayout.IntSlider("填充个数", fillNum.intValue, , ); serializedObject.ApplyModifiedProperties();
}
}