Unity3D - 使用 Time.deltaTime 作为协程的等待时间

问题描述 投票:0回答:3

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);
但理想情况下我希望它精确地执行每一帧。

c# unity-game-engine coroutine
3个回答
9
投票

使用 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");
}

1
投票

如果你想检查每一帧,有 WaitForEndOfFrame

如果不需要特定的等待时间,那么 WaitForSeconds 就没有意义

您也可以

yield return www
等待完成

更新,有 CustomYieldInstruction 以及其中一些继承用于协程中,例如 WaitUntil


1
投票

我知道这有点旧了,但我今天在寻找相关内容时才发现它。

无论如何,程序员的回答是一个好的开始。使用 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 或帧的任何计时无关。

© www.soinside.com 2019 - 2024. All rights reserved.