unity 环形UI菜单实现方法2

在项目中需要一个环形UI并且循环往复的效果,这个方法思路为提前预设好位置,让UI根据坐标预设的移动,然后使用mask遮罩达到循环往复效果的目的。
下图分别分为了三个列表
第一个列表poslist是提前预设的位置
第二个列表为背景暂时不用看
第三个列表btnlist为实际的移动UI
在这里插入图片描述
脚本上首先把路径放入,路径要比实际UI多两个是为了制作进入退出的动画效果,路径可以是空物体,实际作用就是为了定位移动。
第二个列表就为实际的操作UI
中心点设置是根据路径列表长度,如果是2那就是路径列表第[2]个,根据自己的列表调整
剩下两个列表为文字显示使用,方便显示各个btn要显示的名称
在这里插入图片描述
以下就是具体实现代码,代码不复杂理解一下就能愉快的玩耍了

using Cysharp.Threading.Tasks;
using DG.Tweening;
using QFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks.CompilerServices;
using System.Threading;
using TMPro; // 关键命名空间

public class LoopUI : MonoBehaviour
{

    public List<RectTransform> posList = new List<RectTransform>();
    public List<RectTransform> itemlist = new List<RectTransform>();
    bool is_是否处于动画 = true;
    public int index_中心点 = 2;
    public CanvasGroup BG_背景动画;

    public List< TextMeshProUGUI> texts   =new List<TextMeshProUGUI>();

    public List<string> btn_names=new List<string>();

    void Start()
    {
        Ins_初始化item坐标();


    }
    void Ins_初始化item坐标()
    {
        for (int i = 0; i < itemlist.Count; i++)//第一步先吧 需要移动的放到相应的位置
        {
            itemlist[i].anchoredPosition = posList[i + 1].anchoredPosition;
            var aa = itemlist[i];
            itemlist[i].GetComponent<Button>().onClick.AddListener(() => SetPos(aa));
        }

        //实例化第一个和最后一个用于 进行动画过渡 
        //把第一个的实力放在最下面,取名为1因为这是实例化列表中的第一个
        var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);
      //  ins.name = "1";
        //把第二个的示例放在最上面        取名为6因为这是实例化列表中的最后一个
        var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);
      //  ins2.name = "6";
        //位置放过后 路径排序为123456  UI实际排序为234516,因为实际ui就只有2345,1和6都是实例化生成进行动画过渡的,所以5后面跟1进行动画衔接
        itemlist.Insert(0,ins);
        ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));
        itemlist.Add(ins2);
        ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));

        for (int i = 0; i < texts.Count; i++)
        {
            texts[i].text = btn_names[i];
        }
    }

    async UniTask UImove(float chat, bool istrue)
    {
        if (istrue)
        {
            //移动过后删除隐藏起来的并移除
      
            Destroy(itemlist[0].gameObject);
            Destroy(itemlist[itemlist.Count - 1].gameObject);
            itemlist.Remove(itemlist[0]);
            itemlist.Remove(itemlist[itemlist.Count - 1]);


            //生成新的第一与最后一位,进行下一次动画移动
            var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);

            var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);
            //生成的第一个放到倒数第二个 最后一个还是放在最后
            itemlist.Add(ins);
            ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));

            itemlist.Add(ins2);
            ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));

            var s = btn_names[0];
            btn_names.Remove(btn_names[0]);
            btn_names.Add(s);


            for (int i = 0; i < texts.Count; i++)
            {
                texts[i].text = btn_names[i];
            }

            for (int x = 0; x < itemlist.Count; x++)
            {
                itemlist[x].DOAnchorPos(posList[x].anchoredPosition, chat).SetEase(Ease.Linear).ToUniTask().Forget();
            }



            await UniTaskManager.Instance.DelayedOperation(chat, () =>
            { 
             
                is_是否处于动画 = true;
            });
        }
        else
        {
            Destroy(itemlist[0].gameObject);
            Destroy(itemlist[itemlist.Count - 1].gameObject);
            itemlist.Remove(itemlist[0]);
            itemlist.Remove(itemlist[itemlist.Count - 1]);

            //生成新的第一与最后一位,进行下一次动画移动
            var ins = Instantiate(itemlist[0], posList[posList.Count - 1].position, posList[posList.Count - 1].rotation, itemlist[0].parent);

            var ins2 = Instantiate(itemlist[itemlist.Count - 1], posList[0].position, posList[0].rotation, itemlist[itemlist.Count - 1].parent);        
            //生成的第一个放到倒数第二个 最后一个还是放在最后
            itemlist.Insert(0, ins2);
            ins2.GetComponent<Button>().onClick.AddListener(() => SetPos(ins2));
            itemlist.Insert(0, ins);
            ins.GetComponent<Button>().onClick.AddListener(() => SetPos(ins));


            //把按钮名称排序
            var s = btn_names[btn_names.Count - 1];
         
            btn_names.Remove(btn_names[btn_names.Count - 1]);
            btn_names.Insert(0, s);
            for (int i = 0; i < texts.Count; i++)
            {
                texts[i].text = btn_names[i];
            }
            for (int x = 0; x < itemlist.Count; x++)
            {
                itemlist[x].DOAnchorPos(posList[x].anchoredPosition, chat).SetEase(Ease.Linear).ToUniTask().Forget();
            }
            await UniTaskManager.Instance.DelayedOperation(chat, () => { is_是否处于动画 = true;});

        }
    }
    private async void SetPos(RectTransform a)
    {

        if (!is_是否处于动画) return;
        is_是否处于动画 = false;
        //首先获取当前在列表中属于第几位
        var t = itemlist.IndexOf(a);
        //获取距离中心点差多少
        float chat = t - index_中心点;
    

        if (chat > 0)//算算当前要移动几下
        {
            BG_背景动画.DOFade(0, 0.5f).SetEase(Ease.Linear).OnComplete(() => {
             
                BG_背景动画.DOFade(1, 0.5f).SetEase(Ease.Linear); }).ToUniTask().Forget();
            for (int i = 0; i < chat; i++)
            {
                await UImove(1f / chat, true);
            }
        
        }
        else if (chat < 0)
        {
            BG_背景动画.DOFade(0, 0.5f).SetEase(Ease.Linear).OnComplete(() => {
               
                BG_背景动画.DOFade(1, 0.5f).SetEase(Ease.Linear); }).ToUniTask().Forget();
            for (int i = 0; i > chat; i--)
            {

                await UImove(1f / Mathf.Abs(chat), false);
            }
         
        }
        else { is_是否处于动画 = true; }







    }
    // Update is called once per frame
    void Update()
    {

    }
}

