using System.Collections.Generic; using UnityEngine; using UnityEngine.Sprites; using UnityEngine.UI; [AddComponentMenu("UI/Custom/CircleHollow Image")] [DisallowMultipleComponent] [RequireComponent(typeof(Image))] public class CircleHollowImage:BaseMeshEffect,ICanvasRaycastFilter { [SerializeField] Vector2 m_Center=Vector2.zero; public Vector2 center { get { return m_Center; } set { m_Center = value; if(this.graphic != null) { this.graphic.SetVerticesDirty(); } } } [SerializeField] Vector2 m_HollowArea=new Vector2(50,50); public Vector2 cell { get { return m_HollowArea; } set { m_HollowArea = value; if(this.graphic != null) { this.graphic.SetVerticesDirty(); } } } [Range(32,128)] [SerializeField] int m_Segements = 32; public int segements { get { return m_Segements; } } private Image m_Image; public Image image { get { return m_Image ?? (m_Image = this.AddMissingComponent()); } } protected List innerVertices; protected List outterVertices; protected override void Awake() { innerVertices = new List(); outterVertices = new List(); } public override void ModifyMesh(VertexHelper vh) { vh.Clear(); innerVertices.Clear(); outterVertices.Clear(); var degreeDelta = (float)(2 * Mathf.PI / segements); var realSegements = segements; var width = image.rectTransform.rect.width; var height = image.rectTransform.rect.height; var outerArea = new Vector2(0.5f * width, 0.5f * height); // var realCenter = new Vector2(Mathf.Clamp(center.x,-width * 0.5f + cell.x,width * 0.5f - cell.x), // Mathf.Clamp(center.y,-height * 0.5f + cell.y,height * 0.5f - cell.y)); var realCenter = center; var uv = image.overrideSprite != null ? DataUtility.GetOuterUV(image.overrideSprite) : Vector4.zero; var uvCenterX = (uv.x + uv.z) * 0.5f; var uvCenterY = (uv.y + uv.w) * 0.5f; var uvScaleX = (uv.z - uv.x) / width; var uvScaleY = (uv.w - uv.y) / height; UIVertex uiVertex; var degree = Mathf.PI * 0.5f; var position = Vector2.zero; var uv0 = Vector2.zero; var verticeCount = 0; var triangleCount = 0; verticeCount = realSegements * 2; for(int i = 0;i < verticeCount;i += 2) { var cosA = Mathf.Cos(degree); var sinA = Mathf.Sin(degree); degree = degree - degreeDelta; position = new Vector3(realCenter.x + cosA * cell.x,realCenter.y + sinA * cell.y); uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); uiVertex = UIUtility.PackageUIVertex(position,uv0,image.color); vh.AddVert(uiVertex); innerVertices.Add(position); position = new Vector3(Mathf.Sign(cosA * 2f) * outerArea.x,Mathf.Sign(sinA * 2f) * outerArea.y); uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); uiVertex = UIUtility.PackageUIVertex(position,uv0,image.color); vh.AddVert(uiVertex); outterVertices.Add(position); } triangleCount = realSegements * 3 * 2; for(int i = 0,vIdx = 0;i < triangleCount - 6;i += 6,vIdx += 2) { vh.AddTriangle(vIdx + 1,vIdx,vIdx + 3); vh.AddTriangle(vIdx,vIdx + 2,vIdx + 3); } vh.AddTriangle(verticeCount - 1,verticeCount - 2,1); vh.AddTriangle(verticeCount - 2,0,1); } public virtual bool IsRaycastLocationValid(Vector2 screenPoint,Camera eventCamera) { var sprite = image.overrideSprite; if(sprite == null) { return true; } Vector2 local; RectTransformUtility.ScreenPointToLocalPointInRectangle(image.rectTransform,screenPoint,eventCamera,out local); return Contains(local,outterVertices,innerVertices); } protected bool Contains(Vector2 p,List outterVertices,List innerVertices) { var crossNumber = 0; crossNumber += UIUtility.RayCrossingCount(p,innerVertices); crossNumber += UIUtility.RayCrossingCount(p,outterVertices); return (crossNumber & 1) == 1; } }