轮转图是指在一个模块或者窗口,通过鼠标点击或滑动后,可以看到多张图片或模型之间不断切换,如何实现轮转图:
先计算每个要显示的图片或模型的位置,在对应位置生成物体:
public GameObject obj;
public int num;
public int r;
float ang_all = 0;
List<GameObject> list = new List<GameObject>();
List<Transform> pos = new List<Transform>();
float angle;
float dec = 1;
private void Start()
{
angle = 2 * Mathf.PI / num;
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(i * angle) * r;
float z = Mathf.Cos(i * angle) * r;
GameObject go = Instantiate(obj);
go.transform.parent = transform;
go.transform.localPosition = new Vector3(x, 0, z);
go.GetComponent<RoleItem>().cyclogram = this;
list.Add(go);
pos.Add(go.transform);
}
}
然后给物体挂载一个脚本,用来监听拖拽行为:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoleItem : MonoBehaviour
{
public Cyclogram cyclogram;
private void OnMouseDrag()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 next = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = transform.position.x - next.x;
cyclogram.OnDrag(dis);
}
private void OnMouseUp()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 next = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = transform.position.x - next.x;
cyclogram.Inertia(dis);
}
}
计算鼠标拖拽产生和物体位置的差值发送给轮转图脚本里的OnDrag函数,控制所有物体同步进行旋转:
public void OnDrag(float dis)
{
float ang_move = dis / r;
ang_all += ang_move;
for (int i = 0; i < list.Count; i++)
{
float x = Mathf.Sin(i * angle + ang_all) * r;
float z = Mathf.Cos(i * angle + ang_all) * r;
list[i].transform.localPosition = new Vector3(x, 0, z);
}
}
这样简单的轮转图就做好了,现在的轮转图物体旋转后停止会非常突兀,接下来制作物体旋转时的惯性效果:
public class MyDoTween : MonoBehaviour
{
public Action<float> action;
public Action complete;
public float start;
public float end;
public float time;
float nowTime;
public static MyDoTween To(Action<float> action, float start, float end, float time)
{
GameObject go = new GameObject("DT");
MyDoTween dt = go.AddComponent<MyDoTween>();
dt.action = action;
dt.start = start;
dt.end = end;
dt.time = time;
dt.nowTime = Time.time;
return dt;
}
private void Update()
{
if (Time.time - nowTime < time)
{
float t = Time.time - nowTime;
float p = t / time;
float a = start * (1 - p) + end * p;
action(a);
}
else
{
action(end);
complete?.Invoke();
Destroy(gameObject);
}
}
public void OnComplete(Action complete)
{
this.complete = complete;
}
}
上图仿照DoTween的To方法实现了一个简单的随时间变化返回差值的脚本,使用这个脚本完成物体惯性以及自动对齐的效果:
public void Inertia(float dis)
{
MyDoTween.To((a) =>
{
OnDrag(a);
}, dis, 0, Mathf.Abs(dis / dec)).OnComplete(() =>
{
pos.Sort((a, b) => (int)(a.localPosition.z - b.localPosition.z));
float aligning = Mathf.Asin(pos[0].localPosition.x / r);
float aligningtime = Mathf.Abs(aligning * r / dec);
MyDoTween.To((a) =>
{
ang_all = a;
for (int i = 0; i < list.Count; i++)
{
float x = Mathf.Sin(i * angle + ang_all) * r;
float z = Mathf.Cos(i * angle + ang_all) * r;
list[i].transform.localPosition = new Vector3(x, 0, z);
}
}, ang_all, ang_all + aligning, aligningtime);
});
}
最终实现的效果: