Unity Fixedupdate Wait a Few Seconds and Do Again

Counting.gif

Exercise you need to change a value over a few frames? Practice yous have lawmaking that you'd similar to run over a fix menstruation of fourth dimension? Or perhaps yous take a time-consuming process that if run over several frames would make for a better player experience?

Like almost all things in that location is more than one way to exercise information technology, but one of the best and easiest ways to run code or alter a value over several frames is to use a coroutine!

Just What Is A Coroutine?

Coroutines in many ways tin can exist thought of equally a regular role but with a return type of "IEnumerator." While coroutines can exist chosen merely like a normal function, to become the most out of them, we need to apply "StartCoroutine" to invoke them.

Simply what is really different and new with coroutines (and what besides allows us to leverage the power of coroutines) is that they require at least one "yield" statement in the body of the coroutine. These yield statements are what give us control of timing and let the lawmaking to be run asynchronously.

Information technology'south worth noting that coroutines are unique to Unity and are not available outside of the game engine. The yield keyword, IEnumerable interface, and the IEnumerator type are yet native to C#.

But before we dig in too deep, let's get ane misconception out of the fashion. Coroutines are non multi-threaded! They are asynchronous multi-tasking but not multi-threaded. C#does offer async functions, which can exist multi-threaded, but those are more complex and I'm hopeful it volition be the topic of a future video and weblog post. If async functions aren't plenty you tin become to total-fledged multi-threading, but Unity is non thread-safe and this gets fifty-fifty more complex to implement.

Irresolute a Numeric Value - Update or Coroutine?

Update method… Not so awesome

Update method… Not and so awesome

And then let's start with a simple example of changing a numeric value over time. To arrive easier to run across the results, let's display that value in a UI text chemical element.

We can of class do this with the standard update office and some type of timer, but the implementation isn't especially pretty. I've got iii fields, an if statement, and an update that is going to run every frame that this object is turned on.

While this works, there is a better and cleaner way. Which of class is a coroutine.

Corountines are much Cleaner

Corountines are much Cleaner

So let's look at a coroutine that has the aforementioned result as the update part. We tin can see the return blazon of the coroutine is an IEnumerator. Detect that nosotros can include input parameters and default values for those parameters - but similar a regular function. Then inside the coroutine, we can ascertain the count which volition be displayed in the text. This variable volition live as long as the coroutine is running, so we don't demand a course-broad variable making things a bit cleaner.

And despite personally beingness scared of using while statements this is a practiced utilise of one. Within the while loop, we encounter our first yield statement. Here nosotros are only asking the computer to yield and expect for a given number of seconds. This ways that the computer will render to the code cake that started the coroutine as if the coroutine had been completed and continue running the balance of the program. This is an important item as some users may wait the calling part to likewise interruption or wait.

And then! When wait time is up the thread will return to the coroutine and run until information technology terminates or in this case loops through and encounters another yield statement.

The outcome, I would argue while not shorter is much cleaner than an update role. Plus the coroutine only runs one time per 2d vs. once per frame and as a result, it will be more performant.

In my personal projects, I've replaced update functions with coroutines for functionality that needed to run consistently but not every frame - and it made a dramatic improvement in the performance of the game.

As mentioned earlier, to invoke the coroutine we need to employ the control "StartCoroutine." This function has 2 main overloads. One that takes in a cord and the second which takes in the coroutine itself. The string-based method can not have in input parameters and I generally avert the utilise of strings, if possible, so I'd recommend the strongly typed overload.

Stopping a Coroutine

If you lot accept a coroutine, especially ane that doesn't automatically terminate, you might besides want to stop that coroutine when it's no longer needed or if some other event occurs and y'all want to stop the procedure of the coroutine.

Unlike an update office if the component is turned off the coroutine will not automatically finish. But! If the gameObject with the coroutine is turned off or destroyed the coroutine will finish.

So that'southward one style and can certainly work for some applications. Just what if you want more control?

You can bring down the hammer and use "StopAllCoroutines" which stops all the coroutines associated with the given component.

Stop a particular coroutine by reference

End a particular coroutine by reference

Personally, I've oft found this sufficient, but you tin too finish individual coroutines with the function "StopCoroutine" and give it a reference to the particular coroutine that you want to stop. This is washed by telling it explicitly which coroutine by name OR I recently learned yous can cache a reference to a coroutine and apply that reference in the stop coroutine function. This method is useful if there is more one coroutine running at a fourth dimension - we'll await at an example of that afterward.

ChangingValue+Coroutine.jpg

If you want to ensure that a coroutine stops when a component is disabled, y'all can telephone call either call stop coroutine or stop all coroutines from an "OnDisable" office.

It's also worth noting that you can get more than one case of a coroutine running at a time. This could happen if a coroutine is started in an update office or a while loop. This can cause bug especially if that coroutine, similar the one to a higher place, never terminates and could quickly kill functioning.

A Few Other Examples

GameBoardFillin.gif

Other uses of coroutines could exist unproblematic animations. Such as laying downwardly the tiles of a game board. Using a coroutine may be easier to implement and quicker to adjust than a traditional animation.

