轮转图在游戏中有着非常广泛的应用,它可以以一种炫酷的形式将图片,人物等展示出来,可以给人耳目一新的感觉。同时,它也是游戏开发中不可或缺的一个重要项目。
今天,我们大家就一起来学习一下3D轮转图的绘制
轮转图的绘制原理其实是很容易理解的,
我们利用父物体生成子物体,子物体利用x轴上的间距和 最中心靠前的物体显示的最大(也就是缩放最大),两侧物体逐渐变小(缩放逐渐变小)的原理制造视觉差,从而让我们感受到3D效果,之后利用拖拽事件等使其可以拖动旋转
下面是我们的绘制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotationChart : MonoBehaviour
{
public int n;
public float spacing = 1;
float r;
float c;
float ang;
float distance = 0;
List<GameObject> list = new List<GameObject>();
List<Transform> sortList = new List<Transform>();
// Start is called before the first frame update
void Start()
{
c = (1 + spacing) * n;
r = c / (2 * Mathf.PI);
ang = 2 * Mathf.PI / n;
for (int i = 0; i < n; i++)
{
list.Add(Instantiate(Resources.Load<GameObject>("pp"), transform));
float x = Mathf.Sin(i * ang) * r;
float z = Mathf.Cos(i * ang) * r;
list[i].transform.localPosition = new Vector3(x, 0, z);
list[i].AddComponent<PlayerMove>();
sortList.Add(list[i].transform);
}
}
public void Move(float dis)
{
distance -= dis / r;
for (int i = 0; i < list.Count; i++)
{
float x = Mathf.Sin(i * ang + distance) * r;
float z = Mathf.Cos(i * ang + distance) * r;
list[i].transform.localPosition = new Vector3(x, 0, z);
}
}
public void Inertia(float endspeed)
{
float time = Mathf.Abs(endspeed) / 3;
Dotw.To((float a) =>
{
Move(a);
},endspeed,0,time).OnComlate(()=>
{
Align();
});
}
private void Align()
{
sortList.Sort((a, b) =>
{
if (a.localPosition.z<b.localPosition.z)
{
return -1;
}
else if (a.localPosition.z == b.localPosition.z)
{
return 0;
}
else
{
return 1;
}
});
float AlignAng = Mathf.Atan(sortList[0].localPosition.x / sortList[0].localPosition.z);
float AlignDis = AlignAng * r;
float time = Mathf.Abs(AlignDis) / 1;
Dotw.To((float a) =>
{
for (int i = 0; i < list.Count; i++)
{
float x = Mathf.Sin(i * ang + a) * r;
float z = Mathf.Cos(i * ang + a) * r;
list[i].transform.localPosition = new Vector3(x, 0, z);
}
}, distance, distance - AlignAng, time);
}
// Update is called once per frame
void Update()
{
}
}
先上来是一系列的准备工作,通过简单计算获得轮转图的半径,周长,每份的弧度等数据。
然后是我们移动的方法,别的地方会调用这个移动的方法,并传过来一个参数,我们可以根据参数求出个项数据,从而确定我们预制体的新的位置。
移动完成之后我们还有惯性,惯性同样也是其他地方调用,传过来一个参数。我们通过这个参数求出从我们拖动松手到轮转图停止的时间,然后用我们的手写DoTween来实现惯性的平滑移动。
最后是我们的对齐,我们要让里我们最近的一个预制体移动到它应该在的位置,同样也是求出参数,然后同手写DoTween来实现移动。
轮转图有了移动,惯性和对齐基本上就可以满足我们的基本需求了,如果还有其他需求,可以在这个的基础上自己添加。
我们在开发功能的时候如果遇到DoTween,大部分时候是直接使用插件的,如果没有插件的情况下,我们可能需要手写DoTween,我们在这次的轮转图开发中也用到了这个,下面我们一起来看一下手写DoTween。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class Dotw : MonoBehaviour
{
float starttime, nowtime, alltime;
float now;
Action<float> action;
Action comlate;
bool isplay = true;
public static Dotw To(Action<float> action,float starttime,float nowtime,float alltime)
{
GameObject obj = new GameObject("Dt");
Dotw self = obj.AddComponent<Dotw>();
self.starttime = starttime;
self.nowtime = nowtime;
self.alltime = alltime;
self.now = Time.time;
self.action = action;
return self;
}
public void OnComlate(Action comlate)
{
this.comlate = comlate;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
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);
}
}
}
手写DoTween其实就是知道其实起始时间,结束时间,现在时间等各项参数,然后自己模拟出来物体平滑移动的效果。代码也非常的通俗易懂,大家可以参考一下上面的代码。
这些代码都只是实现了基本的功能,还有很大的不足,大家参考一下就好。