[UGUI]圆形Image

参考链接:

http://www.cnblogs.com/leoin2012/p/6425089.html

前面说过Mask组件会影响性能:https://www.cnblogs.com/lyh916/p/10587632.html

因此,尽量少使用Mask,对于类似技能图标那样的圆形图片,可以考虑用本文的方式去实现。

1.CircleImage.cs

  1 using UnityEngine;
  2 using UnityEngine.UI;
  3 using UnityEngine.Sprites;
  4 using System.Collections.Generic;
  5 
  6 public class CircleImage : Image {
  7 
  8     public float fillPercent = 1f;       //填充比例
  9     public int fillNum = 100;            //填充个数
 10     private List<Vector2> outerVertexs;  //圆上顶点列表
 11 
 12     protected override void Awake()
 13     {
 14         base.Awake();
 15         outerVertexs = new List<Vector2>();
 16     }
 17 
 18     protected override void OnPopulateMesh(VertexHelper toFill)
 19     {
 20         if (overrideSprite == null)
 21         {
 22             base.OnPopulateMesh(toFill);
 23             return;
 24         }
 25 
 26         switch (type)
 27         {
 28             case Type.Simple:
 29                 GenerateSimpleSprite(toFill, preserveAspect);
 30                 break;
 31         }
 32     }
 33 
 34     void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
 35     {
 36         vh.Clear();
 37         outerVertexs.Clear();
 38 
 39         //计算准备
 40         Vector4 uv = (overrideSprite != null) ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
 41 
 42         float degreeDelta = 2 * Mathf.PI / fillNum;
 43         int curNum = (int)(fillNum * fillPercent);
 44         float width = rectTransform.rect.width;
 45         float height = rectTransform.rect.height;
 46         float radius = width * 0.5f;
 47 
 48         float uvCenterX = (uv.x + uv.z) * 0.5f;
 49         float uvCenterY = (uv.y + uv.w) * 0.5f;
 50         float uvScaleX = (uv.z - uv.x) / width;
 51         float uvScaleY = (uv.w - uv.y) / height;
 52 
 53         //添加第一个点
 54         UIVertex uiVertex = new UIVertex();
 55         uiVertex.color = color;
 56         uiVertex.position = Vector2.zero;
 57         uiVertex.uv0 = new Vector2(uvCenterX, uvCenterY);
 58         vh.AddVert(uiVertex);
 59 
 60         //添加圆上的点
 61         int vertNum = (fillPercent == 1) ? curNum : curNum + 1;
 62         for (int i = 1; i <= vertNum; i++)
 63         {
 64             float curDegree = (i - 1) * degreeDelta;
 65             float cosA = Mathf.Cos(curDegree);
 66             float sinA = Mathf.Sin(curDegree);
 67             Vector2 curVertice = new Vector2(cosA * radius, sinA * radius);
 68 
 69             uiVertex = new UIVertex();
 70             uiVertex.color = color;
 71             uiVertex.position = curVertice;
 72             uiVertex.uv0 = new Vector2(uvCenterX + curVertice.x * uvScaleX, uvCenterY + curVertice.y * uvScaleY);
 73             vh.AddVert(uiVertex);
 74 
 75             outerVertexs.Add(curVertice);
 76         }
 77 
 78         //连接点
 79         for (int i = 1; i < vertNum; i++)
 80         {
 81             vh.AddTriangle(0, i + 1, i);
 82         }
 83         if (fillPercent == 1)
 84         {
 85             vh.AddTriangle(0, 1, curNum);
 86         }
 87 
 88         //连接点击区域
 89         if (fillPercent < 1)
 90         {
 91             outerVertexs.Add(Vector2.zero);
 92         }
 93     }
 94 
 95     public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
 96     {
 97         Sprite sprite = overrideSprite;
 98         if (sprite == null)
 99             return true;
100 
101         Vector2 local;
102         RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local);
103 
104         return MathTool.IsPointInPolygon(local, outerVertexs);
105     }
106 }

效果如下:

分析:

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

 1 using UnityEditor;
 2 using UnityEditor.UI;
 3 
 4 [CustomEditor(typeof(CircleImage))]
 5 public class CircleImageEditor : ImageEditor {
 6 
 7     SerializedProperty fillPercent;
 8     SerializedProperty fillNum;
 9 
10     protected override void OnEnable()
11     {
12         base.OnEnable();
13         fillPercent = serializedObject.FindProperty("fillPercent");
14         fillNum = serializedObject.FindProperty("fillNum");
15     }
16 
17     public override void OnInspectorGUI()
18     {
19         base.OnInspectorGUI();
20 
21         serializedObject.Update();
22 
23         fillPercent.floatValue = EditorGUILayout.Slider("填充比例", fillPercent.floatValue, 0, 1);
24         fillNum.intValue = EditorGUILayout.IntSlider("填充个数", fillNum.intValue, 1, 100);
25 
26         serializedObject.ApplyModifiedProperties();
27     }
28 }
原文地址:https://www.cnblogs.com/lyh916/p/10611787.html