using System.Collections.Generic; using UnityEngine; using UnityEngine.Sprites; using UnityEngine.UI; [DisallowMultipleComponent] [AddComponentMenu("UI/Custom/Circle Image")] [RequireComponent(typeof(Image))] public class RoundedRectangleImage:BaseMeshEffect,ICanvasRaycastFilter { [SerializeField] float m_Radius = 10f; public float radius { get { return m_Radius; } } [SerializeField] [Range(16,128)] int m_Segements = 16; public int segements { get { return m_Segements; } } [SerializeField] Vector2 m_RealArea = Vector2.one * 100; public Vector2 realArea { get { return m_RealArea; } } private Image m_Image; public Image image { get { return m_Image ?? (m_Image = this.AddMissingComponent()); } } List vertexPosition = new List(); public override void ModifyMesh(VertexHelper vh) { vh.Clear(); vertexPosition.Clear(); var tw = image.rectTransform.rect.width; var th = image.rectTransform.rect.height; 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) / tw; var uvScaleY = (uv.w - uv.y) / th; var interval = radius / (segements - 1); var center = new Vector2(realArea.x * 0.5f - radius,realArea.y * 0.5f - radius); for(int i = 0;i < segements;i++) { var position = new Vector2(); var offsetX = interval * i; position.x = center.x + offsetX; position.y = center.y + Mathf.Sqrt(radius * radius - offsetX * offsetX); vertexPosition.Add(position); var vertex = new UIVertex(); vertex.position = position; vertex.color = image.color; vertex.uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); vh.AddVert(vertex); } center = new Vector2(realArea.x * 0.5f - radius,-realArea.y * 0.5f + radius); for(int i = 0;i < segements;i++) { var position = new Vector2(); var offsetX = interval * i; position.x = center.x + radius - offsetX; position.y = center.y - Mathf.Sqrt(radius * radius - (radius - offsetX) * (radius - offsetX)); vertexPosition.Add(position); var vertex = new UIVertex(); vertex.position = position; vertex.color = image.color; vertex.uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); vh.AddVert(vertex); } center = new Vector2(-realArea.x * 0.5f + radius,-realArea.y * 0.5f + radius); for(int i = 0;i < segements;i++) { var position = new Vector2(); var offsetX = interval * i; position.x = center.x - offsetX; position.y = center.y - Mathf.Sqrt(radius * radius - offsetX * offsetX); vertexPosition.Add(position); var vertex = new UIVertex(); vertex.position = position; vertex.color = image.color; vertex.uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); vh.AddVert(vertex); } center = new Vector2(-realArea.x * 0.5f + radius,realArea.y * 0.5f - radius); for(int i = 0;i < segements;i++) { var position = new Vector2(); var offsetX = interval * i; position.x = center.x - radius + offsetX; position.y = center.y + Mathf.Sqrt(radius * radius - (radius - offsetX) * (radius - offsetX)); vertexPosition.Add(position); var vertex = new UIVertex(); vertex.position = position; vertex.color = image.color; vertex.uv0 = new Vector2(position.x * uvScaleX + uvCenterX,position.y * uvScaleY + uvCenterY); vh.AddVert(vertex); } var triangleCount = segements * 12 - 3; for(int i = 0,vIdx = 1;i < triangleCount - 3;i += 3,vIdx++) { vh.AddTriangle(vIdx,0,vIdx + 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,vertexPosition); } private bool Contains(Vector2 _p,List _vertexPositions) { var crossNumber = 0; crossNumber += UIUtility.RayCrossingCount(_p,_vertexPositions); return (crossNumber & 1) == 1; } }