首先创建一个背景图和预制体
接下来就是通过挂在BG上的脚本实现轮转图的效果:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using DG.Tweening;
public class Rotationchart2D : MonoBehaviour, IDragHandler, IEndDragHandler
{
public GameObject prefab;
//图片数量
public int num;
//半径
float r;
//差值
float max = 1;
float min = 0.5f;
//间距 (单位是像素)
float padding = 50;
//移动弧度
float moveAngle = 0;
float angle;
//减速度
float cutSpeed = 50;
List<GameObject> list = new List<GameObject>();
List<Transform> trans = new List<Transform>();
// Start is called before the first frame update
void Start()
{
angle = 2 * Mathf.PI / num;
//算出合适的生成半径
r = (prefab.GetComponent<RectTransform>().sizeDelta.x + padding) * num / (2 * Mathf.PI);
OnMove();
}
public void OnMove()
{
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(angle * i + moveAngle) * r;
float z = Mathf.Cos(angle * i + moveAngle) * r;
if (list.Count < num)
{
GameObject go = Instantiate(prefab, transform);
go.name = i.ToString();
list.Add(go);
trans.Add(go.transform);
}
list[i].transform.localPosition = new Vector3(x, 0, 0);
//跟据 z值(距离摄像机前后) / 直径 来求出比例 * 差值 + min 最小值不能小于min限制 求出缩放比
float scale = (z + r) / (2 * r) * (max - min) + min;
list[i].transform.localScale = Vector3.one * scale;
}
//根据图片缩放排序更改层级
trans.Sort((a, b) => { return (int)(a.transform.localScale.z * 100 - b.transform.localScale.z * 100); });
for (int j = 0; j < trans.Count; j++)
{
trans[j].transform.SetSiblingIndex(j);
}
}
public void OnDrag(PointerEventData eventData)
{
float dis = eventData.delta.x;
//需要转动的弧度数
float angle = dis / r;
//3D和2D的区别
//3D时 z越小离摄像机越近 因为相机放在了-10的位置上 所以-=
//2D时 z越大离摄像机越近 所以+=
moveAngle += angle;
OnMove();
}
/// <summary>
/// 惯性向前 并对齐
/// </summary>
/// <param name="eventData"></param>
public void OnEndDrag(PointerEventData eventData)
{
// eventData.delta.x会有负值
// 惯性时间
float moveTime = Mathf.Abs(eventData.delta.x / cutSpeed);
DOTween.To((a) =>
{
//调用drag方法
float angel = a / r;
moveAngle += angel;
OnMove();
}, eventData.delta.x, 0, moveTime).OnComplete(() =>
{
//当前z值最大的 离摄像机最近 自动对齐
Align(list.IndexOf(trans[num - 1].gameObject));
});
}
/// <summary>
/// 对齐方法
/// </summary>
/// <param name="n"></param>
public void Align(int n)
{
int index = list.IndexOf(trans[num - 1].gameObject);
int zheng = n - index;
int fan = num - Mathf.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
int insert = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
float insertAngle = insert * angle;
//得到弧长
float alignAngel = Mathf.Asin(trans[num - 1].localPosition.x / r) + insertAngle;
float moveTime = Mathf.Abs(alignAngel * r / cutSpeed);
DOTween.To((a) =>
{
moveAngle = a;
OnMove();
}, moveAngle, moveAngle - alignAngel, 2);
}
}