Unity 3D 在一段时间内平滑地旋转对象
Unity 3D Rotate object smoothly during time
我正在编写一个游戏,其中立方体必须在节拍器每次节拍时顺畅地围绕自身旋转 90 度。
每次节拍器跳动时,我的方法都会调用协程:
IEnumerator moveCoroutine()
{
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 90 / 10);
yield return null;
}
}
}
立方体旋转得相当平滑,但旋转在节拍器的下一个滴答声之前很长时间就完成了,我希望它从头到尾平滑地旋转。
我想我必须使用两个节拍器滴答声之间的时间(即变量 'Metronome.manager.delay'),但我不知道如何使用。
感谢您的帮助
您可以在 Mathf 中使用 SmoothStep 函数:http://docs.unity3d.com/ScriptReference/Mathf.SmoothStep.html
最小值是立方体的当前角度,最大值是当前角度+90,t类似于(currentTime - previousTick) / (nextTick - previousTick)
(根据你的数据结构修改)
所以您的 unity c# 脚本通常会 运行 在每一帧渲染。为了使动画流畅,您需要根据文档将变化的 field/variable 乘以 Time.DeltaTime
:
http://docs.unity3d.com/ScriptReference/Time-deltaTime.html
Time.DeltaTime
由unity游戏引擎计算,是从最后一帧渲染开始的经过时间。
文档中的示例:
public class ExampleClass : MonoBehaviour {
void Update() {
float translation = Time.deltaTime * 10;
transform.Translate(0, 0, translation);
}
}
在示例中,变换在 z 轴上平移 10 个单位,由于 Time.deltaTime
[校正因子],动画正确。
If you add or subtract to a value every frame chances are you should
multiply with Time.deltaTime. When you multiply with Time.deltaTime
you essentially express: I want to move this object 10 meters per
second instead of 10 meters per frame.
另一个使用协程的例子:
using UnityEngine;
using System.Collections;
public class CoroutinesExample : MonoBehaviour
{
public float smoothing = 1f;
public Transform target;
void Start ()
{
StartCoroutine(MyCoroutine(target));
}
IEnumerator MyCoroutine (Transform target)
{
while(Vector3.Distance(transform.position, target.position) > 0.05f)
{
transform.position = Vector3.Lerp(transform.position, target.position, smoothing * Time.deltaTime);
yield return null;
}
print("Reached the target.");
yield return new WaitForSeconds(3f);
print("MyCoroutine is now finished.");
}
}
你想要的大概是这样的:
IEnumerator moveCoroutine()
{
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 9.0f * Time.deltaTime);
yield return null;
}
}
}
这修复了动画的流畅度,使其独立于每台计算机的渲染帧 (FPS) 能力。 -> 问题只有在您自己的设备以外的其他设备上进行游戏测试时才会注意到。
现在解决动画长度问题:
IEnumerator moveCoroutine()
{
int maxIterations = 10;
if (!isCollided && canRotate) {
for (float i = 0; i < maxIterations; i++) {
transform.RotateAround(pivot, direction, 9.0f * Time.deltaTime);
yield return new WaitForSeconds(Metronome.manager.delay / maxIterations);
}
}
}
WaitForSeconds(Metronome.manager.delay / maxIterations);
将确保您的动画按您希望的时间播放。 (请注意,如果 Metronome.manager.delay
尚未转换为秒,则需要将其转换为秒。
这是一个协程,你只需要为waitforseconds指定一个值。监控游戏并设置任何你想要的值。
IEnumerator moveCoroutine()
{
float time=0.5f;
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 9);
yield return new WaitForSeconds(time);
}
}
}
其他答案可能有效..但我使用此设置在 Unity 中实现流畅的协程,不依赖于帧速率,而是实际时间
(移动的必要更改应该是微不足道的):
public IEnumerator RotateCoroutine(Vector3 rotationEulerAngles, float rotationDuration)
{
/* Set the current goal Rotation to animate between them */
Quaternion currentRotation = transform.localRotation;
Quaternion goalRotation = currentRotation * Quaternion.Euler(rotationEulerAngles);
/* Set control variables */
float timePassed = 0.0f;
float fracTime = 0.0f;
/* Begin the animation, end after rotationDuration seconds */
while (fracTime < 1)
{
/* Set Rotation between current and goal depending on fracTime */
transform.transform.localRotation = Quaternion.Lerp(currentRotation, goalRotation, fracTime);
/* Update timePassed and fracTime */
timePassed += Time.deltaTime;
/* On this way fracTime will always be a value between
* 0 - start of animation and
* 1 - end of animation after rotationDuration seconds */
fracTime = timePassed / rotationDuration;
/* yield return so the actual state gets printed */
yield return null;
}
/* Just to be sure after the animation set yourGameObject
* to exactly the tranformation value(s) you want */
transform.localRotation = goalRotation;
}
有了这个,您可以更轻松地控制动画需要多长时间,并为旋转设置准确的值,确保旋转时不会出现任何异常。
你可以调用这个 Coroutine 而不是例如
StartCoroutine(RotateCoroutine(new Vector3(0,90,0), 2.0f));
用于在 2 秒内将对象沿 其局部 Y 轴
旋转约 90°
我正在编写一个游戏,其中立方体必须在节拍器每次节拍时顺畅地围绕自身旋转 90 度。
每次节拍器跳动时,我的方法都会调用协程:
IEnumerator moveCoroutine()
{
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 90 / 10);
yield return null;
}
}
}
立方体旋转得相当平滑,但旋转在节拍器的下一个滴答声之前很长时间就完成了,我希望它从头到尾平滑地旋转。
我想我必须使用两个节拍器滴答声之间的时间(即变量 'Metronome.manager.delay'),但我不知道如何使用。
感谢您的帮助
您可以在 Mathf 中使用 SmoothStep 函数:http://docs.unity3d.com/ScriptReference/Mathf.SmoothStep.html
最小值是立方体的当前角度,最大值是当前角度+90,t类似于(currentTime - previousTick) / (nextTick - previousTick)
(根据你的数据结构修改)
所以您的 unity c# 脚本通常会 运行 在每一帧渲染。为了使动画流畅,您需要根据文档将变化的 field/variable 乘以 Time.DeltaTime
:
http://docs.unity3d.com/ScriptReference/Time-deltaTime.html
Time.DeltaTime
由unity游戏引擎计算,是从最后一帧渲染开始的经过时间。
文档中的示例:
public class ExampleClass : MonoBehaviour {
void Update() {
float translation = Time.deltaTime * 10;
transform.Translate(0, 0, translation);
}
}
在示例中,变换在 z 轴上平移 10 个单位,由于 Time.deltaTime
[校正因子],动画正确。
If you add or subtract to a value every frame chances are you should multiply with Time.deltaTime. When you multiply with Time.deltaTime you essentially express: I want to move this object 10 meters per second instead of 10 meters per frame.
另一个使用协程的例子:
using UnityEngine;
using System.Collections;
public class CoroutinesExample : MonoBehaviour
{
public float smoothing = 1f;
public Transform target;
void Start ()
{
StartCoroutine(MyCoroutine(target));
}
IEnumerator MyCoroutine (Transform target)
{
while(Vector3.Distance(transform.position, target.position) > 0.05f)
{
transform.position = Vector3.Lerp(transform.position, target.position, smoothing * Time.deltaTime);
yield return null;
}
print("Reached the target.");
yield return new WaitForSeconds(3f);
print("MyCoroutine is now finished.");
}
}
你想要的大概是这样的:
IEnumerator moveCoroutine()
{
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 9.0f * Time.deltaTime);
yield return null;
}
}
}
这修复了动画的流畅度,使其独立于每台计算机的渲染帧 (FPS) 能力。 -> 问题只有在您自己的设备以外的其他设备上进行游戏测试时才会注意到。
现在解决动画长度问题:
IEnumerator moveCoroutine()
{
int maxIterations = 10;
if (!isCollided && canRotate) {
for (float i = 0; i < maxIterations; i++) {
transform.RotateAround(pivot, direction, 9.0f * Time.deltaTime);
yield return new WaitForSeconds(Metronome.manager.delay / maxIterations);
}
}
}
WaitForSeconds(Metronome.manager.delay / maxIterations);
将确保您的动画按您希望的时间播放。 (请注意,如果 Metronome.manager.delay
尚未转换为秒,则需要将其转换为秒。
这是一个协程,你只需要为waitforseconds指定一个值。监控游戏并设置任何你想要的值。
IEnumerator moveCoroutine()
{
float time=0.5f;
if (!isCollided && canRotate) {
for (float i = 0; i < 10; i++) {
transform.RotateAround(pivot, direction, 9);
yield return new WaitForSeconds(time);
}
}
}
其他答案可能有效..但我使用此设置在 Unity 中实现流畅的协程,不依赖于帧速率,而是实际时间 (移动的必要更改应该是微不足道的):
public IEnumerator RotateCoroutine(Vector3 rotationEulerAngles, float rotationDuration)
{
/* Set the current goal Rotation to animate between them */
Quaternion currentRotation = transform.localRotation;
Quaternion goalRotation = currentRotation * Quaternion.Euler(rotationEulerAngles);
/* Set control variables */
float timePassed = 0.0f;
float fracTime = 0.0f;
/* Begin the animation, end after rotationDuration seconds */
while (fracTime < 1)
{
/* Set Rotation between current and goal depending on fracTime */
transform.transform.localRotation = Quaternion.Lerp(currentRotation, goalRotation, fracTime);
/* Update timePassed and fracTime */
timePassed += Time.deltaTime;
/* On this way fracTime will always be a value between
* 0 - start of animation and
* 1 - end of animation after rotationDuration seconds */
fracTime = timePassed / rotationDuration;
/* yield return so the actual state gets printed */
yield return null;
}
/* Just to be sure after the animation set yourGameObject
* to exactly the tranformation value(s) you want */
transform.localRotation = goalRotation;
}
有了这个,您可以更轻松地控制动画需要多长时间,并为旋转设置准确的值,确保旋转时不会出现任何异常。
你可以调用这个 Coroutine 而不是例如
StartCoroutine(RotateCoroutine(new Vector3(0,90,0), 2.0f));
用于在 2 秒内将对象沿 其局部 Y 轴
旋转约 90°