The simplest approach to pausing your game in Unity is to set Time.timeScale = 0
. While the time scale is 0, Update
methods in your scripts will still called, but Time.deltaTime
will always return 0. This works well if you want to pause all on-screen action, but it is severely limiting if you need animated menus or overlays, since Time.timeScale = 0
also pauses animations and particle systems.
We first encountered this limitation when we were trying to implement a world map in Lovers. When the player enters the ship’s map station, we display a overlay of the current level. Since the map obstructs the ship and, as such, inhibits gameplay, we needed to pause the game while the display is visible. However, a completely static map screen would make it difficult to convey information (and also look pretty dull). In order to achieve our goal we needed a separate way to track how much time has elapsed since the last update loop.
It turns out that Time.realtimeSinceStartup
is the ideal mechanism for this. As its name implies, Time.realtimeSinceStartup
uses the system clock to track how much time has elapsed since the game was started, independent of any time scale manipulation you may be doing. By tracking the previous update’s Time.realtimeSinceStartup
, we can calculate a good approximation of the delta time since the last frame:
This script on its own is not enough, however, especially since we want to use Unity’s Animation
component to drive our dynamic map elements. To allow this, we created a subclass of TimeScaleIndependentUpdate
that manually “pumps” the animation:
By using AnimationState
‘s normalizedTime
property and our calculated delta time, we scrub through the animation in each Update
. Now all we need to do is attach this script to the GameObject we want to animate while Time.timeScale = 0
:
As you can see above, the game action is paused when the map appears, but the icons on the map are still animating.
Particle systems can also animate while the game is paused. ParticleSystem
contains a handy Simulate
method which, similar to Animation
, allows us to manually pump the particle animation. All that’s needed is a simple subclass of TimeScaleIndependentUpdate
:
We can combine these three scripts to create fairly complex sequences. In Lovers, once the player has collected enough friends to unlock a warp tunnel, we play a little cutscene while Time.timeScale = 0
:
This sequence relies heavily on the TimeScaleIndependentWaitForSeconds
method of TimeScaleIndependentUpdate
, which approximates Unity’s built-in WaitForSeconds
method and is extremely useful for creating coroutines.