Programming
Article

Adding Pause, Main Menu and Game over Screens in Unity

By Vincent Quarles

What are the buttons, text, dropdowns, etc. that can be seen when playing a game? All of that is part of what is called the User Interface (UI). Most games have some sort of UI which makes it easier for players to switch between levels and activate certain controls (such as pausing the game or restarting a level). In a previous article describing how to create Dodger in Unity, we created a small button to refresh the game if a player lost.

In this tutorial, we are going to take that to the next level, and allow users to pause or restart the game and switch between different scenes. We will also be taking a look at how to show certain UI elements only at certain times – such as when the game is paused or when the player dies/loses.

User Interface Elements

Most games contain a pause menu, a game over screen, and a main menu. Since these are some of the few elements that are required for a “finished” game, we will insert all three into our Dodger clone. In addition, we will also create an instructions screen so that players will be able to learn the controls they can use before they start playing the game.

The completed game can be played at itch.io.

Creating a Basic Pause Screen

A pause screen has a common set of controls that players are able to use to restart a level, move back to the main menu, or un-pause the game. Pause screens should only be visible when the game is paused. In Unity we are, in general, able to differentiate between a paused and un-paused game by using Time.timescale. If the time scale is zero, the game is paused. If it’s greater than zero, the game is un-paused (we’ll discuss this later). Let’s get started!

Creating Pause Text

First, we are going to need to create a title which tells the player that the game is paused. We should create a text object by right-clicking in the hierarchy pane and selecting UI -> Text. Let’s name the newly created object PauseText.

We need to create a title which tells the player that the game is paused. We should create a text object by right-clicking in the hierarchy pane and selecting UI -> Text. Let’s name the newly created object PauseText.

Now we can format the Text object to have it look better within the game screen. In order to change the text of a Text object we have to click in the Inspector pane under the text attribute where the words “New Text” are. Inside the text attribute, we can change the text of our pause text to “Paused”. To keep with the color scheme for the game we should change the color of the text to white. This can be accomplished by clicking under the color object (where black or another color may be selected) and choosing white.

PauseText

Let’s adjust the placement of our text. The pause text should be centered horizontally on the screen and be at about the top third of the game screen. The pause text can be moved by changing the values of X and Y inside of the Rect Transform attribute or by using the four way arrows in the mouse controls in the top left corner of the Unity editor. If needed or wanted, we can also change the text size by changing the value and by changing the size of the width and height attributes (under Rect Transform).

All we need to do now is tag the object so that the program, after we add code, will be able to tell that we only want this object to show when the game is paused. We can click under the name of the pause text where it says “Untagged” and then click “Add tag…”. Now we can create a tag named “ShowOnPause”. Once this tag is created we need to add it to the pause text.

Creating the Paused Buttons

Since we have created the pause text and added a new tag for game objects that should appear when the game is paused, we can begin creating the buttons that will make up the paused game menu.

We will be creating three different buttons: a play button, a restart button, and a main menu button. The play button will un-pause the game, the restart button will restart the game, and the main menu button will take players back to the main menu scene of the game.

Let’s begin by creating a new button (right-click in hierarchy -> UI -> Button) and naming it “PlayButton”. We should set the play button’s tag to ShowOnPause so that it will only be shown when the game is paused. Now let’s set the text of the play button to “Play”. This can be done by opening the text child object in the inspector (click the dropdown next to the play button in the hierarchy and select the text object) and then changing the text property to “Play”. We should align the play button with the center of the screen so that it will be under the pause text.

A quick way to create the other two buttons is to select the play button in the hierarchy and duplicating it (Command / CTRL + D) twice. We can name the new buttons “RestartButton” and “MainMenuButton”. We should also give each of the new buttons the appropriate text. The restart button should say “Restart” and the main menu button should say “Main Menu”. Now let’s delete the refresh button that was created in the last tutorial. We can see now that we have a basic pause menu. However, the menu doesn’t do anything because we haven’t attached any code to the objects.

PauseButtons

Let’s open the UIManager script that was created in the last tutorial. We should edit our UIManager script so that it looks like the code below.

GameObject[] pauseObjects;

	// Use this for initialization
	void Start () {
		Time.timeScale = 1;
		pauseObjects = GameObject.FindGameObjectsWithTag("ShowOnPause");
		hidePaused();
	}

	// Update is called once per frame
	void Update () {

		//uses the p button to pause and unpause the game
		if(Input.GetKeyDown(KeyCode.P))
		{
			if(Time.timeScale == 1)
			{
				Time.timeScale = 0;
				showPaused();
			} else if (Time.timeScale == 0){
				Debug.Log ("high");
				Time.timeScale = 1;
				hidePaused();
			}
		}
	}


	//Reloads the Level
	public void Reload(){
		Application.LoadLevel(Application.loadedLevel);
	}

	//controls the pausing of the scene
	public void pauseControl(){
			if(Time.timeScale == 1)
			{
				Time.timeScale = 0;
				showPaused();
			} else if (Time.timeScale == 0){
				Time.timeScale = 1;
				hidePaused();
			}
	}

	//shows objects with ShowOnPause tag
	public void showPaused(){
		foreach(GameObject g in pauseObjects){
			g.SetActive(true);
		}
	}

	//hides objects with ShowOnPause tag
	public void hidePaused(){
		foreach(GameObject g in pauseObjects){
			g.SetActive(false);
		}
	}

	//loads inputted level
	public void LoadLevel(string level){
		Application.LoadLevel(level);
	}

