2023 年更新:由于这个问题多年来受到了很多关注,我将在这里总结学习内容:使用
yield return null
。这达到了问题所寻求的效果,即协程将尽快再次评估。
TL,DR:在协程中使用 Time.deltaTime 作为 Yield 的等待时间是否安全?
为了避免 Update() 中不必要的逻辑来实现短暂的功能,我通常会运行一个协程。例如,在我的游戏中,我有一个缓慢的协程,它会定期检查 NPC 和玩家之间的距离,如果该距离低于某个阈值,我将运行一个更频繁的协程,并使用光线投射等进行更昂贵的视线测试。这似乎比在 Update() 中不断检查所有内容要高效得多。
我的问题是:使用 Time.deltaTime 作为收益的等待时间,从而在协程的持续时间内模拟 Update() 是否安全?即
yield return new WaitForSeconds(Time.deltaTime);
由于 deltaTime 不是恒定的,如果下一帧比上一帧花费的时间更长,会发生什么 - 协程是否会延迟到下一帧,或者是否发生了可怕的事情,例如整个帧被延迟到协程完成为止?为了安全起见,我很想留出一个缓冲区,例如
yield return new WaitForSeconds(Time.deltaTime * 1.2f);
但理想情况下我希望它精确地执行每一帧。
使用 Time.deltaTime 作为收益率的等待时间是否安全 协程?
不。这不是
WaitForSeconds
函数的使用方法。 WaitForSeconds
以秒为单位作为参数,而不是每帧中 Time.deltaTime
提供的微小值。
以下是如何使用
WaitForSeconds
功能的示例。
IEnumerator waitFunction1()
{
Debug.Log("Hello Before Waiting");
yield return new WaitForSeconds(3); //Will wait for 3 seconds then run the code below
Debug.Log("Hello After waiting for 3 seconds");
}
至于用
Time.deltaTime
等待,通常除了另一个 while
变量之外,您通常会在 float
循环中使用它,您将 increment
或 decrement
直到达到想要的值。使用 Time.deltaTime
的优点就是在等待的时候可以看到还剩多少等待时间。您可以将其用于倒计时器或正计时器。您还将 yield return null;
放入 while
循环中,以便 Unity 也允许其他脚本运行,并且您的应用程序不会冻结。下面是如何使用 Time.deltaTime
等待 3 秒的示例。您可以轻松地将其变成倒计时器。
IEnumerator waitFunction2()
{
const float waitTime = 3f;
float counter = 0f;
Debug.Log("Hello Before Waiting");
while (counter < waitTime)
{
Debug.Log("Current WaitTime: " + counter);
counter += Time.deltaTime;
yield return null; //Don't freeze Unity
}
Debug.Log("Hello After waiting for 3 seconds");
}
如果你想检查每一帧,有 WaitForEndOfFrame
如果不需要特定的等待时间,那么 WaitForSeconds 就没有意义
您也可以
yield return www
等待完成
更新,有 CustomYieldInstruction 以及其中一些继承用于协程中,例如 WaitUntil
我知道这有点旧了,但我今天在寻找相关内容时才发现它。
无论如何,程序员的回答是一个好的开始。使用 Time.detlaTime 并不是释放协程控制权的好方法。首先,使用空值将使您进入模拟中的下一帧。其次,如果刚刚完成的帧有点慢(或者下一帧有点快),会发生什么。请记住,模拟(或游戏)在帧中运行,就像电影中的帧一样。因此,使用 WaitForSeconds 可以产生一些有趣的效果。例如,如果您请求的时间发生在帧之间,您认为会发生什么?协程将在之后请求的时间重新获得控制权。因此,如果您希望在协程中的每个循环上执行 WaitForSeconds(Time.deltaTime) ,那么您很可能会跳过偶尔的帧(有时更多)。
我的一位同事在一个长时间运行的协程中执行了一堆 WaitForSeconds,并且总时间比预期长了 5 到 10 秒。那些在请求时间内丢失部分帧的错误将会累加,并且与自然情况不同,错误往往会趋于平均,这些错误总是会累加up。这是因为经过的时间总是大于或等于请求的时间。
程序员的回答告诉你如何使用Time.deltaTime来获取模拟时间的流逝。我应该警告你,一旦你开始使用 null 以外的东西来释放对协程的控制,Time.deltaTime 可能会停止为你工作。
如果您使用 null 后跟一些代码,后跟 WaitForEndFrame,则当协程恢复控制时,您仍将位于同一帧内。因为您仍处于调用 WaitForEndFrame 之前的同一帧中,所以过去的模拟时间将为零,但 Time.deltaTime 不会为零。所以,是的,一旦开始混合不同的返回类型,测量时间就会变得很棘手。您还应该小心框架和固定框架之间的切换。使用 WaitForFixedUpdate 将使您进入固定帧时代。在 WaitForFixedUdpate 之后调用 Time.fixedDeltaTime 将为您提供该固定帧和前一个固定帧之间的时间,这与 Time.deltaTime 或帧的任何计时无关。