Unity NGUI圆形排列UI

在游戏制作时,有很多圆形排列的UI,我们自己用肉眼很难发现位置的对错。

我们常使用的两个组件是:UITable、UIGrid

但是这两个都不支持圆形排列的

于是写了一种圆形排列

效果如下:

 核心代码:

UICircleTable.cs

// UICircleTable.cs
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

// UICircleTableInspector.cs
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;
}

用法:

将UICircleTable.cs 保存到Assets/Scripts

将UICircleTableInspector.cs保存到Assets/Editor目录中

挂载UICircleTable.cs

挂载UICircleTable.cs

 

参数说明:

Angle:单个UI所占用的角度(360°:10个 每个被分为36° ;12个 每个被分为30°)自己计算

Radius:圆的半径

SyncAngle: 是否同步子节点角度

BaseOnChildCnt:是否基于子节点平均角度

HideInactive:是否隐藏组件参加排序

Child Name:单个名字

Start Angle:开始显示时的角度

real time refresh:是否实时刷新(调整预设的时候要勾上,这样就可以实时预览效果,Apply预设之前再把real time refresh去掉勾选即可)

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Unity提供了处理UI的组件和工具,可以使用这些组件和工具来创建扇形排列UI元素。 首先,我们可以使用Unity的Canvas组件来创建UI元素的容器。在Canvas上创建一个空的GameObject,并将它作为Canvas的子对象,用来承载扇形排列UI元素。 然后,可以在这个空的GameObject上添加一个Image组件,用来显示扇形的形状。可以通过设置Image组件的形状为扇形,并调整扇形的大小、颜色、透明度等属性来定制UI元素的外观。 接下来,可以在这个扇形形状的GameObject上添加Text组件,用来显示UI元素的文字。可以设置Text组件的文本内容、颜色、字体等属性,根据需要定制显示的文字。 最后,可以使用Unity的Layout组件来实现扇形排列。可以在扇形形状的GameObject上添加一个Layout组件,将UI元素排列在指定的方向上。可以使用Layout组件的参数来定义扇形的角度、半径、间距等,以达到想要的扇形排列效果。 通过以上步骤,我们可以在Unity中创建一个扇形排列UI元素。可以根据自己的需求和创意来定制UI元素的外观和布局,实现各种各样的扇形排列效果。同时,通过使用Unity提供的其他功能和特性,还可以为这些UI元素添加交互、动画效果等,使其更加生动和吸引人。 ### 回答2: Unity UI的扇形排列是指在Unity引擎中使用UI组件来实现扇形形状的排列效果。 要实现扇形排列,首先需要创建一个UI组件的父对象,可以是Canvas或者Panel等。然后在该父对象下创建多个子对象,每个子对象代表一个UI元素,可以是Button、Image等。 接下来,我们需要编写脚本来实现扇形排列的逻辑。可以通过计算每个子对象在父对象上的位置和旋转角度,并将其应用到子对象的Transform组件上来实现。 一种实现的方法是通过极坐标来计算子对象的位置和旋转角度。我们可以设置一个角度范围,然后通过遍历所有子对象,在每个角度上生成一个子对象,并将其放置在父对象的中心位置。可以使用Mathf类的Deg2Rad将角度转换为弧度。 具体而言,可以按照以下步骤实现: 1. 遍历子对象,根据子对象在子对象列表中的索引i和子对象总数n,设置子对象的旋转角度为(angleRange / n) * i,其中angleRange为你想要设置的扇形角度范围。 2. 将该角度转换为弧度,然后使用Mathf.Sin和Mathf.Cos函数计算子对象在父对象上的位置坐标。可以使用半径r和中心位置(centerX, centerY)来计算。 3. 将计算得到的位置坐标应用到子对象的RectTransform组件上的anchoredPosition属性上。 4. 对于子对象的旋转角度,可以将其应用到子对象的Transform组件的rotation属性上。 通过以上步骤,我们可以实现扇形排列效果。根据需要可以调整扇形的角度范围、子对象的大小和颜色等来满足不同的设计需求。 ### 回答3: Unity中的UI(用户界面)系统具有强大的排列和布局功能,可以实现扇形排列。 要实现扇形排列,我们可以使用Unity的GridLayoutGroup组件。GridLayoutGroup是一种用于排列子对象的布局组件,它可以在网格、水平、垂直和其他常用布局模式中排列子对象。但是,默认情况下,GridLayoutGroup不支持扇形排列。 要实现扇形排列,我们可以通过编写自定义脚本来改变子对象的位置和角度。具体步骤如下: 1. 创建一个空物体,作为扇形排列的父物体。 2. 在父物体下创建子物体,作为要排列UI元素。 3. 在父物体上添加GridLayoutGroup组件,并将子对象的布局类型设置为Cell Size。 4. 在脚本中获取父物体和子物体的引用。 5. 计算每个子物体之间的角度差(可以根据需要设置)。 6. 循环遍历所有子物体,并根据其在父物体中的索引值,计算并设置其位置和旋转角度。 7. 运行游戏,就能看到UI元素按照扇形排列的效果。 需要注意的是,实现扇形排列可能需要一些数学计算,如三角函数等知识。希望以上步骤能帮助你实现Unity中的UI扇形排列

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值