Guide

Game scene management and screen flow explained

Every game is a sequence of screens — splash, main menu, loading, gameplay, pause overlay, settings, game over — wired together by a scene manager that decides what loads, what unloads, and what stays alive in memory. Poor scene flow is one of the fastest ways to lose players: a three-second hitch on level load, a pause menu that forgets controller focus, or a back button that dumps you to the desktop instead of the previous menu. This guide explains how to model scenes vs UI screens, build navigation stacks, run async loads behind transitions, layer pause and modal overlays without corrupting game state, budget memory across scene changes, and implement patterns that work in Unity, Godot, Phaser, and custom engines — with ties to save systems, HUD design, and the game loop.

Scenes, levels, and screens — three different ideas

Developers often conflate these terms. Separating them early prevents spaghetti navigation code:

  • Scene (engine term). A self-contained unit the engine loads and unloads — a collection of nodes, entities, or GameObjects with its own update loop. Unity's SceneManager, Godot's change_scene(), and Phaser's Scene plugin all operate at this layer.
  • Level (gameplay term). A playable space inside a scene — often one scene per level, but open-world games may stream level chunks inside a persistent world scene.
  • Screen (UI term). A visible state the player recognizes — main menu, inventory, credits. Screens can live inside one scene (overlay UI) or map 1:1 to scenes (mobile games often use one scene per screen).

The architectural choice is whether navigation is scene-swapping (unload everything, load fresh) or screen-stacking (push/pop UI layers on a persistent root). Action games typically swap gameplay scenes but stack pause/settings overlays. Menu-heavy mobile titles often stack everything in one scene to avoid reload cost.

The navigation stack

Treat screen flow like a browser history stack. Each push(screen) pauses the screen below; each pop() resumes it. A minimal stack for a single-player RPG might look like:

[Boot] → [MainMenu] → [Loading] → [World] ⇄ [Pause] → [Settings]
                                              ⇄ [Inventory modal]

Implement the stack as a finite state machine or explicit array with lifecycle hooks: onEnter, onPause, onResume, onExit. Every screen must know whether it is opaque (hides everything below) or transparent (gameplay continues underneath — rare for full-screen UI but common for HUD tooltips).

Back-button and escape semantics

Console certification and mobile OS guidelines require predictable back behavior. Document a single rule: Escape / B button calls stack.pop() unless the top screen overrides (e.g. gameplay opens pause first; second press opens confirm-quit dialog). Never let back exit the app from deep menus without confirmation — players fat-finger constantly.

Async loading and loading screens

Synchronous scene loads freeze the main thread and produce visible hitches. Production games load asynchronously and show a loading screen that:

  • Displays immediately (lightweight first scene or persistent bootstrap scene).
  • Polls load progress (Unity AsyncOperation.progress, Godot ResourceLoader.load_threaded_request, custom asset manifests).
  • Never reports 100% until activation is safe — Unity's async load stalls at 0.9 until you call allowSceneActivation.
  • Offers tips, lore, or tutorial hints during waits longer than two seconds.

Fake progress bars that stall at 99% erode trust. Either show real bytes loaded or an indeterminate spinner with engaging content. For web games, prefetch critical bundles during the menu idle time using requestIdleCallback or background fetches.

Additive vs single-load

Single-load replaces the entire scene — simplest memory profile, highest transition cost. Additive loading keeps a persistent bootstrap scene (audio manager, net session, UI canvas) and loads gameplay additively on top. Unload the additive scene when leaving gameplay; bootstrap survives. This pattern is standard for multiplayer where disconnecting must not destroy the lobby UI.

Transitions — hiding the seam

Hard cuts between scenes feel cheap. Common transition types:

  • Full-screen fade. Fade to black, swap scene during opaque frame, fade in. Cheap and reliable; masks load hitches.
  • Crossfade. Two scenes render briefly — expensive on fill-rate but cinematic for story beats.
  • Slide / wipe. Popular in mobile puzzle games; works well when scenes share a visual language.
  • Loading curtain with animation. Character runs through a door while assets load behind — ties transition to fiction.

Run transitions on a persistent overlay canvas owned by the bootstrap scene so they survive scene swaps. Duration sweet spot: 0.25–0.6 seconds for menus; longer only when paired with real load time. Ease curves (ease-in-out) feel more polished than linear alpha ramps.

Pause, settings, and modal overlays

Pause is not a new scene in most action games — it is an overlay that:

  • Sets timeScale = 0 (or pauses fixed-tick simulation only).
  • Stops or ducks audio via mixer snapshots.
  • Captures input focus for UI navigation (see input handling).
  • Leaves the gameplay scene resident so resume is instant.

