Unity UGUI 按钮呈半圆型滑动的无限列表 可左右镜像排列
程序员文章站
2022-05-18 18:35:51
...
上一篇是实现了按钮可拖拽并自动吸附在屏幕两侧,接着呈半圆分布。之前是道具按钮比较少的情况,道具按钮一多,屏幕空间又局促的情况下,按钮就要适当隐藏了,所以做成一个可以滑动的列表。滑动的轨迹是一个圆形。这个需求还挺有意思的,记录一下代码:
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;
}
}
}
}
由于项目时间比较紧张,很多东西没有抽象出来,等有时间了会考虑做成一个好用的工具。
下一篇: 原生PHP利用QQ邮箱发送邮件