Skip to content

Instantly share code, notes, and snippets.

@mitay-walle
Created October 17, 2023 22:20
Show Gist options
  • Save mitay-walle/8310d6cdf19d6a122bbe1a88c1acfdca to your computer and use it in GitHub Desktop.
Save mitay-walle/8310d6cdf19d6a122bbe1a88c1acfdca to your computer and use it in GitHub Desktop.
Unity uGUI Circle Layout Group
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace Plugins.mitaywalle.UI.Layout
{
[ExecuteAlways]
public class UICircleLayoutGroup : LayoutGroup
{
static readonly Vector2 HALF_VECTOR = new Vector2(0.5f, 0.5f);
[SerializeField] float innerRadius = 100;
[Range(-360, 360)] public float offset;
[Range(0, 360)] public float maxDegree = 360;
[SerializeField] bool Resize = true;
[SerializeField] bool reverseArrangement;
public int count { get; private set; }
public int ChildCount() => rectChildren.Count;
public float IndexOf(RectTransform rectTransform1) => rectChildren.IndexOf(rectTransform1);
protected override void OnTransformChildrenChanged()
{
base.OnTransformChildrenChanged();
CalculateRadial();
}
public override void SetLayoutVertical() => CalculateRadial();
public override void SetLayoutHorizontal() => CalculateRadial();
public override void CalculateLayoutInputVertical() => CalculateRadial();
public override void CalculateLayoutInputHorizontal() => CalculateRadial();
protected override void OnRectTransformDimensionsChange() => CalculateRadial();
void CalculateRadial()
{
if (transform.childCount == 0) return;
base.CalculateLayoutInputHorizontal();
var children = rectChildren;
int childrenToFormat = children.Count;
m_Tracker.Clear();
count = childrenToFormat;
Rect rect = rectTransform.rect;
float radiusX = rect.width / 2;
float radiusY = rect.height / 2;
radiusX -= innerRadius / 2;
radiusY -= innerRadius / 2;
float degreeStep = maxDegree / childrenToFormat;
float currentDegree = offset + degreeStep / 2;
if (reverseArrangement)
{
degreeStep *= -1;
currentDegree *= -1;
}
DrivenTransformProperties properties = DrivenTransformProperties.Anchors |
DrivenTransformProperties.AnchoredPosition |
DrivenTransformProperties.Pivot;
Vector2 sizeVector = default;
if (Resize) properties |= DrivenTransformProperties.SizeDelta;
if (Resize)
{
float size = GetSize(childrenToFormat, maxDegree);
sizeVector = new Vector2(size, size);
}
for (int i = 0; i < childrenToFormat; i++)
{
RectTransform child = children[i];
m_Tracker.Add(this, child, properties);
var vector = new Vector3(Mathf.Cos(currentDegree * Mathf.Deg2Rad) * radiusX, Mathf.Sin(currentDegree * Mathf.Deg2Rad) * radiusY, 0);
child.localPosition = vector;
child.anchorMin = child.anchorMax = child.pivot = HALF_VECTOR;
if (Resize) child.sizeDelta = sizeVector;
currentDegree += degreeStep;
}
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
float GetSize(int childrenCount, float maxAngle)
{
float outer = rectTransform.rect.width / 2;
float inner = outer - innerRadius;
float halfRadius = outer - inner;
float size1 = Mathf.Abs(outer - inner);
float step = maxAngle / childrenCount;
Vector3 vector = new Vector2(1 * halfRadius, 0);
Vector3 vector2 = new Vector2(Mathf.Cos(step * Mathf.Deg2Rad) * halfRadius, Mathf.Sin(step * Mathf.Deg2Rad) * halfRadius);
float size2 = (vector - vector2).magnitude;
float size = Mathf.Min(size1, size2);
return size;
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
EditorApplication.delayCall += CalculateRadial;
}
#endif
}
}
@mitay-walle
Copy link
Author

Screenshot_17
Screenshot_16

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment