如何平滑地旋转立方体
How to rotate cube smoothly
每次按 space 键时,我都试图将立方体平滑地旋转到 90 度。在我的代码中,每次我将速度降低到小于 1 时,它的旋转在 90 度降低时不一致,而速度超过 1 时,它的旋转立即不平稳。这是我的代码
Vector3 to = new Vector3(0, 0, 90);
public float speed = 0.5f;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
RotateOne();
}
}
void RotateOne()
{
transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles, to, speed * Time.deltaTime);
to += new Vector3(0, 0, 90);
}
Quaternion to = Quaternion.Euler(0,0,90);
transform.rotation = Quaternion.Lerp(transform.rotation, to, speed * Time.deltaTime);
不要更改 to
并添加 Time.deltaTime
你几乎成功了 ;)
主要问题是当你点击按键时,你只旋转了一点点。
您更希望连续旋转并且只在单击时增加一次目标旋转。
第二个问题是您使用 eulerAngles
进行连续旋转。来自 API:
When using the .eulerAngles property to set a rotation, it is important to understand that although you are providing X, Y, and Z rotation values to describe your rotation, those values are not stored in the rotation. Instead, the X, Y & Z values are converted to the Quaternion's internal format.
When you read the .eulerAngles property, Unity converts the Quaternion's internal representation of the rotation to Euler angles. Because, there is more than one way to represent any given rotation using Euler angles, the values you read back out may be quite different from the values you assigned. This can cause confusion if you are trying to gradually increment the values to produce animation.
To avoid these kinds of problems, the recommended way to work with rotations is to avoid relying on consistent results when reading .eulerAngles particularly when attempting to gradually increment a rotation to produce animation. For better ways to achieve this, see the Quaternion * operator
.
// In general instead of eulerAngles always prefer calculating with
// Quaternion directly where possible
private Quaternion to;
void Start()
{
to = transform.rotation;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
RotateOne();
}
// You want to do this always, not only in the one frame the key goes down
// Rather use RotateTowards for a linear rotation speed (angle in degrees per second!)
transform.rotation = Quaternion.RotateTowards(transform.rotation, to, speed * Time.deltaTime);
// Or if you still rather want to interpolate
//transform.rotation = Quaternion.Lerp(transform.rotation, to, speed * Time.deltaTime);
}
void RotateOne()
{
to *= Quaternion.Euler(0, 0, 90);
}
但请注意这会有一个小问题:当您按下按键 3 或 4 次时,它会突然向后旋转!这是因为 RotateTowards
和 Lerp
都使用了朝向目标旋转的最短路径。
为了在您的情况下完全避免这种情况,您可以使用 Corotuine 并堆叠您的输入,例如
private int pendingRotations;
private bool isRotating;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
pendingRotations++;
if(!isRotating) StartCoroutine(RotateRoutine());
}
}
IEnumerator RotateRoutine()
{
// just in case
if(isRotating) yield break;
isRotating = true;
var targetRotation = transform.rotation * Quaternion.Euler(0, 0, 90);
while (transform.rotation != targetRotation)
{
transform.rotation = Quaternion.RotateTowards(startRotation, targetRotation, speed * Time.deltaTime);
// tells Unity to "pause" the routine here, render this frame
// and continue from here in the next fame
yield return null;
}
// in order to end up with a clean value
transform.rotation = targetRotation;
isRotating = false;
pendingRotations--;
// are there more rotations pending?
if (pendingRotations > 0)
{
// start another routine
StartCoroutine(RotateRoutine());
}
}
每次按 space 键时,我都试图将立方体平滑地旋转到 90 度。在我的代码中,每次我将速度降低到小于 1 时,它的旋转在 90 度降低时不一致,而速度超过 1 时,它的旋转立即不平稳。这是我的代码
Vector3 to = new Vector3(0, 0, 90);
public float speed = 0.5f;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
RotateOne();
}
}
void RotateOne()
{
transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles, to, speed * Time.deltaTime);
to += new Vector3(0, 0, 90);
}
Quaternion to = Quaternion.Euler(0,0,90);
transform.rotation = Quaternion.Lerp(transform.rotation, to, speed * Time.deltaTime);
不要更改 to
并添加 Time.deltaTime
你几乎成功了 ;)
主要问题是当你点击按键时,你只旋转了一点点。
您更希望连续旋转并且只在单击时增加一次目标旋转。
第二个问题是您使用 eulerAngles
进行连续旋转。来自 API:
When using the .eulerAngles property to set a rotation, it is important to understand that although you are providing X, Y, and Z rotation values to describe your rotation, those values are not stored in the rotation. Instead, the X, Y & Z values are converted to the Quaternion's internal format.
When you read the .eulerAngles property, Unity converts the Quaternion's internal representation of the rotation to Euler angles. Because, there is more than one way to represent any given rotation using Euler angles, the values you read back out may be quite different from the values you assigned. This can cause confusion if you are trying to gradually increment the values to produce animation.
To avoid these kinds of problems, the recommended way to work with rotations is to avoid relying on consistent results when reading .eulerAngles particularly when attempting to gradually increment a rotation to produce animation. For better ways to achieve this, see the
Quaternion * operator
.
// In general instead of eulerAngles always prefer calculating with
// Quaternion directly where possible
private Quaternion to;
void Start()
{
to = transform.rotation;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
RotateOne();
}
// You want to do this always, not only in the one frame the key goes down
// Rather use RotateTowards for a linear rotation speed (angle in degrees per second!)
transform.rotation = Quaternion.RotateTowards(transform.rotation, to, speed * Time.deltaTime);
// Or if you still rather want to interpolate
//transform.rotation = Quaternion.Lerp(transform.rotation, to, speed * Time.deltaTime);
}
void RotateOne()
{
to *= Quaternion.Euler(0, 0, 90);
}
但请注意这会有一个小问题:当您按下按键 3 或 4 次时,它会突然向后旋转!这是因为 RotateTowards
和 Lerp
都使用了朝向目标旋转的最短路径。
为了在您的情况下完全避免这种情况,您可以使用 Corotuine 并堆叠您的输入,例如
private int pendingRotations;
private bool isRotating;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
pendingRotations++;
if(!isRotating) StartCoroutine(RotateRoutine());
}
}
IEnumerator RotateRoutine()
{
// just in case
if(isRotating) yield break;
isRotating = true;
var targetRotation = transform.rotation * Quaternion.Euler(0, 0, 90);
while (transform.rotation != targetRotation)
{
transform.rotation = Quaternion.RotateTowards(startRotation, targetRotation, speed * Time.deltaTime);
// tells Unity to "pause" the routine here, render this frame
// and continue from here in the next fame
yield return null;
}
// in order to end up with a clean value
transform.rotation = targetRotation;
isRotating = false;
pendingRotations--;
// are there more rotations pending?
if (pendingRotations > 0)
{
// start another routine
StartCoroutine(RotateRoutine());
}
}