2D轮转图和3D轮转图类似,但是用大小来表示前后位置关系,用SetSiblingIndex方法决定遮盖效果
1.在画布下创建空物体,输入框和按钮,给 空物体 挂上脚本
2.脚本继承 MonoBehaviour, IDragHandler, IEndDragHandler
public TMP_InputField input; //输入框
public Button btn; //按钮
public int num = 14; //物体数量
public float space = 0; //物体间距
public Image prefab; //预制体
float l;//周长
float r;//半径
float angle; //每个角的弧度
float allangle = 0; //移动的弧度
float max = 1; //最大值
float min = 0.5f; //最小值
public float dec = 10; //减速度
DT dt;
DT dt0;
public List<GameObject> list = new List<GameObject>(); //存放游戏对象
public List<Transform> sort = new List<Transform>(); //存放游戏对象的transform,排序用
输入框和按钮是从外部拖拽的
3.Start里确认 周长,半径和角度的弧度,调用移动函数
void Start()
{
btn.onClick.AddListener(OnBtn);
l = num * (prefab.rectTransform.sizeDelta.x + 10);
r = l / (2 * Mathf.PI);
angle = 2 * Mathf.PI / num;
Move();
}
4.移动函数,生成预制体并设置位置和大小,调用排序函数
public void Move()
{
for (int i = 0; i < num; i++)
{
if (list.Count <= i)
{
list.Add(Instantiate(prefab.gameObject, transform));
sort.Add(list[i].transform);
list[i].transform.GetComponentInChildren<TextMeshProUGUI>().text = i.ToString();
}
float x = Mathf.Sin(i * angle + allangle) * r;
float z = Mathf.Cos(i * angle + allangle) * r;
float p = (z + r) / (r + r);
float scale = max * (1 - p) + min * p;
list[i].transform.localPosition = new Vector3(x, 0, 0);
list[i].transform.localScale = Vector3.one * scale;
}
Sort();
}
5.排序方法
public void Sort()
{
sort.Sort((a, b) => { return (int)(a.localScale.z * 10 - b.localScale.z * 10); });
for (int i = 0; i < sort.Count; i++)
{
sort[i].SetSiblingIndex(i);
}
}
6.实现拖拽中的事件:
public void OnDrag(PointerEventData eventData)
{
if (dt != null)
{
Destroy(dt.gameObject);
}
if (dt0 != null)
{
Destroy(dt0.gameObject);
}
allangle -= eventData.delta.x / r;
Move();
}
7.实现拖拽结束的事件
public void OnEndDrag(PointerEventData eventData)
{
float dis = eventData.delta.x;
float time = Mathf.Abs(dis / dec);
dt = DT.To((a) =>
{
allangle -= a / r;
Move();
}, dis, 0, 2).OnComplete(() =>
{
float moveang = Mathf.Asin(sort[num - 1].localPosition.x / r);
float movetime = Mathf.Abs(moveang * r / dec);
dt0 = DT.To((b) =>
{
allangle = b;
Move();
}, allangle, allangle + moveang, 1).OnComplete(() =>
{
});
});
}
8.点击按钮的 回调
public void OnBtn()
{
//要去的位置
int next = int.Parse(input.text);
Sort();
//当前位置(距离最近的图片)
int id = list.IndexOf(sort[sort.Count - 1].gameObject);
//默认的长度和方向
int n0 = id - next;
//反方向的长度
int n1=num-Mathf.Abs(n0);
//反方向的方向
int n2 =n0>0?-n1:n1;
//取长度较小的方向
int n3=Mathf.Abs(n0)<Mathf.Abs(n2)?n0:n2;
print("n0:" + n0 + " n1:" + n1 + " n2:" + n2 + " n3:" + n3);
float moveang = Mathf.Asin(sort[num - 1].localPosition.x / r)+n3*angle;
float movetime = Mathf.Abs(moveang * r / dec);
dt0 = DT.To((b) =>
{
allangle = b;
Move();
}, allangle, allangle + moveang, 1).OnComplete(() =>
{
});
}
DT用来代替DOTween
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DT : MonoBehaviour //DoTween
{
public Action<float> action;
public Action complete;
public float begin, end, time;
float nowtime;
public static DT To(Action<float> action, float begin, float end, float time)
{
GameObject dt = new GameObject("DT");
DT tween = dt.AddComponent<DT>();
tween.action = action;
tween.begin = begin;
tween.end = end;
tween.time = time;
tween.nowtime = Time.time;
return tween;
}
// Update is called once per frame
void Update()
{
if(Time.time - nowtime<time)
{
float t = Time.time - nowtime;
float p = t / time;
float a = begin *(1- p) + end * p;
action(a);
}
else
{
action(end);
if (complete != null) complete();
Destroy(gameObject);
}
}
public DT OnComplete(Action act )
{
this.complete=act;
return this;
}
}