Making a Simple Pause System in Unity

Pause Menu

Here’s how to make a quick and dirty pause system in Unity. The overall breakdown involves four general steps:

  1. Make a paused panel pop up on a keypress
  2. Make that same keypress stop the movement of all game objects
  3. Pause all visible coroutines
  4. Pause all particles

Of course, individual results may vary, but this will hopefully get you moving in the right direction. Below are more details on each of these steps.

Make A Paused Panel Pop Up On A Keypress

Start by creating a UI canvas and paused panel that you wish to appear when you press a key. For this purpose, we will use the “P” key. I don’t currently have tutorials on making a pause panel, but there are plenty on the internet. I’ll be using the one below for mine.

An Example Pause Panel.
My Pause Panel Example

Arrange the panel in your scene the way you want it to appear when the player pauses the game. Then, with the paused panel selected, you’ll see a checkbox to the top left of the inspector. Make sure to uncheck that box. That makes sure the panel will be inactive when the scene starts.

Uncheck this box in the inspector.
Make sure the box in the circle in unchecked.

Next, to make the paused panel pop up on a keypress, first open the script you use for your Game Controller and add a “public GameObject pausedPanel;” and a “public int pauseSpeed = 1;” . We will discuss pauseSpeed later.

Back in Unity, select your Game Controller object. The Game Controller script should now have a Pause Panel slot in the inspector, where you will want to drag the scene’s instance of your paused panel. Next, add the below code to your Game Controller script, within the Fixed Update function.

void FixedUpdate()
	{
		//Pause
		if (Input.GetKeyDown (KeyCode.P))
		{
			if (pauseSpeed == 1)
			{
				pauseSpeed = 0;
				pausedPanel.SetActive(true);
			}
		//Play
			else
			{
				pauseSpeed = 1;
				pausedPanel.SetActive(false);
			}
		}
	}

This code basically says “if the user presses “P”, check if pauseSpeed is 1. If it is, set it to 0 and open the pausedPanel. Otherwise, if pauseSpeed, isn’t 1 (which means it should be 0), set it to 1 and close the pausedPanel.

You may wonder why we don’t make pauseSpeed a bool if we are only setting it to 0 or 1. That reason comes next.

Stop the Movement of All Game Objects

There are two ways of doing this one. How you do it decides whether or not you need pauseSpeed to be a public int.

  1. You can make all your mover scripts – any script that determines the speed or rotation of a game object – access the pauseSpeed of the GameController and multiply it by the speed in the script. This option is a little move complicated and requires that pauseSpeed be public.
  2. You can have your mover scripts check for a keypress and then toggle their own version of pauseSpeed, which is then multiplied by the speed in the script. We will use this option.

Either way, both of these routes use pauseSpeed to change the speed or rotation of an object’s movement. For example, say an object using your script moves at a speed of 5. Now multiply that speed by pauseSpeed. If we are paused and pauseSpeed is 0, 5 x 0 = 0. If we are in play and pauseSpeed is 1, 5 x 1 = 5.

So now open your mover scripts and, for each one, add the “private int pauseSpeed = 1;”. Then add the below code in FixedUpdate:

void FixedUpdate()
	{
		//Pause
		if (Input.GetKeyDown (KeyCode.P))
		{
			if (pauseSpeed == 1)
			{
				pauseSpeed = 0;
			}
		//Play
			else
			{
				pauseSpeed = 1;
			}
		}
	}

This is almost the same script as the one you added in the Game Controller script, minus the pausedPanel.

Finally, for each piece of your movement scripts that involve speed, add “*pauseSpeed” next to the speed variable.

For example, “rb.velocity = transform.forward * speed * pauseSpeed;”.

Now, back in the Game Controller script, pauseSpeed doesn’t just decide velocity.

Pause All Visible Coroutines

This is where a lot of individual results may vary. I am open to add some color to any questions in the comments, but the primary coroutines I am talking about on here have to do with loops that spawn enemies and others of the like. Coroutines that visibly change the scene.

You’ll have your own coroutines and loops in your game controller, but the gist of this system is that pauseSpeed can be used to make it look like they are paused. Note: they will still be running in the background, so if you want to do some extra work to actually pause them, feel free.

But, in this case, it’s easiest to show where pauseSpeed fits in the loop prompts. So here that is:

for (int i = 0; i < Random.Range(spawnMin,spawnMax)*pauseSpeed; i++)

Basically, this prompt says that i starts at 0 and, for each time i is less than the variable number, do something. Then it repeats over and over. That being said, when you are paused and pauseSpeed equals 0, that variable number will always be 0. So the loop will never run. That is, at least, until you return to play and pauseSpeed returns to 1.

Pause All Particles

The final step is to pause particle systems; and Unity has built-in functions to do so. It is just a matter of having a script attached to your particle systems that listens for a keypress and then runs Unity’s functions to pause or play the particles. That script is below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleParameters : MonoBehaviour
{
    
	private bool paused = false;

	void FixedUpdate()
	{
		if (Input.GetKeyDown (KeyCode.P))
		{
			if(paused == true)
			{
				GetComponent<ParticleSystem>().Play();
				paused = false;
			}
			else
			{
				GetComponent<ParticleSystem>().Pause();
				paused = true;
			}
		}
	}
}

This script checks for when “P” is pressed. Then, if the paused bool is true, it sets it to false and plays the particle system it is attached to. On the other hand, if the paused bool is false, it sets it to true and pauses the particle system.

Simply create this script and attach it as a component of the object containing the particle system you want to pause.

A Note

The first thing that may pop out to you is that pauseSpeed is used so widely throughout this system that it might be better to make it a static variable. That is next on my list of items to research and I will update this post when I finish that.

Hopefully this gives you some ideas for your own pause system in Unity. Like I said, individual results will vary; but I’m happy to help or discuss where able. Drop a comment!

-LVL12