Now that we have the code we need accessible in the UIManager script, we can go back to Unity. Inside Unity, let’s select the play button and attach the pauseControl method to it. To do this we can select the play button and drag the UIManager game object onto the game object space under the OnClick() attribute in the inspector pane. With the UIManager game object added, we can now use the second dropdown to select the pauseControl function (UIManager -> pauseControl).

Using the same steps, we can add the reload() method to the restart button and the loadLevel() method to the main menu button. Since the loadLevel() method takes a string parameter, we should type “MainMenu” into the box under the function dropdown.

Pause Menu

If we hit play now, we will notice that the play and restart buttons work. Also, if we hit P while the game is playing, we are able to pause and un-pause the game. The only problem is that the main menu button doesn’t work. This is because we haven’t added a scene named “MainMenu” to the build settings.

Creating a Main Menu Scene

Creating the Scene

With the pause menu created in the play scene, we can now create a new scene that will function as the main menu of the game. The main menu we will create will be simple and only contain a Play button that will take players to the play scene.

First, we should save the current scene that we are working in so that the work we have done will not get deleted when we open a new one. Let’s create a new scene (Command / CTRL + N or File -> New Scene). Once the scene is open, save it and name it “MainMenu”.

Game Scenes

Note: We are naming it “MainMenu” because that is the string property to which we set the main menu button in the play scene. If we wanted a different name, then we could change the string property of the loadLevel() function attached to the main menu button in the play scene.

Creating the Menu

Now that the scene has been saved we can begin working on it. Let’s start by selecting the main camera game object and changing its background to the same color as in the play scene (R: 0, G: 223, B: 255).

For this scene, we will need to be able to access the loadLevel() method inside the UIManager script. This means we need to create a UIManager game object and attach the UIManager script to it so that we can add the function to our button.

Let’s create an empty game object (right-click in hierarchy -> Create Empty) and name it UIManager. Now we can add the UIManager script to the UIManager game object.

We can begin creating the simple menu that will contain the text that says “Dodger” and a play button. We’ll begin by creating the text (right-click in hierarchy -> UI -> Text) and naming it “TitleText”. We should change the text to say “Dodger” and align it to the center of the screen, a little towards the top. Now let’s set the color of title text to white.

With the text created and edited we can create a new button and name it “PlayButton”. We should change the text of the play button’s child object to “Play”. Finally, let’s add the UIManager game object to the button’s OnClick() attribute and choose the loadLevel() function. The parameter of the loadLevel() function depends on what the name of the play scene from the last tutorial is. We can find the name of the play scene by finding the scene in the Assets pane.

Main Menu

If we run the game and hit the play button, we will notice that the button does not work. The reason is the same as it was when the main menu button didn’t work in our play scene: we haven’t added the MainMenu scene to the build settings. To add our current scene to the build settings, we can open the build settings (File -> Build Settings) and click Add Current.

Finishing the Game

For the game to be considered “finished” it needs to have a game over screen so that players will be able to tell when they have lost. We will also add a score counter to the game, so players will know how high they scored.

Adding a Score

We should save our current scene and open the play scene. With the play scene open, we can create a text object and name it “ScoreText”. The score text object should be aligned to the top of the screen. With the score text object selected we can add a top stretch anchor to it by looking in the Rect transform property and clicking the anchor menu. We should also center the text and make it white.

The condition that we will use to update the score will be blocks going off screen (meaning the blocks the player has already dodged). For this condition to be active we will need to check for the blocks’ collision off screen and increment a variable for the score.

Let’s create an empty game object and name it “BottomBorder”. We add a BoxCollider2D to the bottom border and set the X size to a large number that goes slightly past the camera’s borders. Now we can add a Rigidbody2D to the bottom border object and set the gravity scale attribute to 0 so that the bottom border object doesn’t fall. We can align the bottom border object slightly below the player making sure that it is off screen.

We need to create a new script in order to set a score for the player. Let’s create a new C# script named “PointCounter” inside of our Scripts folder. Once the PointCounter script has been created we can open it in our IDE and type:

