Unity Return and Do for Loop Again
If you're making a game in Unity then, chances are, you're going to need a way to pause it.
This might be to stop the game to display a message, to access inventory or other game settings or to simply offer a traditional pause menu to the player.
Whatever it is, the benefits of being able to freeze gameplay temporarily will be obvious to you.
But, what's the best way to do it?
Luckily, there's a simple option.
So… what's the best method for pausing the game in Unity?
The most convenient method for pausing the game in Unity is by setting the game's time scale to zero (Time.timeScale = 0), which effectively pauses all time based operations including movement, physics and animation. Setting the time scale to one again will return the game to its normal speed.
In most cases just setting the time scale to zero to pause your game will be all you need to do.
However…
While most operations will be paused when using this method, not everything in the game will be affected.
In some cases, this is by design, for example when designing pause menus that still need to move and animate.
Other times, however, it's possible to accidentally exclude in-game objects from being paused properly.
In this post, I'll be exploring what is and is not affected by a time scale pause, how to exclude certain objects from being stopped as well as helping you to avoid some common pitfalls when pausing and unpausing your game.
Let's get started.
What you'll find in this article:
- How to pause the game in Unity (using time scale)
- What does and doesn't get paused
- How to pause everything in the game except for certain objects
- How to use a coroutine when the game is paused
- How to animate menus and objects when the game is paused
- How to prevent control input when the game is paused
- How to pause all audio when the game is paused
- How to pause the game without using time scale
How to pause the game in Unity (using time scale)
To pause a game in Unity, simply set the time scale to zero to pause it and back to one (the default) to unpause it again.
In scripting it looks like this:
void PauseGame () { Time.timeScale = 0; } void ResumeGame () { Time.timeScale = 1; }
How does it work?
Setting the time scale affects the time and delta time measuring variables in the Time class.
Put simply, changing the time scale from its default of one will speed up or slow the game down – for example, you can run the game at half speed with a time scale of 0.5, or twice as fast with a timescale of 2). Setting it to zero, pauses the game entirely.
However, not everything is affected.
Understanding what actually happens when the game is paused using this method will help you to avoid unexpected behaviour later on.
What does and doesn't get paused
Stopping the game using time scale will, effectively, pause every object that is time-based.
This typically accounts for everything that is happening in the game, as movement is usually scaled by delta time, animation, also, is time-based and physics steps will not be called when time scale is zero.
But not everything is stopped, and understanding what's happening behind the scenes can help to make building a pause system a little bit easier.
Update will continue to be called
It may surprise you to know that Update will continue to be called when the game's time scale is at zero.
This means that anything inside of an Update loop, including in coroutines, will continue to run regardless of the time scale, which can potentially cause an issue when detecting input (more on that later).
However, anything that relies on time-based measurement will be stopped, such as animations, time-based delays such as Invoke and Wait for Seconds and all movement, so long as it's being multiplied by Time.deltaTime.
In practice, this means that, in most cases, everything will be stopped when the game is paused and, even though Update is still being called, nothing is actually happening.
FixedUpdate doesn't get called at all
When the time scale is set to zero, Fixed Update will not be called at all.
This is useful as it essentially freezes all physics-based movement automatically whenever the game is paused using the time scale method.
Time will be stopped
When the time scale is set to zero, Time.time, which is the time in seconds since the game started, will be stopped.
In most cases, this is a good thing, as any in-game measurement that relies on the Time.time value will also be paused with it.
But what if you still need to measure time when the game is paused?
Luckily there are a couple of options for doing just that.
Time.realtimeSinceStartup and Time.unscaledTime are not affected by time scale and will continue to measure time even when the game is paused.
Delta time based movement will be stopped
When the time scale is set to zero, all movement will be stopped, but only if that movement is being calculated in units per second (using Time.deltaTime).
What does that mean?
In Unity it's good practice to multiply movement calculations by Time.deltaTime, which is the amount of time since the last frame. Like this:
void Update() { gameObject.transform.Translate(Vector3.down * Time.deltaTime); }
This converts the rate of movement from units per frame to units per second.
It's likely that you're already familiar with this concept, as it's used frequently when performing all kinds of actions over a period of time. The purpose being to maintain consistent, smooth movement, even when the frame rate changes (which it will).
But there's another reason to use Time.deltaTime when moving objects.
When pausing the game using the time scale method, instead of the time since the last frame, Time.deltaTime will be zero.
This means that any movement that is being multiplied by Time.deltaTime, will be multiplied by zero. Which means no movement at all.
Usually, this is the desired behaviour when the game is paused.
If, however, you were to move an object using a fixed multiplier, like this:
void Update() { // Don't do this! gameObject.transform.Translate(Vector3.down * 0.02f); }
In this example, the object would continue to move, even when the game is paused.
But what if you actually do want this behaviour?
For example, what if you want to pause the entire game, except for some objects.
What's the right way to do that?
How to pause everything in the game except for certain objects
When pausing the game, you may want some objects to continue to move without being affected by the change in time scale.
Luckily, it's possible to prevent objects from being paused by using unscaled time in place of regular time variables.
For example, to use unscaled time:
- Instead of Time.deltaTime, use Time.unscaledDeltaTime
- Instead of Time.fixedDeltaTime use Time.fixedUnscaledDeltaTime
- Instead of Time.time, use Time.unscaledTime
Most variables in the Time class include an unscaled option that, when used, will ignore changes to the time scale.
Which is ideal for excluding certain objects from being paused, or from other time scale changes as well.
How to use a coroutine when the game is paused
Most coroutines will be frozen when the game is paused.
The coroutine itself isn't actually suspended.
Instead, the timing elements of the coroutine, such as while loops, Time.deltaTime and WaitForSeconds, cannot complete and are preventing the coroutine from finishing.
But what if you want to use a coroutine when the game is paused?
Just like in the previous example, replacing Time.deltaTime with Time.unscaledDeltaTime will allow the coroutine to run on unscaled time.
There's also a replacement for WaitForSeconds: WaitForSecondsRealtime, which will operate independent of time scale changes, allowing the coroutine to run as normal, even when the game is paused.
When building a pause menu, it's likely that your menu screen, buttons and controls will all use animation.
There's just one problem…
Animation is time-based and when pausing the game using the time scale method, any menu animations will be paused too.
Luckily there's an easy solution, by changing the Update Mode of the Animator component to use Unscaled Time.
The unscaled time update mode ignores time scale changes and is ideal for animating pause menus and other GUIs.
How to prevent control input when the game is paused
While movement will be stopped when the game is paused, Update will continue to be called.
This can cause control input conditions (which are often placed inside the Update loop) to still be checked, even when the game is stopped.
In some cases, this isn't a problem.
Either because the movement can't occur or, in the case of physics-based movement, won't be called at all, as Fixed Update is not called when time scale is at zero.
However…
Allowing gameplay input while the game is paused can cause you problems.
For example, in a top-down 2D game, it might be that player controls may still change the character sprite to face a different direction, even though the character isn't moving.
Actions and other controls may also still fire, but may not work correctly or at all, only to then trigger when the game is unpaused again.
The controls that move the player, may also be required to navigate the pause menu.
In any case, for these reasons and more, it's good practice to prevent gameplay input while the game is paused.
So what's the best way to do it?
The simplest method is to first keep track of whether the game is paused or not with a public static boolean variable, like this:
public class PauseControl : MonoBehaviour { public static bool gameIsPaused; void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { gameIsPaused = !gameIsPaused; PauseGame(); } } void PauseGame () { if(gameIsPaused) { Time.timeScale = 0f; } else { Time.timeScale = 1; } } }
Making the variable static means that it is not specific to a single instance (the value is always the same, even if there are multiple instances) and that any class can access it.
Next, place all of the game's input checks inside if conditions, so that they can only occur if the game is not paused, like this:
public class Jump : MonoBehaviour { void Update() { if (!PauseControl.gameIsPaused) { if (Input.GetKeyDown(KeyCode.Space)) { // Make the player jump! } } else { if (Input.GetKeyDown(KeyCode.Space)) { // Player can't jump! (The game is paused) } } } }
Alternatively, you may want to use a more general condition, similar to the above, but that controls all of the gameplay input, turning it on or off. This would allow you to disable input when the game is paused and also for other purposes as well, such as cutscenes.
Adding this simple condition early on in development will make it easier to prevent unexpected behaviour later.
How to pause all audio in Unity
If you've tried using time scale to pause the game, you may have noticed that audio continues to play even when the game is paused.
The Audio DSP time value, which is the audio system time value used for Play Scheduled, will also continue despite the game being paused.
So how do you stop all of the game's audio when the game is paused?
Helpfully there's a very easy method for doing exactly that.
Pausing the Audio Listener will pause all audio in the game, as well as the audio DSP time value.
Simply set Audio Listener Pause to true when pausing the game, like this:
void PauseGame () { Time.timeScale = 0f; AudioListener.pause = true; } void ResumeGame () { Time.timeScale = 1; AudioListener.pause = false; }
Audio that is paused using this method will resume from where it left off when the Audio Listener is unpaused again. Likewise, any audio that was scheduled to play using Play Scheduled will play at the correct time after gameplay is resumed.
But what about menu sounds and music?
What if you want to stop some sounds, but keep others playing?
Helpfully, you can instruct Audio Sources to ignore the Audio Listener Pause state, like this:
AudioSource.ignoreListenerPause=true;
This will allow special Audio Sources, such as for your menu and UI sounds to continue to play, even though other sounds have been stopped.
How to pause the game without using time scale
Setting time scale to zero is, in most cases, one of the most effective and convenient methods for pausing the game in Unity.
Despite this, I've seen a number of questions from people asking how to pause the game without using the time scale method.
This is, of course, absolutely fine. What works for one project may not be right for another.
There are options available for doing this, with the most straightforward being to simply check the game's pause state before running any gameplay scripts. This is similar to the method of preventing control input mentioned earlier.
However…
When reading more about why some people would prefer not to use the time scale method, I was surprised to learn that most of the reasons why were related to not being able to animate menus, move objects, play audio or run coroutines.
Which, as you now know, are all possible to do when using the time scale method.
If it's simply the case that you weren't aware that the Audio Listener could be paused, or that animation could use unscaled time or that coroutines can actually be used when the game is paused, then the time scale method may still be the best option for you.
So give it a try.
Now I want to hear from you
How are you pausing your game? Are you using the time scale method or something else?
Did it work, and did anything happen that you didn't expect?
And what do you know now about pausing a game in Unity that others could benefit from?
Whatever it is, leave a comment below and let me know.
Image Attribution
- Unity Logo © Unity Technologies
My favourite time-saving Unity assets
Rewired (the best input management system)
Rewired is an input management asset that extends Unity's default input system, the Input Manager, adding much needed improvements and support for modern devices. Put simply, it's much more advanced than the default Input Manager and more reliable than Unity's new Input System. When I tested both systems, I found Rewired to be surprisingly easy to use and fully featured, so I can understand why everyone loves it.
DOTween Pro (should be built into Unity)
An asset so useful, it should already be built into Unity. Except it's not. DOTween Pro is an animation and timing tool that allows you to animate anything in Unity. You can move, fade, scale, rotate without writing Coroutines or Lerp functions.
Easy Save (there's no reason not to use it)
Easy Save makes managing game saves and file serialization extremely easy in Unity. So much so that, for the time it would take to build a save system, vs the cost of buying Easy Save, I don't recommend making your own save system since Easy Save already exists.
Source: https://gamedevbeginner.com/the-right-way-to-pause-the-game-in-unity/
0 Response to "Unity Return and Do for Loop Again"
Post a Comment