The game board effect, shown to the right, actually makes use of two coroutines. The showtime instantiates a tile in a filigree and waits a minor amount of time before instantiating the next tile.

The second coroutine is run from a component on each tile. This component caches the start location then moves the object a ready amount direct upward and so over several frames lerps the object'south position back to the original or intended position. The event is a floating down-similar effect.

Another advantage of using a coroutine over a traditional animation is the reusability of the code. The coroutine tin can easily exist added to whatsoever other game object with the parameters of the effect easily modified by adjusting the values in the inspector.

Instantiate the Board Tiles

Instantiate the Board Tiles

Make those Tiles float down into position

Make those Tiles float down into position

Notice that in the float down code information technology doesn't look for the position to become back to the original location since a lerp will never become to the final value. So if the coroutine ran the while loop until it got to the exact original position the coroutine would never terminate. If the exact position is important the position can exist prepare afterward exiting the while loop.

Moving Game Piece.gif

Caching and Stopping Coroutines

Coroutines can also be used to easily create shine move such as a game piece moving around the lath.

Moving Game Piece Coroutine.png

But at that place is a potential snag with this approach. In my case, I'k using a lerp function to summate where the game piece should motion to for the next frame. The trouble comes when using a lerp part that operates over several frames. This creates the smooth motion - but in that time the histrion could click on a different location, which would beginning another instance of the coroutine, and then both coroutines would be trying to move the game piece to dissimilar locations and neither would ever be successful or e'er stop.

This is a waste product of resources, but worse than that the player will lose control and non exist able to motion the game slice.

A simple style to avert this upshot is to enshroud a reference to the coroutine. This is fabricated piece of cake, as the outset coroutine part returns a reference to the started coroutine!

Then all nosotros need to do, before starting a new coroutine is to check if the coroutine variable is null, if information technology's non we can terminate the previous coroutine before starting the next coroutine.

It's easy to lose control or lose rail of coroutines and caching references is a great mode to maintain that command.

Yield Instructions!

The yield instructions are the cardinal improver to coroutines vs. regular functions and there are several options congenital into Unity. Information technology is possible to create your ain custom yield instructions and Unity provides some documentation on how to do that if your project needs a custom implementation.

Maybe the near common yield instruction is "look for seconds" which pauses the coroutine for a set number of seconds earlier returning to execute the code. If you are concerned most garbage drove and are using "wait for seconds" frequently with the same amount of fourth dimension you lot tin create an example of it in your course. This is useful if you've replaced some of your update functions with coroutines and that coroutine will be called oftentimes while the game is running.

Another common yield argument is to render "null." This causes Unity to wait until the side by side frame to go along the corountine which is particularly useful if you desire an action to take place overall several frames - such as a simple blitheness. I've used this for computationally heavy tasks that could cause a lag spike if done in ane frame. In those cases, I simply converted the function to a coroutine and sprinkled in a few yield return null statements to break it up over several frames.

An equally useful, simply I think often forgotten yield statement is "break" which only ends the execution of a coroutine much similar the "render" command does in a traditional function.

"Look Until" and "Look While" are similar in function in that they will pause the coroutine until a delegate evaluates as truthful or while a consul is true. These could be used to look a specific number of frames, await for the histrion score to equal a given value, or maybe show some dialogue when a player has died three times.

"Wait For End of Frame" is a slap-up way to ensure that the residuum of the game code for that frame has completed as well as subsequently cameras and GUI have rendered. Since it is often difficult, or impossible, to control what code executes before other lawmaking this can be very useful if y'all demand specific code to run later on other code is consummate.

"Wait for Stock-still Update" is pretty self-explanatory and waits for "fixed update" to be called. Unity doesn't specify if this triggers before, afterwards, or somewhere in the in-between when fixed update functions are getting called.

Wait for "Seconds Real-Time" is very similar to "wait for seconds" but as the proper name suggests it is done in existent-fourth dimension and is not affected past the scaling of time whereas "wait for seconds" is affected past scaled fourth dimension.

Other Bits and Details

Many when they go started with Unity and coroutines think that coroutines are multi-threaded but they aren't. Coroutines are a simple fashion to multi-task merely all the work is still done on the main thread. Mult-threading in Unity is possible with async office or manually managing threads simply those are more than circuitous approaches. Multi-tasking with coroutines means the thread can bounce back and forth between tasks before those tasks are complete, but can't truly do more than than one task at one time.

Tasks vs Time.png

The diagram to the correct is stolen from the video Best Practices: Coroutines vs. Async and is is a keen visual of real multi-threading on the left and what multi-tasking with coroutines really does.

While pretty dry, the video does offer some very good information and some more detailed specifics on coroutines.

It's besides worth noting that coroutines do not back up return values. If you lot need to become a value out of the coroutine y'all'll need a course-wide variable or some other data structure to salve and access the value.

etheridgeapprokill.blogspot.com

Source: https://onewheelstudio.com/blog/2021/2/12/unity-coroutines

0 Response to "Unity Fixedupdate Wait a Few Seconds and Do Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel