DEV Community

Cover image for Learn Godot 4 by Making a 2D Platformer — Part 19: Pause & Main Menu
christine
christine

Posted on

Learn Godot 4 by Making a 2D Platformer — Part 19: Pause & Main Menu

*You can find the links to the previous parts at the bottom of this tutorial.

One of the core pieces of any game is a Pause and Main Menu. The Main Menu is the first screen that your player will see when they start the game, and the Pause Menu will pause the game when the player presses a button such as “ESC”. In our game, we want our Main Menu to allow the player to start a new game, load a saved game, or quit the game entirely. In our Pause Menu, we want the player to be able to resume their level, save their current level, reload their current level, and quit to the main menu screen.

STEP 1: PAUSE MENU UI

In our Player scene, let’s add a new CanvasLayer node called “PauseMenu”.

Godot 2D Platform

Add a ColorRect node to it and call it “Menu”. Change the anchor preset of this menu to be full-rect, and change its color to #834040.

Godot 2D Platform

Add another ColorRect node to your Menu node, and call it “Container”. Change its color to #964545, its size to (x: 1078, y: 580), and position to (x: 35, y: 25).

Godot 2D Platform

Godot 2D Platform

Copy and paste the TileMap, AnimatedKing, and AnimatedPig nodes from your GameOver node into your PauseMenu/Menu node.

Godot 2D Platform

Let’s change the AnimatedPig animation to be all the frames from the “res://Assets/Kings and Pigs/Sprites/06-Pig Hide in the Box/Looking Out (26x20).png” spritesheet. Change the FPS to “4”, and leave the looping on.

Godot 2D Platform

Change the AnimatedKing animation to be all the frames from the “res://Assets/Kings and Pigs/Sprites/01-King Human/Idle (78x58).png” spritesheet. Change the FPS to “11”, and leave the looping on.

Godot 2D Platform

Make the TileMap a bit different and move your King and Pig to where you want them to be.

Godot 2D Platform

Now, to your PauseMenu/Menu/Container node, add four Button nodes and one Label node. Organize and rename them as indicated in the image below.

Godot 2D Platform

1. Label

Select your Label node and change its text to “Pause Menu”. Its font should be “QuinqueFive”, and the size of the font should be 35. Also change its position to be (x: 299, y: 20).

Godot 2D Platform

2. ButtonResume

Select your ButtonResume node and change its text to “Resume Level”. Its font should be “QuinqueFive”, and the size of the font should be 25. Change the font color to #d98c8a. Also change its size to (x: 500, y: 80) and its position to (x: 285, y: 100).

Godot 2D Platform

3. ButtonSave

Select your ButtonSave node and change its text to “Save Level”. Its font should be “QuinqueFive”, and the size of the font should be 25. Change the font color to #d98c8a. Also change its size to (x: 500, y: 80) and its position to (x: 285, y: 200).

Godot 2D Platform

4. ButtonLoad

Select your ButtonLoad node and change its text to “Load Level”. Its font should be “QuinqueFive”, and the size of the font should be 25. Change the font color to #d98c8a. Also change its size to (x: 500, y: 80) and its position to (x: 285, y: 300).

Godot 2D Platform

5. ButtonQuit

Select your ButtonQuit node and change its text to “Quit Level”. Its font should be “QuinqueFive”, and the size of the font should be 25. Change the font color to #d98c8a. Also change its size to (x: 500, y: 80) and its position to (x: 285, y: 400).

Godot 2D Platform

Now, connect all of your four buttons’ pressed() signals to your Player script.

Godot 2D Platform

Change your PauseMenu node’s visibility to be hidden.

Godot 2D Platform

Finally, we need to change our PauseMenu node’s Processing Mode to “When Paused”, since we only want it to accept input when the game is paused, and no other nodes need access to it when the game isn’t paused.

Godot 2D Platform

STEP 2: MAIN MENU UI

Copy your PauseMenu node branch from your Player scene, and create a new scene from the option “Paste From Clipboard”.

Godot 2D Platform

Godot 2D Platform

Rename the root node to “MainMenu”, and save your scene as “MainMenu” underneath your Scenes folder.

Godot 2D Platform

Now, delete one Button node, and rename the remaining three as indicated in the image below.

Godot 2D Platform

Attach a new script to your MainMenu scene, and save it underneath your Scripts folder.

Godot 2D Platform

Disconnect and reconnect the pressed() signal connections on all three of your buttons so that they are connected to your MainMenu script.

