That means you can freeze gameplay cleanly without faking it by disabling random systems one by one.
When the game is paused:
update()still runslateUpdate()still runsfixedUpdate()stops- physics stops stepping
- sprite animation playback stops
WaitForSecondsstops 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 / StopPause / ResumeStep
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()andTime::isPaused()still reporttrue
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:
- listen for pause input during normal gameplay
- toggle the engine pause state
- 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
WaitForSecondsrespects engine pauseTime::time()andTime::deltaTime()freeze while pausedTime::unscaledTime()andTime::unscaledDeltaTime()continue while pausedupdate()andlateUpdate()still run while pausedfixedUpdate()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.