在空物体上挂载下面脚本 ,其中的对齐方法OnAlign可以看做一个对外开放的接口
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using DG.Tweening;
using UnityEngine.UI;
public class RC2D : MonoBehaviour,IDragHandler,IEndDragHandler
{
//图片预制体
public GameObject m_Prefab;
//图片个数
public int m_Num;
//图片间距
public float m_Spacing;
//半径
float m_R;
//每个图片之间的弧度
float m_Rad;
//移动弧度
float m_MoveRad=0;
//存储图片游戏对象
List<GameObject> m_List=new List<GameObject>();
//存储图片transform信息
List<Transform> m_Trans=new List<Transform>();
private void Start()
{
m_Rad = 2 * Mathf.PI / m_Num;
m_R = (m_Prefab.GetComponent<RectTransform>().sizeDelta.x+m_Spacing)*m_Num/(2*Mathf.PI);//算出合适的半径
OnMove();//初始化图片游戏对象
}
private void OnMove()
{
for (int i = 0; i < m_Num; i++)
{
float x=Mathf.Sin(i*m_Rad+m_MoveRad)*m_R;
float z=Mathf.Cos(i*m_Rad+m_MoveRad)*m_R;
if (m_List.Count<=i)
{
GameObject go = Instantiate(m_Prefab, transform);
go.GetComponent<Image>().sprite=Resources.Load<Sprite>(i.ToString());
go.name=i.ToString();
m_List.Add(go);
m_Trans.Add(go.transform);
}
m_List[i].transform.localPosition = new Vector3(x, 0, 0);
float scale = (z + m_R) / (2 * m_R) * 0.5f + 0.5f;//根据z值求出缩放比
m_List[i].transform.localScale=Vector3.one*scale;//缩放赋值
}
//根据图片缩放排序更改层级
m_Trans.Sort((a, b) =>
{
return (int)(a.localScale.z*10-b.localScale.z*10);
});
for (int i = 0;i < m_Trans.Count;i++)
{
m_Trans[i].SetSiblingIndex(i);
}
}
/// <summary>
/// 结束拖拽
/// </summary>
/// <param name="eventData"></param>
public void OnEndDrag(PointerEventData eventData)
{
//惯性
DOTween.To((a) =>
{
m_MoveRad += (a/m_R);
OnMove();
}, eventData.delta.x, 0, 2).OnComplete(() =>
{
//惯性结束,对齐
OnAlign(m_List.IndexOf(m_Trans[m_Num - 1].gameObject));
});
}
/// <summary>
/// 对齐
/// </summary>
/// <param name="v"></param>
public void OnAlign(int v)
{
int index = m_List.IndexOf(m_Trans[m_Num - 1].gameObject);
//计算旋转最短路径
int posi = v - index;//2D中不能写成index-v,否则指定查找效果错误
int nega = m_Num - Mathf.Abs(posi);
nega = posi < 0 ? nega : -nega;
int insert = Mathf.Abs(posi) < Mathf.Abs(nega) ? posi : nega;
//忽略最短路径
//int insert = v-index;//2D中不能写成index-v,否则指定查找效果错误
float totalRad = Mathf.Asin(m_Trans[m_Num - 1].localPosition.x / m_R) + insert * m_Rad;
DOTween.To((a) =>
{
m_MoveRad = a;
OnMove();
},m_MoveRad,m_MoveRad-totalRad,1);
}
/// <summary>
/// 拖拽中
/// </summary>
/// <param name="eventData"></param>
public void OnDrag(PointerEventData eventData)
{
//3D轮转图与2D轮转图的区别
//3D时 z越小离摄像机越近 因为相机放在了-10的位置上 所以-=
//2D时 z越大离摄像机越近 所以+=
m_MoveRad += (eventData.delta.x / m_R);
OnMove();
}
}