Godot 2D Platform

Then, change your MainMenu root node’s Processing Mode to “Always”.

Godot 2D Platform

1. Label

Select your Label node and change its text to “Castle Climber”. Its font should be “QuinqueFive”, and the size of the font should be 35. Also change its position to be (x: 299, y: 20).

Godot 2D Platform

2. ButtonNew

Select your ButtonNew node and change its text to “New Game”. Its font should be “QuinqueFive”, and the size of the font should be 30. Change the font color to #d98c8a. Also change its size to (x: 500, y: 100) and its position to (x: 285, y: 120).

Godot 2D Platform

3. ButtonLoad

Select your ButtonLoad node and change its text to “Load Game”. Its font should be “QuinqueFive”, and the size of the font should be 30. Change the font color to #d98c8a. Also change its size to (x: 500, y: 100) and its position to (x: 285, y: 240).

Godot 2D Platform

4. ButtonQuit

Select your ButtonQuit node and change its text to “Quit”. Its font should be “QuinqueFive”, and the size of the font should be 30. Change the font color to #d98c8a. Also change its size to (x: 500, y: 100) and its position to (x: 285, y: 360).

Godot 2D Platform

You can change your AnimatedKing and AnimatedPig animations to be any animation you want. I duplicated my AnimatedPig node to be another pig that stands on our boxed friend. Also, draw the tilemap so that it has a variety from the other screens!

Godot 2D Platform

STEP 3: PAUSE MENU FUNCTIONALITY

To have our pause menu show, we’ll first need to create a new input called ui_pause that will open up our menu if we press an input such as “ESC”.

Godot 2D Platform

In our input() function, let’s make our pause menu visible when the player presses our newly created input. We’ll also pause the game to stop our players and spawners from processing.

    ### Player.gd

    #older code

    #singular input captures
    func _input(event):
        #pause game
        if event.is_action_pressed("ui_pause"):
            #pause scene
            get_tree().paused = true
            #show menu
            $PauseMenu.visible = true
Enter fullscreen mode Exit fullscreen mode

Then, in our resume button’s _on_button_resume_pressed() function, we’ll unpause our game and hide our menu.

    ### Player.gd

    #older code

    #resume game
    func _on_button_resume_pressed():
        #unpause scene
        get_tree().paused = false
        #hide menu
        $PauseMenu.visible = false
Enter fullscreen mode Exit fullscreen mode

Next, we’ll change our scene back to our MainMenu scene if the player presses our quit button. We’ll do these changes in our _on_button_quit_pressed() function.

    ### Player.gd

    #older code

    #quit to main menu  
    func _on_button_quit_pressed():
        get_tree().change_scene_to_file("res://Scenes/MainMenu.tscn")
Enter fullscreen mode Exit fullscreen mode

We’ll add the remaining functionality to our _load_pressed() and _save_pressed() in the next part when we add a save/load system.

Now if you run your scene, you should be able to pause your game, resume it, as well as quit the MainMenu scene.

Godot 2D Platform

STEP 4: MAIN MENU FUNCTIONALITY

To quit our game in our _on_button_quit_pressed() function, we can simply call the quit() method, which will kill and close the application entirely.

    ### MainMenu.gd

    #older code

    #quit game
    func _on_button_quit_pressed():
        get_tree().quit()
Enter fullscreen mode Exit fullscreen mode

Now, in our _on_button_new_pressed() function, we will first need to clear our current_scene that our player is in. We need to do this to ensure that our current_scene is properly removed from the application’s memory, and thus we can assign a new current_scene which will override the data from the previous current_scene value.

    ### MainMenu.gd

    #older code

    #starts a new game in the Main scene, which is our 1st level
    func _on_button_new_pressed():
        # Get the current scene
        var current_scene = get_tree().current_scene
        # Free the current scene if it exists
        if current_scene:
            current_scene.queue_free()
Enter fullscreen mode Exit fullscreen mode

After we’ve removed our current_scene from our memory, we need to create a new instance of our first level — which is our Main.tscn scene.

    ### MainMenu.gd

    #older code

    #starts a new game in the Main scene, which is our 1st level
    func _on_button_new_pressed():
        # Get the current scene
        var current_scene = get_tree().current_scene
        # Free the current scene if it exists
        if current_scene:
            current_scene.queue_free()
        # Load the new scene
        var new_scene = load("res://Scenes/Main.tscn").instantiate()
Enter fullscreen mode Exit fullscreen mode