public int score;

	// Use this for initialization
	void Start () {
		score = 0;
	}

	// Update is called once per frame
	void Update () {

	}

	//checks for entering a trigger
	void OnTriggerEnter2D(Collider2D other){
		//checks other collider's tag
		if(other.gameObject.tag == "Enemy"){
			score++;								//increments score
			Destroy (other.gameObject);				//destroys other collider's gameobject
		}
	}

The PointCounter script should be added to the bottom border game object so that once a block collides with it, the block will be destroyed and the score updated.

Now, let’s create a script named “PointUpdater” which will update the score text. We can open the PointUpdater script in our IDE and type:

public PointCounter pointCounter;
	// Use this for initialization
	void Start () {
		text = gameObject.GetComponent<Text>();
    text.text = "Score: 0";
	}

	// Update is called once per frame
	void Update () {
		text.text = "Score: " + pointCounter.score.ToString();

	}

We should add the PointUpdater script to the score text game object. The bottom border game object should be added to the point counter value so that the score can be updated.

Creating a Game over Menu

To finish up the game, we need to add a game over menu that will appear when the player has died.

Let’s open the PlayerController script in our IDE and below the last variable declaration add:

public bool alive;
	// Use this for initialization
	void Start () {
		alive = true;
	}

Inside of the EnemyController script let’s add:

void OnTriggerEnter2D(Collider2D other){

  //Checks if other gameobject has a Tag of Player
  if(other.gameObject.tag == "Player"){
    other.gameObject.GetComponent<PlayerController>().alive = false;
    Time.timeScale = 0;
  }
}

To begin fleshing out the menu, we can create a new text game object and name it “GameOverText”. The text should be set to “Game Over” and the text color should be white. We should align the game over text to be slightly above the center of the screen. To make sure that this menu will only appear when the player has died we should create a new tag named “ShowOnFinish” and add it to the game over text.

Now let’s duplicate the restart and main menu buttons. We should rename the buttons to “FinRestartButon” and “FinMainMenuButton” and add the ShowOnFinish tag to both of the buttons.

Finally, let’s open the UIManager script in our IDE and edit it so that it looks like the code below.

GameObject[] pauseObjects;
	GameObject[] finishObjects;
	PlayerController playerController;
	// Use this for initialization
	void Start () {
		Time.timeScale = 1;

		pauseObjects = GameObject.FindGameObjectsWithTag("ShowOnPause");			//gets all objects with tag ShowOnPause
		finishObjects = GameObject.FindGameObjectsWithTag("ShowOnFinish");			//gets all objects with tag ShowOnFinish


		hidePaused();
		hideFinished();

		//Checks to make sure MainLevel is the loaded level
		if(Application.loadedLevelName == "MainLevel")
			playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
	}

	// Update is called once per frame
	void Update () {

		//uses the p button to pause and unpause the game
		if(Input.GetKeyDown(KeyCode.P))
		{
			if(Time.timeScale == 1 && playerController.alive == true)
			{
				Time.timeScale = 0;
				showPaused();
			} else if (Time.timeScale == 0 && playerController.alive == true){
				Time.timeScale = 1;
				hidePaused();
			}
		}

		//shows finish gameobjects if player is dead and timescale = 0
		if (Time.timeScale == 0 && playerController.alive == false){
			showFinished();
		}
	}


	//Reloads the Level
	public void Reload(){
		Application.LoadLevel(Application.loadedLevel);
	}

	//controls the pausing of the scene
	public void pauseControl(){
			if(Time.timeScale == 1)
			{
				Time.timeScale = 0;
				showPaused();
			} else if (Time.timeScale == 0){
				Time.timeScale = 1;
				hidePaused();
			}
	}

	//shows objects with ShowOnPause tag
	public void showPaused(){
		foreach(GameObject g in pauseObjects){
			g.SetActive(true);
		}
	}

	//hides objects with ShowOnPause tag
	public void hidePaused(){
		foreach(GameObject g in pauseObjects){
			g.SetActive(false);
		}
	}

	//shows objects with ShowOnFinish tag
	public void showFinished(){
		foreach(GameObject g in finishObjects){
			g.SetActive(true);
		}
	}

	//hides objects with ShowOnFinish tag
	public void hideFinished(){
		foreach(GameObject g in finishObjects){
			g.SetActive(false);
		}
	}

	//loads inputted level
	public void LoadLevel(string level){
		Application.LoadLevel(level);
	}

Game Over Menu

Conclusion

We have now added a simple UI to our game. Players will now be able to move through the two scenes using the buttons. We have also gained experience in modular Unity development and DRY coding (Don’t-Repeat-Yourself). The way we created the score text is a good example of how Unity code should be divided so that it is recyclable.

Questions? Comments? Please leave them below!

The finished project can be downloaded from GitHub.

No Reader comments

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Front-end, once a week, for free.