-
-
Save MeisterDerMagie/f99f8d7af7f95fa69c19f4f17dfff6d8 to your computer and use it in GitHub Desktop.
Create circles/ellipses in Unity UI system in one of three modes: FillInside, FillOutside and Edge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.UI; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
// Custom Editor to order the variables in the Inspector similar to Image component | |
[CustomEditor( typeof( CircleGraphic ) ), CanEditMultipleObjects] | |
public class CircleGraphicEditor : Editor | |
{ | |
private SerializedProperty colorProp; | |
private void OnEnable() | |
{ | |
colorProp = serializedObject.FindProperty( "m_Color" ); | |
} | |
public override void OnInspectorGUI() | |
{ | |
serializedObject.Update(); | |
EditorGUILayout.PropertyField( colorProp ); | |
DrawPropertiesExcluding( serializedObject, "m_Script", "m_Color", "m_OnCullStateChanged" ); | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
#endif | |
[RequireComponent( typeof( CanvasRenderer ) )] | |
[AddComponentMenu( "UI/Circle Graphic", 12 )] | |
public class CircleGraphic : MaskableGraphic | |
{ | |
public enum Mode { FillInside = 0, FillOutside = 1, Edge = 2 }; | |
#pragma warning disable 0649 | |
[SerializeField] | |
private int detail = 64; | |
[SerializeField] | |
private Mode mode; | |
[SerializeField] | |
[Tooltip( "Edge mode only" )] | |
private float edgeThickness = 1; | |
#pragma warning restore 0649 | |
private Vector2 uv = Vector2.zero; | |
private Color32 color32; | |
private float width = 1f, height = 1f; | |
private float deltaWidth, deltaHeight; | |
private float deltaRadians; | |
protected override void OnPopulateMesh( VertexHelper vh ) | |
{ | |
Rect r = GetPixelAdjustedRect(); | |
color32 = color; | |
width = r.width * 0.5f; | |
height = r.height * 0.5f; | |
vh.Clear(); | |
Vector2 pivot = rectTransform.pivot; | |
deltaWidth = r.width * ( 0.5f - pivot.x ); | |
deltaHeight = r.height * ( 0.5f - pivot.y ); | |
if( mode == Mode.FillInside ) | |
{ | |
deltaRadians = 360f / detail * Mathf.Deg2Rad; | |
FillInside( vh ); | |
} | |
else if( mode == Mode.FillOutside ) | |
{ | |
int quarterDetail = ( detail + 3 ) / 4; | |
deltaRadians = 360f / ( quarterDetail * 4 ) * Mathf.Deg2Rad; | |
vh.AddVert( new Vector3( width + deltaWidth, height + deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( -width + deltaWidth, height + deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( -width + deltaWidth, -height + deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( width + deltaWidth, -height + deltaHeight, 0f ), color32, uv ); | |
int triangleIndex = 4; | |
FillOutside( vh, new Vector3( width + deltaWidth, deltaHeight, 0f ), 0, quarterDetail, ref triangleIndex ); | |
FillOutside( vh, new Vector3( deltaWidth, height + deltaHeight, 0f ), 1, quarterDetail, ref triangleIndex ); | |
FillOutside( vh, new Vector3( -width + deltaWidth, deltaHeight, 0f ), 2, quarterDetail, ref triangleIndex ); | |
FillOutside( vh, new Vector3( deltaWidth, -height + deltaHeight, 0f ), 3, quarterDetail, ref triangleIndex ); | |
} | |
else | |
{ | |
deltaRadians = 360f / detail * Mathf.Deg2Rad; | |
GenerateEdges( vh ); | |
} | |
} | |
// Uncomment for precise raycasts/clicks (might be processor-heavy) | |
//public override bool Raycast( Vector2 sp, Camera eventCamera ) | |
//{ | |
// if( base.Raycast( sp, eventCamera ) ) | |
// { | |
// Vector2 localPoint; | |
// if( RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, sp, eventCamera, out localPoint ) ) | |
// { | |
// Vector2 deltaPoint = localPoint - rectTransform.rect.center; | |
// float distance = deltaPoint.sqrMagnitude; | |
// float angle = Vector2.Angle( Vector2.right, new Vector2( deltaPoint.x / width, deltaPoint.y / height ) ) * Mathf.Deg2Rad; | |
// Vector2 edge = new Vector2( width * Mathf.Cos( angle ), height * Mathf.Sin( angle ) ); | |
// if( mode == Mode.FillInside ) | |
// return edge.sqrMagnitude >= distance; | |
// if( mode == Mode.FillOutside ) | |
// return edge.sqrMagnitude <= distance; | |
// if( edge.sqrMagnitude < distance ) | |
// return false; | |
// angle = Vector2.Angle( Vector2.right, new Vector2( deltaPoint.x / ( width - edgeThickness ), deltaPoint.y / ( height - edgeThickness ) ) ) * Mathf.Deg2Rad; | |
// Vector2 edgeInner = new Vector2( ( width - edgeThickness ) * Mathf.Cos( angle ), ( height - edgeThickness ) * Mathf.Sin( angle ) ); | |
// Debug.DrawLine( transform.position, transform.position + (Vector3) edgeInner ); | |
// Debug.DrawLine( transform.position, transform.position + (Vector3) deltaPoint ); | |
// return edgeInner.sqrMagnitude <= distance; | |
// } | |
// } | |
// return false; | |
//} | |
private void FillInside( VertexHelper vh ) | |
{ | |
vh.AddVert( new Vector3( deltaWidth, deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( width + deltaWidth, deltaHeight, 0f ), color32, uv ); | |
int triangleIndex = 2; | |
for( int i = 1; i < detail; i++, triangleIndex++ ) | |
{ | |
float radians = i * deltaRadians; | |
vh.AddVert( new Vector3( Mathf.Cos( radians ) * width + deltaWidth, Mathf.Sin( radians ) * height + deltaHeight, 0f ), color32, uv ); | |
vh.AddTriangle( triangleIndex, triangleIndex - 1, 0 ); | |
} | |
vh.AddTriangle( 1, triangleIndex - 1, 0 ); | |
} | |
private void FillOutside( VertexHelper vh, Vector3 initialPoint, int quarterIndex, int detail, ref int triangleIndex ) | |
{ | |
int startIndex = quarterIndex * detail; | |
int endIndex = ( quarterIndex + 1 ) * detail; | |
vh.AddVert( initialPoint, color32, uv ); | |
triangleIndex++; | |
for( int i = startIndex + 1; i <= endIndex; i++, triangleIndex++ ) | |
{ | |
float radians = i * deltaRadians; | |
vh.AddVert( new Vector3( Mathf.Cos( radians ) * width + deltaWidth, Mathf.Sin( radians ) * height + deltaHeight, 0f ), color32, uv ); | |
vh.AddTriangle( quarterIndex, triangleIndex - 1, triangleIndex ); | |
} | |
} | |
private void GenerateEdges( VertexHelper vh ) | |
{ | |
float innerWidth = width - edgeThickness; | |
float innerHeight = height - edgeThickness; | |
vh.AddVert( new Vector3( width + deltaWidth, deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( innerWidth + deltaWidth, deltaHeight, 0f ), color32, uv ); | |
int triangleIndex = 2; | |
for( int i = 1; i < detail; i++, triangleIndex += 2 ) | |
{ | |
float radians = i * deltaRadians; | |
float cos = Mathf.Cos( radians ); | |
float sin = Mathf.Sin( radians ); | |
vh.AddVert( new Vector3( cos * width + deltaWidth, sin * height + deltaHeight, 0f ), color32, uv ); | |
vh.AddVert( new Vector3( cos * innerWidth + deltaWidth, sin * innerHeight + deltaHeight, 0f ), color32, uv ); | |
vh.AddTriangle( triangleIndex, triangleIndex - 2, triangleIndex - 1 ); | |
vh.AddTriangle( triangleIndex, triangleIndex - 1, triangleIndex + 1 ); | |
} | |
vh.AddTriangle( 0, triangleIndex - 2, triangleIndex - 1 ); | |
vh.AddTriangle( 0, triangleIndex - 1, 1 ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment