首先创建一个背景图,比例设置为你游戏界面的比例
接下来创建如下预制体:
上边的text主要是方便我们确认他在轮转图中的位置
接下来手写Dotween,主要作用是实现缓速效果
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DT : MonoBehaviour
{
public Action<float> action;
public float begin;
public float end;
public float time;
public GameObject dt;
float nowtime;
public Action complete;
public static DT To(Action<float> action, float begin, float end, float time)
{
//创建一个名为DT的空物体,将创过来的值接住
GameObject dt = new GameObject("DT");
DT dowteen = dt.AddComponent<DT>();
dowteen.action = action;
dowteen.begin = begin;
dowteen.end = end;
dowteen.time = time;
dowteen.nowtime = Time.time;
dowteen.dt = dt;
return dowteen;
}
// Update is called once per frame
void Update()
{
//在Update每帧调用,用起点和终点的差值确认item的位置
if (Time.time - nowtime < time)
{
//Time.time时从游戏开发到现在的时间,nowTime是游戏开发到调用To方法的时间
//t是调用到To方法到最新的时间
float t = Time.time - nowtime;
//p是t和传过来时间的比,也就是每帧所需花费的时间
float p = t / time;
//a是起点和终点的差值
//start-------*---end
//如果整条虚线是1,平分成10分,那起点就是(1-p)=0.7,终点就是p=0.3,---
float a = begin * (1 - p) + end * p;
action(a);
}
else
{
action(end);
//如果有后续的Complete函数,则继续执行
if (complete != null)
{
complete();
}
Destroy(gameObject);//删除空物体
}
}
public DT OnComplete(Action complete)
{
this.complete = complete;
return this.GetComponent<DT>();
}
}
接下来就是在image上的脚本实现轮转图的效果
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
public class Cyclogram2D : MonoBehaviour, IDragHandler, IEndDragHandler
{
public TMP_InputField field;
public int num = 14;//item个数
public float space = 10;//item之间的间隙
public Image prefab;//预制体
//item的缩放比的最大最小值,为了实现远近效果
public float max = 1;
public float min = 0.5f;
public float dec = 100f;//减速度
float l;//周长
float r;//半径
float ang;//每个角弧度
float allAng = 0;//移动的总弧度
List<GameObject> list = new List<GameObject>();//item集合
List<Transform> sorts = new List<Transform>();//通过缩放的比例确认顺序,主要用于排序
//Dotween实例
DT dt;
DT dt0;
// Start is called before the first frame update
void Start()
{
//周长等于预制体rectTransform的X的值加上两个item之间的间隙
l = num * (prefab.rectTransform.sizeDelta.x+space);
//半径等于周长除以弧度
r = l / (2 * Mathf.PI);
//角度等于弧度除以item的数量
ang = 2 * Mathf.PI / num;
Move();
}
public void Move()
{
for (int i = 0; i < num; i++)
{
//当集合中的个数小于下一个item的下标(也就是表达为第几个)是才创建,所以当超过我们限制的数量时就不会继续创建了
if (list.Count <= i)
{
//在背景板上生成对应的预制体
list.Add(Instantiate(prefab.gameObject, transform));
//在排序的集合中添加对应的预制体transform
sorts.Add(list[i].transform);
//找子对象身上的TextmeshPro,设置为对应的下标
list[i].GetComponentInChildren<TextMeshProUGUI>().text = i.ToString();
}
//计算image的x和z
float x = Mathf.Sin(i * ang + allAng) * r;
float z = Mathf.Cos(i * ang + allAng) * r;
//通过z轴计算差值
float p = (z + r) / (r + r);
//计算每个Item的缩放比
float scale = max * (1 - p) + min * p;
//值改变X轴,通过渲染顺序(在排列中实现渲染顺序的先后)实现轮转和滑动效果
list[i].transform.localPosition = new Vector3(x, 0, 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.x / r;
Move();
}
public void OnEndDrag(PointerEventData eventData)
{
//2D轮转图是通过拖拽时确定鼠标相对起始点滑动的位置来转动的
float dis = eventData.delta.x;
float time = Mathf.Abs(dis / dec);
dt= DT.To((a) =>
{
allAng -= a / r;
Move();
}, dis, 0, time).OnComplete(() =>
{
float moveAng = Mathf.Asin(sorts[num - 1].localPosition.x / r);
float moveTime = Mathf.Abs(moveAng * r / dec);
dt0= DT.To((b) =>
{
allAng = b;
Move();
}, allAng, allAng + moveAng, moveTime).OnComplete(() => { });
});
}
//将item排序的方法
public void Sort()
{
sorts.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 < sorts.Count; i++)
{
sorts[i].SetSiblingIndex(i);
}
}
public void OnBtn()
{
Debug.Log(field.text);
int next=int.Parse(field.text);
Sort();
//首先找到排列数组中的最后一名
int id = list.IndexOf(sorts[num - 1].gameObject);
//取到最后一名到输入下标的差值
int n0 = id - next;
//n1取到距离对应下标所相差的距离(也就是差几个下标)
int n1=num-Mathf.Abs(n0);
//判断n0是正是负确认方向
int n2=n0>0?-n1: n1;
int n3 = Mathf.Abs(n0) < Mathf.Abs(n2) ? n0 : n2;
float moveAng = Mathf.Asin(sorts[num-1].localPosition.x / r)+n3*ang;
float moveTime=Mathf.Abs(moveAng*r/dec);
dt0 = DT.To((b) =>
{
allAng = b;
Move();
}, allAng, allAng + moveAng, moveTime).OnComplete(() =>{ });
}
}