之前提及的轮转图是在3D空间内利用z轴作为深度信息实现的,但是在2D空间内只有x,z,缺少了z轴.所以利用z轴进行场景伸缩的部分更改为使用UI上的Scale,更改缩放值实现。与3D相比,2D更多利用了UGUI自带的事件系统,代码也更简洁,3D上也可以使用事件系统实现。
定义部分如下
/*
Button和Inputfield用于实现特别效果
num表示总数量
image为生成的预制体
Max和Min为最大最小缩放值
des则是之后Dottween效果的减速度
*/
public Button enter;
public InputField inputField;
public int num = 14;
public Image prefeb;
public float Max = 1;
public float Min = 0.5f;
public float des = 10; //减速度\
/*
周长
半径
弧度
总移动幅度
*/
float l;
float r;
float ang;
float allang = 0; //总移动幅度
List<GameObject> RoleList = new List<GameObject>();
List<Transform> RoleTran = new List<Transform>();
初始化 确定半径 周长 和弧度 开始实现
l = num * prefeb.rectTransform.sizeDelta.x;
r = l / (2 * Mathf.PI);
ang = 2 * Mathf.PI / num;
Move();
Move函数内存放了初始化预制体和移动的位置,开始是 allang总幅度为0,所以不移动
{
for (int i = 0; i < num; i++)
{
if (RoleList.Count <= i)
{
RoleList.Add(Instantiate(prefeb.gameObject, transform));
RoleTran.Add(RoleList[i].transform);
RoleList[i].GetComponentInChildren<Text>().text = i.ToString();
}
//计算
float x = Mathf.Sin(i * ang + allang) * r * 2;
float z = Mathf.Cos(i * ang + allang) * r * 2;
float p = (z + r) / (r + r);
float scale = Max * (1 - p) + Min * p; //缩放比
RoleList[i].transform.localPosition = new Vector3(x, 0, 0);
RoleList[i].transform.localScale = Vector3.one * scale;
}
//Sort函数负责排序
Sort();
}
Sort排序函数中使用了Dotween,也可以参考之前3D轮转图部分的自制Dotween可互通
{
//由于没有Z轴,所以前后顺序需要依靠缩放值以及渲染排序实现
RoleTran.Sort((a, b) =>
{
//判断 2个图片的z轴哪一个更近
if (a.lossyScale.z < b.lossyScale.z)
{
return -1;
}
else if (a.lossyScale.z > b.lossyScale.z)
{
return 1;
}
else
{
return 0;
}
});
//循环添加进队列,进行渲染排序
for (int i = 0; i < RoleTran.Count; i++)
{
RoleTran[i].SetSiblingIndex(i);
}
}
接下来使用拖拽事件,跳过BeginDrag的逻辑
//拖拽中持续调用移动脚本
public void OnDrag(PointerEventData eventData)
{
allang -= eventData.delta.x / r;
Move();
}
//拖拽结束后确定位置,并判断对其以及缓动效果
public void OnEndDrag(PointerEventData eventData)
{
float dis = eventData.delta.x / r;
float time = Mathf.Abs(dis / des);
DOTween.To((a) =>
{
allang -= a / r;
Move();
}, dis, 0, time).OnComplete(() =>
{
float moveang = Mathf.Asin(RoleTran[num - 1].localPosition.x / r);
float moveTime = Mathf.Abs(dis / des);
DOTween.To((b) =>
{
allang = b;
Move();
}, allang, allang + moveang, moveTime).OnComplete(() =>
{ });
});
DOTween.To((a) =>
{
allang -= a / r;
Move();
}, dis, 0, time);
}
这是额外的Button和Inputfield使用,在Input里输入点击Button使用,跳转到对应图片,也可以单独设置Button进行固定位置的跳转
n0到n4
的引用是用于判断最短路径,从而避免绕转一圈的效果
enter.onClick.AddListener(() =>
{
print(inputField.text);
//前往位置
int next = int.Parse(inputField.text);
Sort();
//当前位置
int id = RoleList.IndexOf(RoleTran[num - 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;
//(id - next)
float moveang = Mathf.Asin(RoleTran[num - 1].localPosition.x / r) + n3 * ang;
float moveTime = Mathf.Abs(moveang / des);
dt0 = DT.To((b) =>
{
allang = b;
Move();
}, allang, allang + moveang, moveTime).OnComplete(() =>
{
});
});