NGUI圆形排列ui:UICircleTable

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;
}

相关文章

这篇文章将为大家详细讲解有关Unity3D中如何通过Animator动画...
这篇文章主要介绍了Unity3D如何播放游戏视频,具有一定借鉴价...
这篇文章给大家分享的是有关Unity3D各平台路径是什么的内容。...
小编给大家分享一下Unity3D如何实现移动平台上的角色阴影,希...
如何解析基于Unity3D的平坦四叉树地形与Virtual Texture的分...
这篇文章主要介绍Unity3D如何实现动态分辨率降低渲染开销,文...