Skip to content

Pause Menu

Rahul-18K edited this page Oct 5, 2026 · 11 revisions

The pause menu allows players to pause the game during gameplay.

Players can:

  • pause the game using the Esc key
  • resume the game
  • restart the current level
  • quit to the main menu
  • change settings
  • check key binds for the game
  • save game state

When paused:

  • player movement is stopped
  • enemy movement is stopped
  • gameplay timers are stopped
  • animations freezes (except loot item bobbing effect)

Additional menu features and visual improvements may be added later.

Menu Actions

The pause menu and main menu use a display/action split: display components fire events, and a separate actions component listens for those events and performs the actual behaviour (changing screens, restarting the game, etc.).

Core Workflow

  • Event Firing: PauseMenuDisplay doesn't perform any logic itself — clicking Resume, Restart, or Main Menu just fires resumeClicked, restartClicked, or mainMenuClicked through the entity's event system.
  • Action Handling: PauseMenuActions listens for these events and performs the actual behaviour — toggling isPaused, or triggering restartGame.
  • Restart: MainGameActions listens for restartGame and calls game.setScreen(GdxGame.ScreenType.MAIN_GAME), which rebuilds the entire game screen — regenerating the terrain, entities, and player state (including resetting health to full).

Team Dependencies

  • PauseMenuDisplay: Must fire the correct event names (resumeClicked, restartClicked, mainMenuClicked, SettingsClicked, saveClicked) for PauseMenuActions to respond to.
  • MainGameScreen: Owns the ForestGameArea and service registration that gets rebuilt on restart or load to the saved game state; any changes to how the game area is constructed affect restart behaviour.

Behind The Scenes

Displays fire named events rather than acting directly, keeping button UI decoupled from game logic:

private void restart() {
  entity.getEvents().trigger("restartClicked");
}

PauseMenuActions listens and performs the actual action:

entity.getEvents().addListener("restartClicked", this::restart);

private void restart() {
  pauseMenu.toggleIsPaused();
  entity.getEvents().trigger("restartGame");
}

MainGameActions rebuilds the screen on restart:

private void onRestart() {
  game.setScreen(GdxGame.ScreenType.MAIN_GAME);
}

Note: An earlier version reset only the player's health in-place (via CombatStatsComponent) to avoid regenerating the map on restart. This was reverted so that restart fully regenerates the game area, matching the original ticket scope.

Keyboard Navigation

Overview

Both the Pause Menu and Main Menu support keyboard navigation in addition to mouse interaction, letting players move between menu options, adjust the volume sliders (master, music, effects), and confirm a selection without a mouse.

Core Workflow

  • Input Detection: Listens for Up, Down, Left, Right, Enter, and Space, and translates them into navigation intent.
  • Selection Movement: Up/Down move the highlighted option, wrapping around at the first and last item. In the Pause Menu, the volume slider is included as the final navigable item alongside the Resume/Restart/Main Menu buttons.
  • Volume Adjustment: When the slider is the currently selected item, Left/Right adjust its value.
  • Confirmation: Enter or Space triggers whichever action the currently highlighted option represents.
  • Mouse Compatibility: Mouse hover still works alongside keyboard navigation; whichever input method was used most recently controls the highlight, so the two never conflict.

Team Dependencies

  • Pause Menu UI / Main Menu UI: Provides the buttons (and, for the pause menu, the volume slider) that navigation moves between and confirms selections on.
  • Pause Trigger: Navigation only responds to input while the game is actually paused, via PauseMenuComponent.isPaused().

Behind The Scenes

Input Detection

PauseMenuInputComponent and MainMenuInputComponent each extend InputComponent and override keyDown(). Rather than acting directly, they fire named events through the entity's event system:

if (keycode == KeybindSettings.getKey("attack")) {
      entity.getEvents().trigger("attack");
      entity.getEvents().trigger("attacking", direction);
      return true;
    }

Event names fired:

  • navigateUp / navigateDown — direction pressed
  • navigateLeft / navigateRight (Pause Menu only) — adjusts the volume slider when it's selected
  • confirmSelection — Enter or Space pressed

This keeps input detection separate from menu behaviour: the input component has no knowledge of what the menu looks like or does, and the display component has no knowledge of how input was captured.

Selection Movement

The corresponding display component (PauseMenuDisplay / MainMenuDisplay) listens for navigateUp and navigateDown, and maintains a selectedIndex into its navigable items, wrapping with modulo arithmetic:

selectedIndex = (selectedIndex + 1) % itemCount;

Volume Adjustment

navigateLeft() and navigateRight() only take effect when the volume slider is the currently selected item. They adjust musicVol by a fixed step, clamped between 0 and 1, via musicSlider.setValue() — which fires the slider's existing ChangeListener, so the actual audio volume and the on-screen percentage label update through the same path as a mouse drag, rather than duplicating that logic. The navigateLeft() and navigateRight() also takes long press in account to adjust the volume too.

Keyboard vs. Mouse Highlighting

Since both keyboard navigation and mouse hover can highlight a menu item, a usingKeyboardNav flag determines which one currently owns the highlight colour:

private boolean usingKeyboardNav = true;
  • Pressing a navigation key sets usingKeyboardNav = true and highlights the selected item.
  • Any mouse movement sets usingKeyboardNav = false, clearing the keyboard highlight so hover can take over.
  • Each button's enter/exit listeners only apply hover colour while usingKeyboardNav is false.

This prevents both systems from highlighting different items at the same time.

Confirmation

confirmSelection maps selectedIndex onto the same events each button's click listener already fires (e.g. resumeClicked, restartClicked, mainMenuClicked, saveClicked, settingsClicked, audioClicked, keybindsClicked for the pause menu), so keyboard and mouse confirmation both funnel into the same downstream logic in PauseMenuActions / MainMenuActions. It has no effect when the volume slider is selected.

Clone this wiki locally