欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity UGUI 按钮呈半圆型滑动的无限列表 可左右镜像排列

程序员文章站 2022-05-18 18:35:51
...

   上一篇是实现了按钮可拖拽并自动吸附在屏幕两侧,接着呈半圆分布。之前是道具按钮比较少的情况,道具按钮一多,屏幕空间又局促的情况下,按钮就要适当隐藏了,所以做成一个可以滑动的列表。滑动的轨迹是一个圆形。这个需求还挺有意思的,记录一下代码:

Unity UGUI 按钮呈半圆型滑动的无限列表 可左右镜像排列                                          Unity UGUI 按钮呈半圆型滑动的无限列表 可左右镜像排列

using DG.Tweening;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
namespace ArrowLegend
{
    /// <summary>
    /// 按钮自动吸附和呈半圆分布
    /// </summary>
    public class AutoAdsorptiontoEdge : MonoBehaviour, IBeginDragHandler, IDragHandler,  IEndDragHandler
    {
        private RectTransform rectTransform;
        
        
        public RectTransform SlidingZone;//旋转滑动区域
        public RectTransform Mask;//遮罩区域
        public RectTransform RightMask;//右遮罩区域
        public RectTransform LeftMask;//左遮罩区域
        //public RectTransform RightSlidingZone;//右滑动区域
        //public RectTransform LeftSlidingZone;//左滑动区域
        private CircleSliding circleSliding;
        private Button[] propButtons;
        private Button CenterBtn;
        private bool isRight;
        private float LeftAdsorptiontoX;//吸附到的位置,根据屏幕判断
        private float RightAdsorptiontoX;
        private float UpAdsorptiontoY;//上下位置判断,防止出现按钮到屏幕外的情况
        private float DownAdsorptionY;
        //private List<Button> currentPropBtnList = new List<Button> ();//当前正在展示的按钮
        private int showNum = 4;//展示个数
        
        void Start()
        {
            rectTransform = GetComponent<RectTransform>();
            circleSliding = SlidingZone.GetComponent<CircleSliding>();
            propButtons = circleSliding.PropBtns;
            CenterBtn = circleSliding.CenterPos.GetComponent<Button>();
        }
        public void OnBeginDrag(PointerEventData data)
        {
            if (!new Rect(0, 0, Screen.width,  Screen.height).Contains(Input.mousePosition)) return;
            for (int i = 0; i < propButtons.Length; i++)
            {
             
                propButtons[i].gameObject.SetActive(false);
            }
            Vector3 leftPos;
            RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, new  Vector2(Screen.width/15f, Screen.height/15f), data.enterEventCamera, out leftPos);
            LeftAdsorptiontoX = leftPos.x;
            DownAdsorptionY = leftPos.y;
           
            Vector3 rightPos;
            RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, new  Vector2(Screen.width/15f*14, Screen.height/15f*14), data.enterEventCamera, out rightPos);
            RightAdsorptiontoX = rightPos.x;
            UpAdsorptiontoY = rightPos.y;
        }
        public void OnDrag(PointerEventData data)
        {
            
            Vector3 pos;
            //限定在屏幕内操作
            if (!new Rect(0, 0, Screen.width,  Screen.height).Contains(Input.mousePosition)) return;
           
            if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform,  data.position, data.enterEventCamera, out pos))
            {
               
                rectTransform.position = pos;
                //for (int i = 0; i < PropButtons.Length; i++)
                //{
                //    PropButtons[i].transform.position = ShopBtn.transform.position;
                //}
            };
          
        }
        public void OnEndDrag(PointerEventData data)
        {
            if (rectTransform.position.y < DownAdsorptionY)
            {
                rectTransform.position = new Vector2(rectTransform.position.x,  DownAdsorptionY);
            }
            else if(rectTransform.position.y > UpAdsorptiontoY)
            {
                rectTransform.position = new Vector2(rectTransform.position.x,  UpAdsorptiontoY);
            }
            //左右镜像
            if (rectTransform.position.x > 0)
            {
                rectTransform.DOMove(new Vector3(RightAdsorptiontoX,  rectTransform.position.y), 0.4f).OnComplete(() =>
               {
                   MoveToRight();
                
               });
            }
            else
            {
                rectTransform.DOMove(new Vector3(LeftAdsorptiontoX,  rectTransform.position.y), 0.4f).OnComplete(() =>
                {
                    MoveToLeft();
                
                });
            }
         
        }
        /// <summary>
        /// 移动到右边
        /// </summary>
        private void MoveToRight()
        {
            //SlidingZone.transform.DOMoveX(1.5f,0);
            //SlidingZone.transform.position = RightSlidingZone.transform.position;
            for (int i = 0; i < propButtons.Length; i++)
            {
                propButtons[i].transform.SetParent(this.transform);
            }
            //Mask.transform.DOMoveX(1.72f, 0).OnComplete(() =>
            Mask.transform.DOMove(RightMask.transform.position,0).OnComplete(()=>
                {
                    for (int i = 0; i < propButtons.Length; i++)
                    {
                        propButtons[i].transform.SetParent(Mask);
                    }
                    circleSliding.IsRight(true);
                });
        }
        /// <summary>
        /// 移动到左边
        /// </summary>
        private void MoveToLeft()
        {
            //SlidingZone.transform.DOMoveX(-1.5f, 0);
            //SlidingZone.transform.position = LeftSlidingZone.transform.position;
            for (int i = 0; i < propButtons.Length; i++)
            {
                propButtons[i].transform.SetParent(this.transform);
            }
            Mask.transform.DOMove(LeftMask.transform.position, 0).OnComplete(() =>
            {
                for (int i = 0; i < propButtons.Length; i++)
                {
                    propButtons[i].transform.SetParent(Mask);
                }
                circleSliding.IsRight(false);
            });
        }
      
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine.EventSystems;


