原理:
将3D轮转图的z轴转化成 2D轮转图的大小和层级关系 来实现轮转图的效果 。
工具:
DOTween
using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class LZT2D : MonoBehaviour, IDragHandler, IEndDragHandler
{
//需要实例化的预制体
public GameObject prefab;
//角度
float angle;
//数量
public int num;
//旋转需要改变的角度
public float allang;
//半径
float r;
//惯性速度
float speed = 100;
//线性插值的最大值
float max = 1f;
//线性插值的最小值
float min = 0.5f;
List<GameObject> lists = new List<GameObject>();
List<GameObject> trans = new List<GameObject>();
public List<Sprite> sprites = new List<Sprite>();
// Start is called before the first frame update
void Start()
{
//图片之间的间距
//C=2*Π*r
//计算半径:宽*数量/360+100(计算每一个图片占圆的大小 +100的间隔)
r = prefab.GetComponent<RectTransform>().sizeDelta.x * num / (2 * Mathf.PI) + 100;
//计算角度
angle = 2 * Mathf.PI / num;
OnMove();
}
private void OnMove()
{
for (int i = 0; i < num; i++)
{
if (lists.Count < num)
{
GameObject go = Instantiate(prefab, transform);
go.name = i.ToString();
go.GetComponent<Image>().sprite = sprites[i];
lists.Add(go);
trans.Add(go);
}
//计算x的位置(sin(角度)=对边/斜边)
float x = Mathf.Sin(i * angle + allang) * r;
//计算y的位置(con(角度)=临边/斜边)
float z = Mathf.Cos(i * angle + allang) * r;
lists[i].transform.localPosition = new Vector3(x, 0, 0);
//计算大小 实现近大远小
float scale = (z + r) / (2 * r) * (max - min) + min;
lists[i].transform.localScale = Vector3.one * scale;
}
//根据大小 排序
trans.Sort((a, b) =>
{
if (a.transform.localScale.z > b.transform.localScale.z)
{
return 1;
}
else if (a.transform.localScale.z < b.transform.localScale.z)
{
return -1;
}
else
{
return 0;
}
});
//根据排序设置层级
for (int i = 0; i < trans.Count; i++)
{
trans[i].transform.SetSiblingIndex(i);
}
}
public void OnDrag(PointerEventData eventData)
{
//eventData.delta.x 上一帧到这一帧的x轴距离
//弧度/半径=角度
allang += eventData.delta.x / r;
OnMove();
}
public void OnEndDrag(PointerEventData eventData)
{
//时间=距离/速度
float time = Mathf.Abs(eventData.delta.x / speed);
DOTween.To((a) =>
{
allang += a / r;
OnMove();
}, eventData.delta.x, 0, time).OnComplete(() =>
{
Allign(lists.IndexOf(trans[num - 1]));
});
}
public void Allign(int n)
{
int temp = lists.IndexOf(trans[num - 1]);
int zheng = temp - n;
int fan = num - Math.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
//正反转
int interval = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
float interAng = interval * angle;
float moveAng = Mathf.Asin(trans[num - 1].transform.localPosition.x / r) + interAng;
float time = Mathf.Abs(interAng * r / speed);
DOTween.To((b) =>
{
allang = b;
OnMove();
}, allang, allang - moveAng, time).OnComplete(() =>
{
Debug.Log(n);
});
}
}