Modal dialogs (confirm quit, item inspect) stack above pause. Define a modal priority integer: gameplay HUD = 0, pause = 100, system dialog = 200, debug console = 300. Only the topmost modal receives input. Opening a modal should not destroy the screen beneath — pop when dismissed.

Settings screens deserve special care: changing resolution or key bindings may require applying on close rather than live, with a revert path if the player misconfigures and cannot see the UI.

Memory and asset lifecycle

Scene changes are the right moment to enforce memory budgets:

  • Unload policy. When leaving gameplay, explicitly release level textures, audio banks, and pooled objects. Engines do not always garbage-collect aggressively — call Resources.UnloadUnusedAssets() in Unity or equivalent.
  • Reference leaks. Static events, singleton caches, and DontDestroyOnLoad objects holding scene references prevent unload. Audit with memory profilers after every major scene path.
  • Preload next. Open-world games preload adjacent cells during low-intensity moments; pair with object pooling so spawned entities reset rather than accumulate.
  • Web and mobile caps. Browser tabs crash around 1–2 GB; mobile OS kills background apps without warning. Keep menu scenes lean; stream heavy assets only inside gameplay.

Persisting state across scenes

Not everything belongs in a save file. Cross-scene state falls into tiers:

  • Session state — selected difficulty, current run seed, party composition. Lives in a session singleton cleared on return to main menu.
  • Profile state — unlocked achievements, settings, currency. Persists to disk/cloud; loaded at boot.
  • Scene-local state — enemy positions, open doors. Serialized at checkpoints or lost on scene unload unless explicitly carried forward.

Hydrate scene-local state in onEnter from the session or save layer — never read global statics from scattered files. A single GameSession or RunState object makes testing and multiplayer replication easier.

Multiplayer and scene authority

Online games cannot let every client freely load scenes. Common patterns:

  • Server-driven transitions. Host signals LoadMap(mapId); clients show loading UI, stream assets, then ACK ready before simulation resumes.
  • Staggered spawn. Players who load slowly see a spectator camera until their client reports ready — avoids desync from partial worlds.
  • Reconnect. Persist enough session state that a late joiner or reconnecting player can rebuild the active scene from a snapshot, not from scratch.

See multiplayer netcode for tick sync; scene flow is where that sync meets the player-facing experience.

Engine-specific notes

EngineScene APITypical pattern
Unity SceneManager.LoadSceneAsync, additive mode Bootstrap scene + additive gameplay; UI Toolkit or uGUI on persistent canvas
Godot 4 change_scene_to_packed, threaded load Autoload singletons for session; CanvasLayer for overlays
Phaser 3 scene.start, scene.launch parallel Boot → Preload → Menu → Game scenes; parallel UI scene for HUD
Custom / Web Manual asset manifest + router SPA-style router with lazy import() chunks per screen

Decision table — which pattern when

SituationRecommended approach
Mobile menu-heavy game, small assets Single scene, UI stack navigation, no full reloads
Level-based action game Swap gameplay scenes; pause/settings as overlays on bootstrap
Open world Persistent world scene + streaming sub-scenes / chunks
Online match-based Server-authoritative map load with client ready gates
Web game, large assets Lazy chunks + loading screen; prefetch during menu idle

Anti-patterns to avoid

  • God scenes. One scene containing menu, gameplay, and credits — unmaintainable memory and coupling.
  • Destroy-on-pause. Tearing down gameplay to show pause adds seconds to resume and breaks immersion.
  • Orphaned input listeners. Subscribing in onEnter without unsubscribing in onExit causes double-input after revisiting screens.
  • Blocking main thread loads during gameplay — always async with transition cover.
  • Inconsistent back behavior across platforms — certify early on real hardware.

Production checklist

  • Scene graph documented — diagram of every screen, load type, and overlay priority.
  • Navigation stack with push/pop/back semantics implemented and unit-tested.
  • Async load path for every gameplay scene; no sync loads in shipping builds.
  • Transition overlay on persistent canvas; minimum fade on all scene swaps.
  • Pause overlay freezes simulation, ducks audio, captures UI focus.
  • Memory audit after round-trip menu → game → menu on target hardware.
  • Session vs profile state separated; save hydration on scene enter.
  • Multiplayer ready gates if applicable — no simulation until all clients ACK.
  • Accessibility — focus order restored after closing modals; see accessibility guide.

Key takeaways

  • Scenes, levels, and screens are different layers — model each explicitly.
  • A navigation stack with lifecycle hooks beats ad-hoc if (inMenu) flags.
  • Async loading + transitions hide hitches; never block the main thread mid-gameplay.
  • Pause and modals are overlays with priority — not full scene reloads.
  • Memory and state tiers must be managed at every scene boundary, especially on web and mobile.

Related reading