unity coroutine 随时间移动是不是consistent/accurate?
Unity coroutine movement over time is not consistent/accurate?
我有一个协同程序,每当玩家到达游戏中的某个点时,它就会向上移动我的相机。我使用了协程,这样相机会随着时间的推移平稳移动。
这是我的代码片段:
private IEnumerator MoveCameraUpCoroutine(Vector3 startPos, Vector3 endPos, float duration)
{
float elapsedTime = 0;
while(elapsedTime < duration)
{
transform.position = Vector3.Lerp(startPos, endPos, (elapsedTime/duration));
elapsedTime += Time.deltaTime;
yield return null;
}
}
public void MoveCameraUp(Vector3 startPos, Vector3 endPos, float duration)
{
StartCoroutine(MoveCameraUpCoroutine(startPos, endPos, duration));
}
在我的控制器脚本中,我只是这样调用协程:
cam.GetComponent<CameraMovement>().MoveCameraUp(cam.transform.position,
new Vector3(cam.transform.position.x, cam.transform.position.y + setupLevel.heightOfBlock, cam.transform.position.z),
0.1f);
这个问题是相机的运动在它应该停止的地方并不总是一致的。我做了一些调试。在第一个 运行 上,镜头移动到 0.7864508 yPos
。第二个运行,镜头移到0.7789915 yPos
。等等,这是不一致的。
但是当我简单地使用 Translate
而不是我的协程时:
cam.transform.Translate(0, setupLevel.heightOfBlock, 0);
我在 0.7876318
处获得了相机 yPos 的一致最终值,这正是我所需要的。但是这段代码不会随着时间的推移平滑地移动相机,这不是我想要的。
有谁知道如何解决这个协程问题?我不知道,但我认为我的协程代码有问题。任何帮助是极大的赞赏。
结果其实和预想的很吻合。您的代码绝对没有问题,而是因为帧速率不同。
您看到细微差异的原因是无法保证两帧渲染所用的时间完全相同。
看看这一行
elapsedTime += Time.deltaTime;
您在这里所做的是为您的运行时间添加不一致的值。 (即 Time.deltaTime 每帧都不同)。
一个部分修复可能是使用 Time.smoothDeltaTime 代替,它是 deltaTime 在几个帧上的平滑值。然而,这并不完美。
第二种方法(本身不完全是一个答案,但我也将其留给其他人)是使用补间引擎,例如 DoTweenor iTween。
这些引擎的方法基本上可以完成您想要做的事情。
float elapsedTime = 0;
float ratio = elapsedTime / duration;
while(ratio < 1f)
{
elapsedTime += Time.deltaTime;
ratio = elapsedTime / duration;
transform.position = Vector3.Lerp(startPos, endPos, ratio);
yield return null;
}
使用此设置,您的循环将 运行 直到 ratio 为 1。当 1 时,返回 endPos 并且循环在下一轮退出。
我认为问题在于您将 elapsedTime 与持续时间进行了比较。所以在最后一个 运行 上,你移动然后你增加然后你比较。结果,最后一次增加没有被考虑,你最终接近尾声但不是尾声。
我有一个协同程序,每当玩家到达游戏中的某个点时,它就会向上移动我的相机。我使用了协程,这样相机会随着时间的推移平稳移动。
这是我的代码片段:
private IEnumerator MoveCameraUpCoroutine(Vector3 startPos, Vector3 endPos, float duration)
{
float elapsedTime = 0;
while(elapsedTime < duration)
{
transform.position = Vector3.Lerp(startPos, endPos, (elapsedTime/duration));
elapsedTime += Time.deltaTime;
yield return null;
}
}
public void MoveCameraUp(Vector3 startPos, Vector3 endPos, float duration)
{
StartCoroutine(MoveCameraUpCoroutine(startPos, endPos, duration));
}
在我的控制器脚本中,我只是这样调用协程:
cam.GetComponent<CameraMovement>().MoveCameraUp(cam.transform.position,
new Vector3(cam.transform.position.x, cam.transform.position.y + setupLevel.heightOfBlock, cam.transform.position.z),
0.1f);
这个问题是相机的运动在它应该停止的地方并不总是一致的。我做了一些调试。在第一个 运行 上,镜头移动到 0.7864508 yPos
。第二个运行,镜头移到0.7789915 yPos
。等等,这是不一致的。
但是当我简单地使用 Translate
而不是我的协程时:
cam.transform.Translate(0, setupLevel.heightOfBlock, 0);
我在 0.7876318
处获得了相机 yPos 的一致最终值,这正是我所需要的。但是这段代码不会随着时间的推移平滑地移动相机,这不是我想要的。
有谁知道如何解决这个协程问题?我不知道,但我认为我的协程代码有问题。任何帮助是极大的赞赏。
结果其实和预想的很吻合。您的代码绝对没有问题,而是因为帧速率不同。
您看到细微差异的原因是无法保证两帧渲染所用的时间完全相同。 看看这一行
elapsedTime += Time.deltaTime;
您在这里所做的是为您的运行时间添加不一致的值。 (即 Time.deltaTime 每帧都不同)。
一个部分修复可能是使用 Time.smoothDeltaTime 代替,它是 deltaTime 在几个帧上的平滑值。然而,这并不完美。
第二种方法(本身不完全是一个答案,但我也将其留给其他人)是使用补间引擎,例如 DoTweenor iTween。 这些引擎的方法基本上可以完成您想要做的事情。
float elapsedTime = 0;
float ratio = elapsedTime / duration;
while(ratio < 1f)
{
elapsedTime += Time.deltaTime;
ratio = elapsedTime / duration;
transform.position = Vector3.Lerp(startPos, endPos, ratio);
yield return null;
}
使用此设置,您的循环将 运行 直到 ratio 为 1。当 1 时,返回 endPos 并且循环在下一轮退出。
我认为问题在于您将 elapsedTime 与持续时间进行了比较。所以在最后一个 运行 上,你移动然后你增加然后你比较。结果,最后一次增加没有被考虑,你最终接近尾声但不是尾声。