NGUI中用来排列ui的常用的两个组件是:UITable、UIGrid
但是它们只能横着排或竖着排,不能按圆圈排列
自己写一个吧
效果如下
用法
把下面的UICircleTable.cs
脚本保存的Assets/Scripts
目录中
再把UICircleTableInspector.cs
脚本保存到Assets/Editor
目录中
然后创建一个父节点Container,并在其子节点中创建n个Sprite,在Container节点上挂UICircleTable
组件,调整设置
参数说明:
Angle:角度
Radius:半径
SyncAngle: 是否同步子节点角度
BaseOnChildCnt:是否基于子节点平均角度
HideInactive:是否隐藏组件参加排序
根据自己的需求调整设置即可
注意 real time refresh在调整预设的时候要勾上,这样就可以实时预览效果,Apply预设之前再把real time refresh去掉勾选即可
代码如下
// UICircleTable.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UICircleTable : MonoBehaviour
{
public void Refresh()
{
childTrans.Clear();
var cnt = transform.childCount;
for (int i = 0; i < cnt; ++i)
{
var c = transform.GetChild(i);
if (!hideInactive || c.gameObject.activeSelf)
childTrans.Add(c);
}
var deltaAngle = (baseOnChildCnt ? 360f / childTrans.Count : angle);
var curAngle = 0f;
foreach (var child in childTrans)
{
var formatAngle = curAngle / 180f * Mathf.PI;
var posX = radius * Mathf.Sin(formatAngle);
var posY = radius * Mathf.Cos(formatAngle);
child.localPosition = new Vector3(posX, posY, 0);
if (syncAngle)
child.localEulerAngles = new Vector3(0, 0, -curAngle);
else
child.localEulerAngles = Vector3.zero;
curAngle += deltaAngle;
}
}
private void ResetChild()
{
childTrans.Clear();
for (int i = 0, cnt = transform.childCount; i < cnt; i++)
{
Transform child = transform.GetChild(i);
if (!child.name.StartsWith(childName)) continue;
if (!hideInactive || (child.gameObject.activeSelf))
childTrans.Add(child);
}
}
private void SetChildPos()
{
int cnt = childTrans.Count;
if (cnt == 0) return;
float angle = 360f / cnt;
float angle_offset = cnt % 2 == 0 ? 0 : angle * 0.5f;
//Vector3 tran_pos = transform.localPosition;
for (int i = 0; i < cnt; i++)
{
float item_angle = (angle * i + angle_offset + startAngle) * Mathf.Deg2Rad;
float x = radius * Mathf.Sin(item_angle);
float y = GetRadiusFactor(item_angle, x);
Vector3 item_pos = new Vector3(x, y, 0);
childTrans[i].localPosition = item_pos;
}
}
[ContextMenu("ExecuteSetPos")]
public void ExecuteSetPos()
{
ResetChild();
SetChildPos();
}
private float GetRadiusFactor(float item_angle, float x)
{
float y = radius * Mathf.Cos(item_angle);
if (radius_B > 0)
{
float ellipse_y = Mathf.Sqrt(1 - x * x / (radius * radius)) * radius_B;
if (y >= 0) return ellipse_y;
else return -ellipse_y;
}
return y;
}
/// <summary>
/// 角度
/// </summary>
public float angle;
/// <summary>
/// 半径
/// </summary>
public float radius = 100;
/// <summary>
/// 是否同步子节点角度
/// </summary>
public bool syncAngle;
/// <summary>
/// 是否基于子节点平均角度
/// </summary>
public bool baseOnChildCnt;
/// <summary>
/// 是否隐藏组件参加排序
/// </summary>
public bool hideInactive = true;
public string childName = string.Empty;
public float startAngle = 0;
public float radius_B;
private List<Transform> childTrans = new List<Transform>();
}
// UICircleTableInspector.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(UICircleTable), true)]
public class UICircleTableInspector : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
m_realTimeRefresh = GUILayout.Toggle(m_realTimeRefresh, "real time refresh");
if (m_realTimeRefresh)
{
var t = target as UICircleTable;
t.Refresh();
}
if (GUILayout.Button("Refresh"))
{
var t = target as UICircleTable;
t.Refresh();
}
}
private bool m_realTimeRefresh;
}