namespace ArrowLegend
{
    /// <summary>
    /// 半圆滑动代码
    /// </summary>
    public class CircleSliding : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
    {


       
        public Transform CenterPos;//中心点位置
        public Button[] PropBtns;//待排列的按钮
        public int SlidingSpeed = 10;//滑动速度
        //public AutoAdsorptiontoEdge autoAdsorptiontoEdge;//自动吸附组件




        private Vector2 previousPos;//先前位置
        private float radius = 0.5f;//半径
        private float currentAngle = 0;//旋转的角度
        public float CurrentAngle
        {
            get { return currentAngle; }
        }
        private int showNum = 4;//展示个数


        private Queue<Button> unShowBtnQueue = new Queue<Button>();//还没展示按钮
        private Stack<Button> leftUpBtnStack = new Stack<Button>();//左上待用按钮栈
        private Stack<Button> leftDownStack = new Stack<Button>();//左下待用按钮栈
       
        public List<Button> currentShowBtnList = new List<Button>();//当前展示的按钮


        private int upIndex = 0;//向上移动了几个
        private int downIndex = 0;//向下移动了几个
        private bool needClear = false;//是否需要清除
        private bool m_IsRight;//是否是右边


        void Start()
        {
            for (int i = 0; i < PropBtns.Length; i++)
            {
                PropBtns[i].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * i);
              
                //只展示前面5个,剩下的放在右下方并隐藏备用
                if (i >= showNum)
                {
                    PropBtns[i].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * showNum);
                    PropBtns[i].gameObject.SetActive(false);
                    unShowBtnQueue.Enqueue(PropBtns[i]);
                }
                else
                {
                    currentShowBtnList.Add(PropBtns[i]);
                }


            }
        }


        void Update()
        {
            //if (Input.GetKeyDown(KeyCode.Space))
            //{
            //    isRight = true;
            //    //int index = currentShowBtnList.Count;
            //    for (int i = 0; i < currentShowBtnList.Count; i++)
            //    {
            //        //index -= 1;
            //        PropBtns[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(-((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
            //    }
            //}
        }


        /// <summary>
        /// 是否吸附在右边
        /// </summary>
        /// <param name="isRight"></param>
        public void IsRight(bool isRight)
        {
            m_IsRight = isRight;
            if (m_IsRight == true)
            {
                for (int i = 0; i < currentShowBtnList.Count; i++)
                {
                    currentShowBtnList[i].gameObject.SetActive(true);
                    currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(-((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
                }
            }
            else
            {
                for (int i = 0; i < currentShowBtnList.Count; i++)
                {
                    currentShowBtnList[i].gameObject.SetActive(true);
                    currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
                }
            }
           
        }


        public void OnBeginDrag(PointerEventData eventData)
        {
            previousPos = eventData.position;
           
        }


        public void OnDrag(PointerEventData eventData)
        {
            if(eventData.position.y== previousPos.y)
            {
                return;
            }
            if (eventData.position.y > previousPos.y)
            {
                BtnMove(true);
            }
            else
            {
                BtnMove(false);
            }
            previousPos = eventData.position;
        }


        public void OnEndDrag(PointerEventData eventData)
        {
            
        }


        /// <summary>
        /// 按钮围绕圆心移动
        /// </summary>
        private void BtnMove(bool isUp)
        {
            //向上移动
            if (isUp)
            {
                currentAngle += SlidingSpeed;
                if (currentAngle >= upIndex * 60)
                {
                    //向上移动判断右下栈中是否有数据
                    if (leftDownStack.Count > 0)
                    {
                        currentShowBtnList.Add(leftDownStack.Pop());
                        needClear = true;
                        upIndex += 1;
                    }
                    //是否还有没有展示过的按钮
                    else if(unShowBtnQueue.Count > 0)
                    {
                        currentShowBtnList.Add(unShowBtnQueue.Dequeue());
                        needClear = true;
                        upIndex += 1;
                    }
                    //向上滑动到底
                    else
                    {
                        for (int i = 0; i < currentShowBtnList.Count; i++)
                        {
                            currentShowBtnList[i].gameObject.SetActive(true);
                            if (m_IsRight)
                            {
                                currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(-((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
                            }
                            else
                            {
                                currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle);
                            }
                            
                        }
                        currentAngle -= SlidingSpeed;
                        return;
                    }
                }
                //移动超过60度达到清理条件,清理第一个按钮
                if (needClear && currentAngle >= 60)
                {
                    needClear = false;
                    currentShowBtnList[0].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * showNum);
                    currentShowBtnList[0].gameObject.SetActive(false);
                    leftUpBtnStack.Push(currentShowBtnList[0]);
                    currentShowBtnList.Remove(currentShowBtnList[0]);
                    currentAngle -= 60;
                    upIndex -= 1;
                }
            }


            else
            {
                currentAngle -= SlidingSpeed;
                if (currentAngle <= downIndex*(-60))
                {
                    if (leftUpBtnStack.Count > 0)
                    {
                        needClear = true;
                        downIndex += 1;
                        Button btn = leftUpBtnStack.Pop();
                        btn.gameObject.SetActive(true);
                        currentShowBtnList = InsertBtnToHead(btn, currentShowBtnList);
                        currentAngle += 60;
                       
                    }
                    else
                    {
                        for (int i = 0; i < currentShowBtnList.Count; i++)
                        {
                            currentShowBtnList[i].gameObject.SetActive(true);
                            if (m_IsRight)
                            {
                                currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(-((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
                            }
                            else
                            {
                                currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle);
                            }
                        }
                        currentAngle += SlidingSpeed;
                        return;
                    }
                  
                }
                if (needClear /*&& currentAngle <0*/)
                {
                    needClear = false;
                    currentShowBtnList[currentShowBtnList.Count-1].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * showNum);
                    currentShowBtnList[currentShowBtnList.Count - 1].gameObject.SetActive(false);
                    leftDownStack.Push(currentShowBtnList[currentShowBtnList.Count - 1]);
                    currentShowBtnList.Remove(currentShowBtnList[currentShowBtnList.Count - 1]);
                    downIndex -= 1;
                }
            }




            for (int i = 0; i < currentShowBtnList.Count; i++)
            {
                currentShowBtnList[i].gameObject.SetActive(true);
                if (m_IsRight)
                {
                    currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle(-((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle));
                }
                else
                {
                    currentShowBtnList[i].transform.position = CenterPos.transform.position + GetPosXYByAngle((180 / (/*PropButtons.Length*/showNum - 1)) * i - currentAngle);
                }
            }




        }


        private List<Button> InsertBtnToHead(Button btn,List<Button> btnList)
        {
            List<Button> tempBtnList = new List<Button>();
            tempBtnList.Add(btn);
            for(int i= 0; i < btnList.Count; i++)
            {
                tempBtnList.Add(btnList[i]);
            }
            return tempBtnList;
        }


        /// <summary>
        /// 根据角度拿到相对于圆心的XY坐标
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public Vector3 GetPosXYByAngle(float angle)
        {
            if (angle > 90)
            {
                angle = 180 - angle;
                Vector3 pos = new Vector3();
                pos.x = Mathf.Sin(angle * Mathf.Deg2Rad) * radius;
                pos.y = -Mathf.Cos(angle * Mathf.Deg2Rad) * radius;
                return pos;
            }
            else
            {
                Vector3 pos = new Vector3();
                pos.x = Mathf.Sin(angle * Mathf.Deg2Rad) * radius;


                pos.y = Mathf.Cos(angle * Mathf.Deg2Rad) * radius;
                return pos;
            }


        }
    }
}

由于项目时间比较紧张,很多东西没有抽象出来,等有时间了会考虑做成一个好用的工具。

相关标签: 项目笔记