Guides Behaviours Pausing the Game and Working with Time

Behaviours 4 min read Updated Apr 2026

Pausing the Game and Working with Time

Lenga supports engine-wide pause.

That means you can freeze gameplay cleanly without faking it by disabling random systems one by one.

When the game is paused:

  • update() still runs
  • lateUpdate() still runs
  • fixedUpdate() stops
  • physics stops stepping
  • sprite animation playback stops
  • WaitForSeconds stops counting down
  • active audio sources pause
  • rendering continues
  • input still updates
  • UI still updates and renders

update() and lateUpdate() continue so Behaviours can still listen for input, animate pause menus with unscaled time, and resume the game cleanly. The important difference is that scaled gameplay time is frozen, so Time::deltaTime() becomes 0 while paused.

That gives you the behavior most games actually want for pause menus, countdown overlays, settings screens, and photo-mode style pauses.

Editor Transport: Pause and Step

When you launch the game from the editor, the transport now supports:

  • Play / Stop
  • Pause / Resume
  • Step

Step is only active while the runtime is paused.

It advances exactly one authored simulation frame using the project's target FPS, then returns to paused. That makes it useful for checking animation transitions, physics handoff, scripted state changes, and one-frame gameplay bugs without letting the whole game continue running.

Important caveat:

  • the engine is still considered paused during that step
  • scaled time advances for that one stepped frame
  • but Application::isPaused() and Time::isPaused() still report true

That means Behaviours that immediately return early whenever the game is paused will also opt themselves out of step-frame execution.

If you want a Behaviour to participate in step mode, avoid broad guards like this:

public function update(): void
{
    if (Application::isPaused()) {
        return;
    }

    // gameplay logic...
}

That pattern is fine for pause-menu logic, but it also prevents the Behaviour from advancing during editor stepping.

Prefer using scaled time to freeze normal gameplay behavior where possible. In many cases, Time::deltaTime() === 0 is already enough to stop continuous gameplay movement without blocking the entire Behaviour.

The Core API

Use the Application facade from PHP:

use Lenga\Engine\Core\Application;

Application::pause();
Application::resume();
Application::togglePause();

if (Application::isPaused()) {
    // show a pause menu or update a label
}

That is the cleanest way to pause the whole game from a behaviour or UI button.

A Minimal Pause Controller

use Lenga\Engine\Core\Application;
use Lenga\Engine\Core\Behaviour;
use Lenga\Engine\Core\Input;
use Lenga\Engine\Enumerations\KeyCode;

final class PauseController extends Behaviour
{
    public function update(): void
    {
        if (Input::isKeyPressed(KeyCode::ESCAPE)) {
            Application::togglePause();
        }
    }
}

This is the common pattern:

  1. listen for pause input during normal gameplay
  2. toggle the engine pause state
  3. let UI react to Application::isPaused()

This also works while already paused, because update() keeps running.

Time: Scaled vs Unscaled

Lenga exposes both gameplay time and real frame time.

Gameplay time stops when the engine is paused:

use Lenga\Engine\Core\Time;

$gameplaySeconds = Time::time();
$gameplayDelta = Time::deltaTime();

Real frame time keeps advancing even while paused:

use Lenga\Engine\Core\Time;

$realSeconds = Time::unscaledTime();
$realDelta = Time::unscaledDeltaTime();

Good rule of thumb:

  • use Time::deltaTime() for gameplay movement, animation, and timers
  • use Time::unscaledDeltaTime() for pause-menu fades, cursor effects, and UI animation that should continue while paused

That means gameplay code usually freezes naturally during pause, while menu code can keep responding by switching to unscaled time where needed.

Why WaitForSeconds Freezes on Pause

WaitForSeconds uses gameplay time, not real time.

That means this coroutine pauses cleanly with the rest of the game:

use Lenga\Engine\Core\Behaviour;
use Lenga\Engine\Core\WaitForSeconds;

final class RoundIntro extends Behaviour
{
    public function start(): void
    {
        $this->startCoroutine($this->runIntro());
    }

    private function runIntro(): \Generator
    {
        $this->showLabel('Ready');
        yield new WaitForSeconds(1.0);

        $this->showLabel('Go');
        yield new WaitForSeconds(0.5);

        $this->hideLabel();
    }

    private function showLabel(string $value): void
    {
    }

    private function hideLabel(): void
    {
    }
}

If the player pauses halfway through that sequence, the coroutine waits until the game resumes.

That is usually what you want for gameplay timing.

Pause Menus Usually Want Unscaled Time

A pause menu often still wants subtle animation or transitions.

For example, this fade continues while the world is paused:

use Lenga\Engine\Core\Behaviour;
use Lenga\Engine\Core\Time;

final class PauseMenuPulse extends Behaviour
{
    public float $pulse = 0.0;

    public function update(): void
    {
        $this->pulse += Time::unscaledDeltaTime() * 2.0;
    }
}

The gameplay world is frozen, but the menu still feels alive.

This is also the key to unpausing cleanly: Behaviours still receive update(), but gameplay-time-driven code does not keep progressing unless it explicitly uses unscaled time.

What Pause Is Good At Today

Use engine pause for:

  • pause menus
  • settings overlays opened mid-game
  • photo-mode style freezes
  • countdowns or cut-ins that should stop when the player pauses
  • temporary developer inspection of a live scene

What Pause Does Not Mean

Pause is not the same thing as:

  • disabling a single component
  • muting audio only
  • hiding input from one Behaviour
  • creating bullet-time or slow motion

Those are different features.

Pause is a clean boolean state. Build slow motion, hit stop, or other time effects through the time system instead of scattering ad hoc checks across components.

How Pause Behaves

  • WaitForSeconds respects engine pause
  • Time::time() and Time::deltaTime() freeze while paused
  • Time::unscaledTime() and Time::unscaledDeltaTime() continue while paused
  • update() and lateUpdate() still run while paused
  • fixedUpdate() does not run while paused
  • UI still renders and can still respond
  • audio sources pause and resume with the engine
  • editor Step runs one simulation frame while pause state remains true
  • Behaviours that return early on Application::isPaused() will skip that stepped frame too

If you are building a pause menu, this is the mental model to keep in mind: freeze gameplay, not the application.