随着时间的推移旋转游戏对象
我在这里一个新的,我尝试开始使用Unity引擎。
有人可以解释我,Quaternion.Sleep怎么工作? 因为我想旋转90,180和270不同angular度的一些对象。我的代码你可以看到下面。 不幸的是,当我添加180度的时候,物体做出了疯狂的事情,并且把这个游戏对象的旋转angular度设置为(0,180,180)。 我想得到(180,0,0)
public float speed = 0.1F; private float rotation_x; void Update() { if (Input.GetButtonDown("Fire1")) { rotation_x = transform.rotation.eulerAngles.x; rotation_x += 180; } transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotation_x, transform.eulerAngles.y, transform.eulerAngles.z), Time.time * speed); }
包括Unity官网在内的大多数例子都是以错误的方式使用Lerp。 他们甚至懒得描述它在API文档中的工作原理。 他们只是把它淀粉在Update()
函数中,并称之为一天。
Mathf.Lerp
, Vector3.Lerp
和Quaternion.Slerp
通过从t位置(最后一个参数)被传入的位置/旋转到另一个位置来工作。这个t值也被称为时间。
t值的最小值为0f ,最大值为1f 。
我将用Mathf.Lerp
来解释这一点,以便于理解。 Lerp
函数对于Mathf.Lerp
, Vector
和Quaternion
。
请记住, Lerp
接受两个值并在它们之间返回值。 如果我们有1和10的值,我们对他们做Lerp:
float x = Mathf.Lerp(1f, 10f, 0f); will return 1. float x = Mathf.Lerp(1f, 10f, 0.5f); will return 5.5 float x = Mathf.Lerp(1f, 10f, 1f); will return 10
正如你所看到的, t(0)
返回传入数字的最小值 , t(1)
返回传入的最大值 , t(0.5)
返回最小值和最大值之间的中点。 当你传递任何< 0
或> 1
t值时,你做错了。 Update()
函数中的代码就是这样做的。 Time.time
将会Time.time
增加,并且会在一秒钟以上,所以你有这个问题。
它build议在另一个函数/协程中使用Lerp
,而不是更新函数。
注意 :
当谈到轮换时,使用Lerp
有一个坏的一面。 Lerp
不知道如何用最短的path旋转Object。 所以记住这一点。 例如,你有一个0,0,90
的对象。 比方说,你想要把它的旋转移动到0,0,120
Lerp
有时可以左转而不是右转到新的位置,这意味着需要更长的时间才能达到这个距离。
比方说,我们想要从当前的旋转(0,0,90)
进行旋转(0,0,90)
。 下面的代码将在3秒内将旋转更改为0,0,90
。
旋转时间 :
void Start() { Quaternion rotation2 = Quaternion.Euler(new Vector3(0, 0, 90)); StartCoroutine(rotateObject(objectToRotate, rotation2, 3f)); } bool rotating = false; public GameObject objectToRotate; IEnumerator rotateObject(GameObject gameObjectToMove, Quaternion newRot, float duration) { if (rotating) { yield break; } rotating = true; Quaternion currentRot = gameObjectToMove.transform.rotation; float counter = 0; while (counter < duration) { counter += Time.deltaTime; gameObjectToMove.transform.rotation = Quaternion.Lerp(currentRot, newRot, counter / duration); yield return null; } rotating = false; }
增量式angular度旋转:
只要将对象旋转到z轴的90°,下面的代码就是一个很好的例子。 请理解,将Object移动到新的旋转点并旋转它是有区别的。
void Start() { StartCoroutine(rotateObject(objectToRotate, new Vector3(0, 0, 90), 3f)); } bool rotating = false; public GameObject objectToRotate; IEnumerator rotateObject(GameObject gameObjectToMove, Vector3 eulerAngles, float duration) { if (rotating) { yield break; } rotating = true; Vector3 newRot = gameObjectToMove.transform.eulerAngles + eulerAngles; Vector3 currentRot = gameObjectToMove.transform.eulerAngles; float counter = 0; while (counter < duration) { counter += Time.deltaTime; gameObjectToMove.transform.eulerAngles = Vector3.Lerp(currentRot, newRot, counter / duration); yield return null; } rotating = false; }
我所有的例子都是基于设备的帧率。 您可以使用Time.deltaTime
replaceTime.deltaTime
来实时使用,但需要更多的计算。
在此之前,你不能在这样的欧拉angular上加180,这主要是什么导致你的问题。 你最好直接使用四元数,或者直接使用四元数。
你可以把四元数看作是空间的一个方向。 与之前所说的相反,我build议学习如何使用它们。 不过,我不build议使用欧拉angular度,因为他们是不同的写作惯例,有时会失败。 如果你想了解这方面的细节,你可以看看“万向节锁”。
简单地说,slerp或lerp(分别代表球面线性插值或线性插值)是在方向A和B之间插值(从一个方向到另一个方向,通过将t从0增加到1,在协同程序或其他任何地方) 。两者之间的区别在于,斯勒普给你的A到B的最短path。
最后,当t = 1时,lerp(A,B,t)和slerp(A,B,t)会给你B.
在你的情况下,如果你想立即旋转一个对象的空间到一个特定的方向,我build议你使用Quaternion.AngleAxis这是最正向的方式来math描述一个四元数。
如果你想添加一个旋转angular度,比如说90°对应于你的实际方向(两者之间没有animation),你可以这样做:
transform.rotation * = Quaternion.AngleAxis(axis_of_rotation,angle)或者使用transform.rotate(取决于参数,它可以是右乘或左:局部或世界变换)。
程序员的答案是详细说明如何animation变换。 但是我build议你自己研究一下四元数,因为它可以让你全面理解空间变换。