### 创建圆环形 UI 元素 为了在 Unity 中创建圆环形 UI 元素,可以从多个角度入手,具体取决于所需的功能和视觉效果。 #### 使用 `Image` 组件与自定义精灵 对于简单的静态圆环形 UI 元素,可以直接利用 Unity 的内置 `Image` 组件并为其指定一个预先制作好的圆环形状的精灵图片。这方法简单快捷,适合不需要动态变化的情况[^2]。 ```csharp // 设置 Image 组件来显示预设的圆环图像 public GameObject ringImage; void Start() { Sprite sprite = Resources.Load<Sprite>("RingSprite"); ringImage.GetComponent<Image>().sprite = sprite; } ``` #### 实现交互式的圆环菜单 如果目标是构建可互动的选择界面,则可以参考关卡按钮的设计思路。通过编程控制一系列按钮围绕中心排列形成环状布局,并处理用户的输入事件以实现选项间的平滑过渡[^1]。 ```csharp using UnityEngine; using UnityEngine.UI; public class CircularMenuController : MonoBehaviour { public Transform centerPoint; // 圆心位置 public float radius = 100f; // 半径大小 private List<Button> buttons = new List<Button>(); void ArrangeButtonsInCircle(){ int count = buttons.Count; for (int i=0;i<count;i++){ Vector3 angleOffset = Quaternion.Euler(0, 0, 360f/count * i) * Vector3.right; buttons[i].transform.localPosition = angleOffset * radius; } } // 注册新的按钮到菜单中 public void AddButton(Button btn){ buttons.Add(btn); ArrangeButtonsInCircle(); } // 移除某个特定索引处的按钮 public void RemoveButtonAt(int index){ if(index >= 0 && index < buttons.Count){ Destroy(buttons[index].gameObject); buttons.RemoveAt(index); ArrangeButtonsInCircle(); } } } ``` #### 利用 Radial Progress Bar 效果 当涉及到需要展示进度或其他数值信息时,采用类似于 `RadialProgressBar` 这样的解决方案会非常合适。这种类型的控件能够提供更加生动且具象化的反馈机制给用户[^3]。 ```csharp using UnityEngine; using UnityEngine.UI; public class CustomRadialProgress : MonoBehaviour { [Range(0, 1)] public float progressValue = 0.5f; private RectTransform rectTransform; void Awake(){ rectTransform = GetComponent<RectTransform>(); } void Update(){ DrawArc(progressValue); } void DrawArc(float value){ // 假定此处存在绘制弧线逻辑... } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值