轮转图也叫做轮播图
在UI上,我们只要掌握好近大远小以及角标层级的分配,就能模拟出3D的轮转效果了。
不管是横向、纵向、斜向都能有不错的表现。
这里以纵向代码举例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class Circle2D : MonoBehaviour,IDragHandler,IEndDragHandler
{
public InputField inputf;
public int num = 14;//Item数量
public float offest = 10;//间距
public Image prefab;//Item预制体
public float max = 1;//Item最大比例
public float min = 0.5f;//Item最小比例
public float dec = 10;//减速度
float c;//周长
float r;//半径
float ang;//每个角弧度
float allang;//移动的总弧度
public List<GameObject> list = new List<GameObject>();
public List<Transform> sort = new List<Transform>();
DT dt;
DT dt0;
void Start()
{
c = num * (prefab.rectTransform.sizeDelta.y+offest);
r = c / (360 * Mathf.Deg2Rad);
ang = 360 * Mathf.Deg2Rad / num;
Move();
}
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<Text>().text = i.ToString();
}
float y = Mathf.Sin(i * ang+allang) * r;
float z = Mathf.Cos(i * ang+allang) * r;
float p = (z + r) / (r + r);
float scale = max * (1 - p) + min * p;
list[i].transform.localPosition = new Vector3(0, y, 0);
list[i].transform.localScale = Vector3.one * scale;
}
//排序设置角标
Sort();
}
public void OnDrag(PointerEventData eventData)
{
if (dt != null)
{
Destroy(dt.gameObject);
}
if (dt0 != null)
{
Destroy(dt0.gameObject);
}
allang-=eventData.delta.y/r;
Move();
}
public void OnEndDrag(PointerEventData eventData)
{
float dis = eventData.delta.y;
float time = Mathf.Abs(dis / dec);
dt=DT.To((a) =>
{
allang -= a / r;
Move();
}, dis, 0, time).OnComlate(() =>
{
float moveang = Mathf.Asin(sort[num - 1].localPosition.y / r);
float movetime = Mathf.Abs(moveang * r / dec);
dt0=DT.To((b) =>
{
allang = b;
Move();
}, allang, allang + moveang, movetime).OnComlate(() =>
{
});
});
}
public void Sort()
{
sort.Sort((a, b) =>
{
if (a.localScale.z < b.localScale.z)
{
return -1;
}
else if (a.localScale.z == b.localScale.z)
{
return 0;
}
else
{
return 1;
}
});
for (int i = 0; i < sort.Count; i++)
{
sort[i].SetSiblingIndex(i);
}
}
public void OnButton()
{
int next = int.Parse(inputf.text);
Sort();
//当前位置
int id = list.IndexOf(sort[^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;
//预计位置
float moveang = Mathf.Asin(sort[num - 1].localPosition.y / r) + n3 * ang;
float movetime = Mathf.Abs(moveang * r / dec);
dt0 = DT.To((b) =>
{
allang = b;
Move();
}, allang, allang + moveang, movetime).OnComlate(() =>
{
});
}
void Update()
{
}
}
这里用了一个简单的脚本代替DoTween:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DT : MonoBehaviour
{
float starttime, nowtime, alltime;
float now;
Action<float> action;
Action comlate;
bool isplay = true;
void Start()
{
}
public static DT To(Action<float>action,float starttime,float nowtime,float alltime)
{
GameObject obj = new GameObject("Dt");
DT self = obj.AddComponent<DT>();
self.starttime = starttime;
self.nowtime = nowtime;
self.alltime = alltime;
self.now = Time.time;
self.action = action;
return self;
}
public DT OnComlate(Action comlate)
{
this.comlate = comlate;
return this.GetComponent<DT>();
}
void Update()
{
if (Time.time - now < alltime)
{
float p = (Time.time - now) / alltime;
float c = (1 - p) * starttime + nowtime * p;
if (action != null)
{
action(c);
}
}
else if(isplay)
{
isplay = false;
if (action != null)
{
action(nowtime);
}
if (comlate != null)
{
comlate();
}
Destroy(gameObject);
}
}
}