随着时间的推移旋转游戏对象

我在这里一个新的,我尝试开始使用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.LerpVector3.LerpQuaternion.Slerp通过从t位置(最后一个参数)被传入的位置/旋转到另一个位置来工作。这个t值也被称为时间。

t值的最小值为0f ,最大值为1f

我将用Mathf.Lerp来解释这一点,以便于理解。 Lerp函数对于Mathf.LerpVectorQuaternion

请记住, Lerp接受两个值并在它们之间返回值。 如果我们有110的值,我们对他们做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.deltaTimereplaceTime.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议你自己研究一下四元数,因为它可以让你全面理解空间变换。