*dring* ⏰ Taming time (Unity/C#)

Do you know those advanced tricks for manipulating time in Unity?

This article is also available on Medium.

Photo by Aron Visuals on Unsplash

Overview

In this post, we are going to see:

  • ⏸ how to easily pause/unpause the game in Unity
  • 😴 how to do a slow-down effect
  • ⏱ how to create a timer (both one-time and repeating)

⏸ Pause/Unpause a game

There are plenty of games that need to be paused sometimes. For example, if you are fighting an AI or you play a solo puzzle game and you escape to go to the options menu, it would probably be better to pause everything in the background, right?

In Unity, this is devilishly easily to do. All we have to add to our code is:

This global Time.timeScale is the variable that controls the flow of time everywhere in the game — so by turning it to zero, we effectively suspend all activity.

To restore the normal state, we just need to set it back to one:

😴 Do a slow-down effect

We can use a similar Time.timeScale-based trick to quickly make a slow-down effect and emphasise some heroic moment, or give more feedback to the player about some specific event.

Say that, here, I can get frozen by my enemy, which applies some frost effect to the edges of the screen blueish and shortly causes a slow-down:

To do this, we simply have to change the value of the Time.timeScale variable to something between 0 and 1. Simple enough, right?

Well, the real trick is to figure out how to transition out of this “slow-downed state”. If you look carefully at the video above, you’ll notice that I don’t just click in and out of the slow-down, like I did with the pause/unpause before. I have sort of a ramp-up as things return to normal.

This is possible thanks to a coroutine. In a nutshell, coroutines are the tool Unity provides us with for executing functions that need to wait for some amount of time, or continuously run some logic during a period of time. Now, why can’t we use normal C# functions to do that? Because making our function wait would stop the entire game!

Coroutines let us run the logic parallel to the main code and therefore avoid this global freeze: the function lives its own life, and once started from the main routine, it won’t bother it anymore.

To write a coroutine, all we have to do is set our function to return an IEnumerator, and use some yield instruction(s) inside it. Then, if we are inside a MonoBehaviour class, we can call it using the StartCoroutine() built-in function:

This sample code will start a coroutine when the game is run that prints a “Hello!” message, then waits for two seconds and prints another “World :)” message.

In our case, we can use a similar trick to make our slow-down fade out gradually, except that we need to account for the fact that we have modified the Time.timeScale. This, in turn, means that the related variables like Time.deltaTime are skewed. To solve this issue, we need to use Time.unscaledDeltaTime:

Note: the unscaled equivalent of WaitForSeconds() is WaitForSecondsRealtime(). Also, you can insure that your animators keep moving even if the time is scaled to 0 by using the “Unscaled Time” option for the Update Mode property.

Whenever you use coroutines, you have to be careful not to spawn too many at once, or it will cause some performance issues. In particular, make sure that you don’t accidentally restart another “instance” of your coroutine without stopping the first, if you want to restart it. For all that early abort, StopCoroutine() is your friend! 🙂

⏱ Making a timer

One last time-related feature that can be interesting for many games is the creation of a timer. This can either be a “silent” countdown that a script of yours does in the background, in order to know when to trigger some specific action, or a visual text in the UI that updates to tell the player an event is about to happen.

Let’s keep our little mage battle game example and say that each mage has a limited time to do their actions. These rounds automatically end after the delay has passed, or they can be ended manually by clicking the “End Round” in the bottom-right corner.

To help the players know how much time they have left, we could add a little timer next to the button that shows the remaining time in the round, like this:

Here’s a sample of the C# code to create this timer:

That’s also a good opportunity to showcase the StopCoroutine() we talked about earlier, since if I end the round early by clicking the button manually, I want to cancel this timer. (Or else, as soon as I’ve clicked the button and one second elapsed, it will keep counting down!)

To use StopCoroutine(), you have to store a reference to your coroutine when you start it, in a Coroutine variable, and then use StopCoroutine() to stop its execution where needed. I usually like to check if the variable is not null, so that I’m sure it does correspond to a running coroutine:

And here you are! This basic code can easily be adapted to various situations, and it should get you started whenever you want to have some countdown in your game’s UI 🙂

Conclusion

In this article, I covered a few handy tricks for playing around with time in your Unity games. We learned how to pause/unpause a game, how to slow it down, or how to display a little timer in the UI.

What do you think: are there other nice tips for time-related features I forgot? Did I miss your favourite? 😄

Feel free to tell me in the comments, or on my Twitter!

Leave a Reply

Your email address will not be published.