We then need to add this instanced scene as a child to our new scene, because we want this child to then be the new value of our current_scene variable.

    ### MainMenu.gd
    #older code

    #starts a new game in the Main scene, which is our 1st level
    func _on_button_new_pressed():
        # Get the current scene
        var current_scene = get_tree().current_scene
        # Free the current scene if it exists
        if current_scene:
            current_scene.queue_free()
        # Load the new scene
        var new_scene = load("res://Scenes/Main.tscn").instantiate()
        # Add the new scene as a child of the root node
        get_tree().root.add_child(new_scene)
        # Set the new scene as the current scene
        get_tree().set_current_scene(new_scene)
        # Update the global variable with the name of the new scene
        Global.current_scene_name = new_scene.name
Enter fullscreen mode Exit fullscreen mode

Finally, we need to unpause the game to ensure that our new game does not start in a paused state.

    ### MainMenu.gd
    #older code

    #starts a new game in the Main scene, which is our 1st level
    func _on_button_new_pressed():
        # Get the current scene
        var current_scene = get_tree().current_scene
        # Free the current scene if it exists
        if current_scene:
            current_scene.queue_free()
        # Load the new scene
        var new_scene = load("res://Scenes/Main.tscn").instantiate()
        # Add the new scene as a child of the root node
        get_tree().root.add_child(new_scene)
        # Set the new scene as the current scene
        get_tree().set_current_scene(new_scene)
        # Update the global variable with the name of the new scene
        Global.current_scene_name = new_scene.name
        # Ensures scene isn't paused
        get_tree().paused = false
Enter fullscreen mode Exit fullscreen mode

Your code should look like this.

Now if you run your Main scene, you should be able to start a new game as well as quit your game entirely.

Godot 2D Platform

With our main and pause menu’s bases set up, we can continue on to the next part where we will add the functionality to our player to save and load their game — which will load them into their last saved level.

Now would be a good time to save your project and make a backup of your project so that you can revert to this part if any game-breaking errors occur. Go back and revise what you’ve learned before you continue with the series, and once you’re ready, I’ll see you in the next part!


Next Part to the Tutorial Series

The tutorial series has 24 chapters. I’ll be posting all of the chapters in sectional daily parts over the next couple of weeks. You can find the updated list of the tutorial links for all 24 parts of this series on my GitBook. If you don’t see a link added to a part yet, then that means that it hasn’t been posted yet. Also, if there are any future updates to the series, my GitBook would be the place where you can keep up-to-date with everything!

Godot 2D Platform


Support the Series & Gain Early Access!

If you like this series and would like to support me, you could donate any amount to my KoFi shop or you could purchase the offline PDF that has the entire series in one on-the-go booklet!

The booklet gives you lifelong access to the full, offline version of the “Learn Godot 4 by Making a 2D Platformer” PDF booklet. This is a 451-page document that contains all the tutorials of this series in a sequenced format, plus you get dedicated help from me if you ever get stuck or need advice. This means you don’t have to wait for me to release the next part of the tutorial series on Dev.to or Medium. You can just move on and continue the tutorial at your own pace — anytime and anywhere!

Godot 2D Platform

This book will be updated continuously to fix newly discovered bugs, or to fix compatibility issues with newer versions of Godot 4.

Top comments (3)

Collapse
 
wynandpieters profile image
Wynand Pieters

Just wanted to a leave a comment and say I've really been enjoying this series and the RPG one. Good work and keep it up!

I've mostly been doing Unity in the past, and had a look at Godot 3 but wasn't converted, but I have a new project in mind that can really benefit from this series.

Collapse
 
christinec_dev profile image
christine

I'm glad you like the series! Good luck with your game idea!😊

Collapse
 
alusandman profile image
Luis

Hello, thank you for this fantastic tutorial. But I have a problem. When I press the new game button, the game gives an error related to the bombspawner object. Specifically, the error appears in the _ready lines related to bomb_animation:

E 0:00:01:0580 bomb_spawner.gd:15 @ _ready(): Node not found: "/root/MainMenu/BombPath/Path2D/PathFollow2D" (absolute path attempted from "/root/Main/BombSpawner").
Method/function failed. Returning: nullptr
scene/main/node.cpp:1623 @ get_node()
bomb_spawner.gd:15 @ _ready()
MainMenu.gd:18 @ _on_button_new_pressed()

The same thing happens when I finish, I cross the door to go from one level to another. However, if I directly load the level scene, the game works.