A game without a main menu feels like a prototype. A game without a pause menu feels broken the first time someone needs to step away. Both are quick to build in Godot 4, and there's one detail about pausing that trips up nearly everyone, so let's get it right.
The main menu
A menu is just a scene made of UI nodes. Start with a Control as the root, add a VBoxContainer to stack things vertically, and drop in a few Button nodes: Play, Options, Quit.
Then a script on the root that handles the buttons:
extends Controlfunc _ready() -> void: $VBoxContainer/PlayButton.pressed.connect(_on_play) $VBoxContainer/QuitButton.pressed.connect(_on_quit)func _on_play() -> void: get_tree().change_scene_to_file("res://scenes/Level.tscn")func _on_quit() -> void: get_tree().quit()change_scene_to_file() swaps the whole current scene for your level. get_tree().quit() closes the game. Set this menu scene as your main scene in Project Settings and it's the first thing players see.
You can also connect buttons in the editor through the Node panel, but connecting in code keeps all the behavior in one searchable place, which I prefer once a menu has more than a couple of buttons.
The pause menu and the gotcha
Here's the trap. You call get_tree().paused = true, and then realize your pause menu is also paused, so its buttons don't respond. The game's frozen and so is the thing meant to unfreeze it.
The fix is process_mode. Every node has one, and it decides whether the node keeps running while the tree is paused. Set your pause menu to keep working:
- Select your pause menu's root node.
- In the Inspector, find Process, then Mode.
- Set it to
When Paused(orAlways).
Now the menu runs even while everything else is frozen.
extends Controlfunc _ready() -> void: hide() # Make sure this menu keeps processing while the game is paused process_mode = Node.PROCESS_MODE_WHEN_PAUSEDfunc _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("ui_cancel"): toggle_pause()func toggle_pause() -> void: var paused := not get_tree().paused get_tree().paused = paused visible = pausedfunc _on_resume_pressed() -> void: get_tree().paused = false hide()func _on_quit_to_menu_pressed() -> void: get_tree().paused = false # always unpause before changing scenes get_tree().change_scene_to_file("res://scenes/MainMenu.tscn")ui_cancel is the built-in Escape action, so pause works out of the box. The one thing to remember: always set paused = false before changing scenes, or your next scene loads frozen.
A small polish pass
A pause menu that pops in instantly feels abrupt. Fade it in with a quick tween, and consider a dim background panel so the game clearly recedes:
func show_paused() -> void: modulate.a = 0.0 show() create_tween().tween_property(self, "modulate:a", 1.0, 0.15)Where this fits
Menus, scene changes, and pausing are the connective tissue that turns a pile of scenes into a game someone can actually sit down and play. If you're still building the systems those menus wrap around, the free Inventory System quest is a good place to build a real one, UI and all, with the same Control nodes you just used here.
FAQ
How do I pause a game in Godot 4?
Set get_tree().paused = true. The catch is that your pause menu pauses too, so set its process_mode to When Paused or Always in the Inspector. That keeps the menu responsive while the rest of the game is frozen.
Why doesn't my pause menu work when the game is paused?
Because the menu is paused along with everything else. Its buttons can't respond. Change the menu node's Process Mode to When Paused (or Always) so it keeps running while get_tree().paused is true.
How do I switch scenes in Godot 4?
Call get_tree().change_scene_to_file("res://path/to/Scene.tscn"). It unloads the current scene and loads the new one. Always unpause first with get_tree().paused = false if you're changing scenes from a pause menu, or the new scene starts frozen.