简体   繁体   中英

Unity3D - Using Time.deltaTime as wait time for a coroutine

TL,DR: is it safe to use Time.deltaTime as the wait time for the yield in a coroutine?

Often to avoid unnecessary logic inside Update() for short lived functionality I'll run a coroutine instead. For example in my game I have a slow coroutine that periodically checks the distance between NPCs and the player, if that distance is under some threshold I'll then run a more frequent coroutine with more expensive line of sight testing using raycasting etc. This seems much more efficient than checking everything constantly in Update().

My question is this: is it safe to use Time.deltaTime as the wait time for the yield, thereby simulating Update() for the duration of the coroutine? ie yield return new WaitForSeconds(Time.deltaTime);

Since deltaTime is not constant what happens if the next frame takes longer than the last - is the coroutine delayed until the next frame, or is something horrible happening like the whole frame being delayed until the coroutine finishes? I'm tempted to allow a buffer for safety eg yield return new WaitForSeconds(Time.deltaTime * 1.2f); but ideally I'd like it to execute precisely every frame.

is it safe to use Time.deltaTime as the wait time for the yield in a coroutine?

No . That's not how to use the WaitForSeconds function. WaitForSeconds takes in seconds as a parameter not the tiny values provided by Time.deltaTime in every frame.

Below is an example of how to use the WaitForSeconds function.

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

As for waiting with Time.deltaTime , you usually use it in a while loop in addition to another float variable you will increment or decrement until you reach the wanted value.The advantage of using Time.deltaTime is that you can see how much waiting time is left while waiting. You can use that for a countdown or up timer. You also put yield return null; in the while loop so that Unity will allow other scripts to run too and your App won't freeze. Below is an example of how to use Time.deltaTime to wait for 3 seconds. You can easily turn it into a countdown timer.

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

If you want to check every frame there areWaitForEndOfFrame

There is no point to WaitForSeconds if you don't need specific time to wait for

You can also yield return www to wait for it finish

Update, there are CustomYieldInstruction and some of it inheritance for used in coroutine, like WaitUntil

I know that this is a bit old, but I just came across it today while looking for something that's related.

Anyways, Programmer's answer is a good start. Using Time.detlaTime is not a good way to release control of a coroutine. For one, using a null value will get you to the next frame in simulation. Second, what happens if the frame you just finished was a bit slow (or the next frame is a bit fast). Please keep in mind that the simulation (or game) runs in frames, much like the frames in a film. Because of this, using WaitForSeconds can have some interesting effects. For instance, if the time you requested happens between frames, what do you think will happen? The coroutine will regain control after the requested time. So, if you were hoping to just shoot off a WaitForSeconds(Time.deltaTime) on each loop in the coroutine, chances are, you are skipping the occasional frame (sometimes more).

I had a coworker that did a bunch of WaitForSeconds, inside a long running coroutine and the total time that passed was anywhere between 5 to 10 seconds longer than what was expected. Those off by part of a frame errors in the requested time will add up, and unlike nature, where errors tend to average out, these errors will always add up . That's because the amount of time that passes will always be greater-than or equal-to the amount of time that's requested.

Programmer's answer showed you how to use Time.deltaTime to get the passage of simulation time. I should warn you that once you start using things other than null to release control of the coroutine, that Time.deltaTime might stop working for you.

If you use a null follow by some code followed by a WaitForEndFrame, you will still be within the same frame when the coroutine resumes control. Because you are still in the same frame as you were before calling WaitForEndFrame, the simulation time that has passed will be zero, but Time.deltaTime will not be zero. So, yeah, measuring time can get tricky once you start mixing different return types. You should also be careful of switching between frames and fixed-frames. Using a WaitForFixedUpdate will put you into the times of the fixed-frames. Calling Time.fixedDeltaTime after a WaitForFixedUdpate will give you the time between that fixed-frame and the previous fixed-frame, which has nothing to do with Time.deltaTime or any of timings for the frames.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM