MISSION 15: Game Over & Menus

Build scene management, Game Over screens, Main Menus, and restart functionality

Lesson 15 of 22 75 min session 50 XP available Week 10 — Tue
XP EARNED: 0 / 50 XP
1
Scene Management Basics
~12 min
+10 XP

Key Vocabulary

Scene
A self-contained level or screen in Unity — like pages in a book
SceneManager
Unity's built-in class for loading, unloading, and switching between scenes
Build Settings
The list of scenes that will be included in your final game build
Scene Index
Each scene in Build Settings gets a number (0, 1, 2...) — used for loading
DontDestroyOnLoad
Keeps a GameObject alive when switching scenes (used for managers, music)
1.1
Understand game flow. Most games have this structure:
  • Main Menu → Player sees title, clicks "Play"
  • Gameplay → The actual game level(s)
  • Game Over → Player dies, sees score, can restart or go to menu
  • Win Screen → (Optional) Player completes the game
Each of these is a separate Scene in Unity. Today you'll create a Main Menu scene and a Game Over scene, and learn how to switch between them using code.
1.2
Create your scenes. You should already have a gameplay scene (e.g. "Level1"). Now create two new scenes:
  • File → New Scene → choose "Basic 2D" → Ctrl+S → save as "MainMenu"
  • File → New Scene → choose "Basic 2D" → Ctrl+S → save as "GameOver"
Save location: Save both scenes in your Assets/Scenes/ folder (create the folder if you don't have it). Your Project window should now show: MainMenu.unity, Level1.unity, GameOver.unity.
1.3
Add scenes to Build Settings. Go to File → Build Settings (or Ctrl+Shift+B). You'll see a panel with "Scenes In Build" at the top. Drag your scenes from the Project window into this list in this order:
  • 0: MainMenu (this loads first when the game starts)
  • 1: Level1 (your gameplay scene)
  • 2: GameOver
Important: The order matters! Scene index 0 is the first scene loaded when your game runs. If your scenes are in the wrong order, drag them to rearrange. The number on the right is the scene index you'll use in code.
1.4
Learn the SceneManager API. To switch scenes in code, you need to add this at the top of your script:
using UnityEngine.SceneManagement;
Then use one of these methods:
// Load by scene NAME (recommended): SceneManager.LoadScene("MainMenu"); SceneManager.LoadScene("Level1"); SceneManager.LoadScene("GameOver"); // Load by scene INDEX: SceneManager.LoadScene(0); // MainMenu SceneManager.LoadScene(1); // Level1 SceneManager.LoadScene(2); // GameOver
Name vs Index: Using names is more readable but must match exactly (case-sensitive!). Using index numbers is shorter but breaks if you reorder scenes. Choose whichever you prefer.
Checkpoint: You have 3 scenes (MainMenu, Level1, GameOver) and they're all added to Build Settings in the correct order. You know how to use SceneManager.LoadScene().
2
Game Over Screen
~15 min
+10 XP
2.1
Trigger Game Over from gameplay. Open your gameplay scene (Level1). In your PlayerController (or GameManager), add the game over logic. When lives reach 0:
using UnityEngine.SceneManagement; // In your damage/death logic: public void TakeDamage() { lives--; if (lives <= 0) { GameOver(); } } void GameOver() { // Save the score so GameOver screen can display it PlayerPrefs.SetInt("FinalScore", score); PlayerPrefs.Save(); // Load the Game Over scene SceneManager.LoadScene("GameOver"); }
PlayerPrefs is Unity's simple data storage. It saves key-value pairs that persist between scenes (and even between game sessions). Think of it like a tiny database. We save the score here so the Game Over screen can read it.
2.2
Open your GameOver scene. Double-click "GameOver" in your Project/Scenes folder. It should be an empty scene with just a camera.
2.3
Set the camera background. Select Main Camera → Inspector → Background colour → choose a dark red or dark colour that says "game over".
2.4
Build the Game Over UI. Right-click in Hierarchy → UI → Canvas. Then add:
  • Right-click Canvas → UI → Text - TextMeshPro → name it "GameOverText". Text: "GAME OVER". Font size: 72. Colour: Red. Anchor: top-centre. Position Y: 100.
  • Right-click Canvas → UI → Text - TextMeshPro → name it "ScoreText". Text: "Score: 0". Font size: 36. Colour: White. Position Y: 0.
  • Right-click Canvas → UI → Button - TextMeshPro → name it "RestartButton". Change button text to "PLAY AGAIN". Position Y: -100.
  • Right-click Canvas → UI → Button - TextMeshPro → name it "MenuButton". Change button text to "MAIN MENU". Position Y: -200.
2.5
Create the GameOverManager script. Right-click Scripts folder → Create → C# Script → name "GameOverManager". Replace ALL code:
using UnityEngine; using UnityEngine.SceneManagement; using TMPro; public class GameOverManager : MonoBehaviour { public TextMeshProUGUI scoreText; void Start() { // Read the saved score int finalScore = PlayerPrefs.GetInt("FinalScore", 0); scoreText.text = "Score: " + finalScore; } public void RestartGame() { SceneManager.LoadScene("Level1"); } public void GoToMenu() { SceneManager.LoadScene("MainMenu"); } }
2.6
Wire up the script.
  • Create an empty GameObject → name it "GameOverManager"
  • Add the GameOverManager script to it
  • Drag the ScoreText TMP object into the Score Text field
2.7
Connect buttons to methods. This is the key step! Select the RestartButton. In the Inspector, find the On Click () event section:
  • Click + to add an event
  • Drag the GameOverManager GameObject into the object field
  • Click the dropdown → GameOverManager → RestartGame
Repeat for MenuButton → connect to GoToMenu.
How Button events work: When the player clicks the button, Unity calls the method you assigned. The dropdown shows ALL public methods on the connected object's scripts. This is Unity's event system — no code needed to detect the click!
2.8
Test it. Go back to your Level1 scene (double-click Level1 in Project). Press Play. Let your player die (run into enemies until lives = 0). The Game Over scene should load, show your score, and the buttons should work.
Buttons not working? Check: (1) The scene is in Build Settings, (2) Button On Click event is connected, (3) Scene name matches exactly (case-sensitive), (4) You have an EventSystem in the scene (auto-created with Canvas, but check it's there).
Checkpoint: When lives reach 0, the Game Over scene loads. It shows the final score and has working Restart and Menu buttons.
3
Main Menu Screen
~15 min
+10 XP
3.1
Open the MainMenu scene. Double-click "MainMenu" in your Project/Scenes folder.
3.2
Set a nice background. You have several options:
  • Option A: Set Camera background colour to a gradient-like dark colour
  • Option B: Create a UI → Image that fills the screen (set anchors to stretch-stretch) and assign a background sprite
  • Option C: Place a sprite in the scene as a background decoration
3.3
Build the Main Menu UI. Right-click Hierarchy → UI → Canvas. Add these elements:
  • Title Text (TMP): Your game's name! Font size: 80. Colour: your accent colour. Anchor: top-centre. Position Y: 150.
  • Subtitle Text (TMP): A tagline (e.g., "A 2D Adventure"). Font size: 24. Colour: light grey.
  • Play Button (TMP): Text "PLAY". Position Y: -50. Make it big and inviting!
  • Quit Button (TMP): Text "QUIT". Position Y: -150. Smaller and less prominent.
3.4
Style the buttons. Select a button. In the Image component, change the Color to match your game's theme. You can also:
  • Change the button's child TMP text colour, size, and font
  • In the Button component, customise Highlighted Color (hover) and Pressed Color (click)
  • Add a subtle Navigation → None if keyboard/gamepad nav isn't needed
3.5
Create the MainMenuManager script. New C# Script → "MainMenuManager":
using UnityEngine; using UnityEngine.SceneManagement; public class MainMenuManager : MonoBehaviour { public void PlayGame() { SceneManager.LoadScene("Level1"); } public void QuitGame() { // Only works in a built game, not in the Editor Application.Quit(); // This line helps test in the Editor: #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif } }
Application.Quit() only works in a built game — not in the Editor's Play mode. The #if UNITY_EDITOR block is a preprocessor directive that only runs in the Editor, letting you test the quit button during development.
3.6
Wire up buttons. Same process as Game Over:
  • Create empty GameObject → add MainMenuManager script
  • Play Button → On Click → drag MainMenuManager → select PlayGame
  • Quit Button → On Click → drag MainMenuManager → select QuitGame
3.7
Test the full game loop. Make sure MainMenu is Scene 0 in Build Settings. Press Play from the MainMenu scene. Click "PLAY" → gameplay starts. Die → Game Over screen. Click "PLAY AGAIN" → gameplay restarts. Click "MAIN MENU" → back to menu. The whole loop should work!
💡
Pro tip: Add a button click sound! In the Button's On Click event, add a second entry: drag SoundManager → select PlayButton. Now buttons make a satisfying click sound (if your SoundManager uses DontDestroyOnLoad from last lesson).
Checkpoint: Main Menu has a title, Play button, and Quit button. The full game loop works: Menu → Play → Game Over → Restart/Menu.
4
Polish — Pause Menu & Transitions
~20 min
+10 XP
4.1
Create an in-game Pause Menu. Go to your Level1 scene. On the existing Canvas, create a Panel (right-click Canvas → UI → Panel). Name it "PausePanel".
  • Set the Panel's Image colour to semi-transparent black: RGBA(0, 0, 0, 200)
  • Add a TMP text child: "PAUSED", font size 60, centre
  • Add a "Resume" Button (TMP) inside the Panel
  • Add a "Main Menu" Button (TMP) inside the Panel
4.2
Create a PauseManager script. New C# script → "PauseManager":
using UnityEngine; using UnityEngine.SceneManagement; public class PauseManager : MonoBehaviour { public GameObject pausePanel; private bool isPaused = false; void Start() { pausePanel.SetActive(false); // hidden at start } void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { if (isPaused) ResumeGame(); else PauseGame(); } } public void PauseGame() { pausePanel.SetActive(true); Time.timeScale = 0f; // FREEZE the game! isPaused = true; } public void ResumeGame() { pausePanel.SetActive(false); Time.timeScale = 1f; // UN-FREEZE isPaused = false; } public void GoToMenu() { Time.timeScale = 1f; // Reset before leaving! SceneManager.LoadScene("MainMenu"); } }
4.3
Understand Time.timeScale. This is powerful!
  • Time.timeScale = 0f → FREEZES everything that uses Time.deltaTime (physics, animations, movement). The game pauses!
  • Time.timeScale = 1f → Normal speed
  • Time.timeScale = 0.5f → Slow motion (half speed)
  • Time.timeScale = 2f → Double speed
Warning: UI buttons and Input.GetKeyDown still work when timeScale = 0, because they don't depend on deltaTime. That's why the Escape key and Resume button work even while paused!
4.4
Wire up the Pause Menu.
  • Create an empty GameObject → add PauseManager script
  • Drag the PausePanel into the Pause Panel field
  • Resume Button → On Click → PauseManager → ResumeGame
  • Main Menu Button → On Click → PauseManager → GoToMenu
4.5
Test the pause menu. Press Play in Level1. Press Escape — the game should freeze and show the pause overlay. Click Resume — game continues. Press Escape again — paused again. Click Main Menu — goes to menu.
4.6
Add a simple fade transition (optional but impressive). On both your MainMenu and Level1 Canvas, add a Panel named "FadePanel":
  • Image colour: Black, Alpha: 255 (fully opaque)
  • Move it to the TOP of the Canvas hierarchy (so it covers everything)
  • Add a CanvasGroup component to it
Then add this simple fade script:
using UnityEngine; public class FadeIn : MonoBehaviour { public CanvasGroup fadePanel; public float fadeSpeed = 1.5f; void Start() { fadePanel.alpha = 1f; // start fully black } void Update() { if (fadePanel.alpha > 0) { fadePanel.alpha -= fadeSpeed * Time.deltaTime; if (fadePanel.alpha <= 0) fadePanel.gameObject.SetActive(false); } } }
Effect: When the scene loads, it fades from black to visible. Simple but effective! For fade OUT, you'd increase alpha before calling LoadScene. Try it as an extension challenge.
Checkpoint: Pressing Escape pauses the game with a semi-transparent overlay. Resume button works. You understand Time.timeScale.
5
Extension — High Score & Win Condition
~13 min
+10 XP
🏆
Challenge time! Add a high score system and a win condition to make your game feel complete.
5.1
High Score System. Modify your GameOver logic to track the highest score:
// In GameOverManager.Start(): int finalScore = PlayerPrefs.GetInt("FinalScore", 0); int highScore = PlayerPrefs.GetInt("HighScore", 0); if (finalScore > highScore) { highScore = finalScore; PlayerPrefs.SetInt("HighScore", highScore); PlayerPrefs.Save(); // Show "NEW HIGH SCORE!" text } scoreText.text = "Score: " + finalScore; highScoreText.text = "Best: " + highScore;
5.2
Win Condition. Create a "WinZone" trigger at the end of your level:
  • Create an empty GameObject → name "WinZone"
  • Add Box Collider 2D → Is Trigger ✓
  • Position it at the end of your level
  • Tag it as "WinZone" (create new tag)
// In PlayerController.OnTriggerEnter2D: if (other.CompareTag("WinZone")) { PlayerPrefs.SetInt("FinalScore", score); SceneManager.LoadScene("WinScreen"); }
5.3
Animated menu elements. Make your Main Menu more professional:
  • Title text: Add an Animation component, create a gentle "bob" animation (move Y up and down slightly)
  • Buttons: Adjust Button colours for Normal, Highlighted (hover), Pressed, and Disabled states
  • Add floating particles in the background for atmosphere
  • Add your background music to the Main Menu scene
5.4
Multiple levels. If you have multiple levels:
// Load the NEXT scene by index: int nextScene = SceneManager.GetActiveScene().buildIndex + 1; if (nextScene < SceneManager.sceneCountInBuildSettings) { SceneManager.LoadScene(nextScene); } else { // No more levels — go to win screen SceneManager.LoadScene("WinScreen"); }
🚀
Super Extension: Add a "Settings" screen accessible from the Main Menu with volume sliders, a "Credits" screen, or a level select screen where each level is a button that loads a specific scene.
Checkpoint: You've implemented at least one extension (high score, win condition, animated menu, or multi-level loading).