An Introduction to Coroutines with Unity
I remember it taking a little while for me to start using coroutines in Unity, and awhile longer to understand or at least appreciate how they were different from regular C# methods. The part which stands out to me from a definition of coroutines is that they ‘allow execution to be suspended and resumed’. Essentially, when we call a standard method the program will try to execute every statement within that method before proceeding. To give an example, every statement in the ‘Setup’ method below will be executed before any of the statements in the ‘BeginGame’ method:
By contrast, with coroutines, we’re simply giving the command for the program to start working its way through the code within the methods, not to necessarily finish doing so before continuing. This allows us to do all kinds of handy things in our programming, for instance adding in delays using real time:
In this case, I’m telling the coroutine MyCoroutine to start and passing in a float value as an argument. This value is then getting used to determine the realtime delay between the first Debug.Log and the second. We could also chain these sorts of delays to allow for some sequencing within our games, for instance if we want a delay, then some text to appear, then a delay, then for the text to disappear and the game to start, we can do this all using coroutines and yield statements.
One of the other useful things coroutines allow for is that they allow us to execute blocks of code over and over until a condition is no longer met using while loops:
The logic within that while loop is essentially getting run as though we’d placed it inside the Update method, only coroutines can give us greater control over exactly when these sorts of loops should start and stop (whereas even an empty Update method will still be using up performance even when it’s empty or none of the code is able to run). We could use loops like this to handle transitions, for instance if we say the condition of a while loop is that it’ll run until the alpha value of a color is 0 (and that the while loop gradually reduces the alpha value of a color). Or, potentially, we could use these to handle some of the main logic in our games. For instance, in the 2D space shooter I’ve been working on in the GameDevHQ program:
As long ‘_stopSpawning’ bool isn’t true, the logic within that while loop is running, meaning in this case that new enemies are getting instantiated and parented to a container GameObject (to keep things tidy). We’re also using a yield statement so that there’s a real time delay of 5 seconds between each loop. If we then create a method like ‘StopGame’ within the same script to change that bool from false to true, then we can tell the SpawnManager to stop spawning when, say, the player’s just died. We could create a direct reference to this method and call it from another script, or we could instead use an event system to make this method ‘listen’ for the player’s death (as an ‘Event’). I’ll touch on Event Systems in a separate article as they’ve had a huge impact on the way I code my games.
Lastly, it’s worth noting the different ways of calling a coroutine. Using the above example, we could call it in at least three different ways:
I typically use the first one, admittedly more because the syntax feels a little more comfortable and familiar to me than using quotation marks to call methods (although similar syntax can be found in the ‘Invoke’ method which may occasionally be of use), but from what I understand this method is also faster. The main drawback is that using it in its current form leaves us without a way to stop that instance of the coroutine while we can easily stop the second with ‘StopCoroutine(“SpawnCoroutine”)’. That’s why the third option is probably best practice in most use cases: it works as fast as the first one while giving us a direct reference to the coroutine which we can use to stop it should we need to (‘StopCoroutine(spawnCoroutine)’).
Think that’s all most of what I have to report on the subject. Should have some visuals for some of this logic in action sometime soon! 😊