Skip to main content

gameloop Folder

Files Index

filehelios/engine/runtime/gameloop/_module.ixx

Module aggregator for helios.engine.runtime.gameloop. More...

fileCommitPoint.ixx

Defines commit points for synchronization within the game loop. More...

fileGameLoop.ixx

Central orchestrator for the game update cycle. More...

filePass.ixx

Abstract base class for game loop passes. More...

filePassCommitListener.ixx

Interface for listeners notified when a pass commits its state. More...

filePhase.ixx

Represents a phase within the game loop containing multiple passes. More...

fileTypedPass.ixx

State-filtered pass implementation for game loop phases. More...

Description

helios::engine::runtime::gameloop

Central game loop orchestration module providing phased system execution.

The gameloop module provides the core infrastructure for managing the game update cycle. It organizes systems into a hierarchical structure of phases and passes, enabling deterministic execution order and event synchronization.

Architecture

The game loop follows a three-phase architecture:

Pre Phase - Processes input and generates commands. Systems in this phase read player input and enqueue commands into the CommandBuffer.

Main Phase - Executes core gameplay simulation. This includes physics, AI, game logic, and collision detection systems.

Post Phase - Handles cleanup and synchronization. Systems in this phase synchronize the gameplay state with the scene graph and clear dirty flags.

Each phase contains one or more passes. A pass groups related systems and can optionally define a commit point for event synchronization within the phase.

Commands can be enqueued into the CommandBuffer during any phase, not just the Pre phase. After each phase completes, the CommandBuffer is flushed and all registered managers process their pending requests. This ensures that spawn/despawn operations and other deferred actions are executed at well-defined points in the update cycle.

Key Components

GameLoop is the central orchestrator that owns the three phases and the event buses. The EngineCommandBuffer and Managers are owned by the GameWorld's ResourceRegistry and accessed via UpdateContext at commit points. The GameLoop drives the frame update by iterating through all phases and committing events and commands after each phase.

Phase represents a distinct stage in the update cycle. Phases contain passes and are executed in fixed order (Pre → Main → Post).

Pass contains a registry of systems that execute sequentially. Passes support commit points to synchronize pass-level events before the next pass begins.

CommitPoint is a flag enum that specifies which synchronization actions occur at the end of a pass. Available flags include:

  • PassEvents - Synchronizes pass-level events for the next pass.
  • FlushCommands - Executes pending commands from the CommandBuffer.
  • FlushManagers - Processes manager requests (e.g., spawning from pools).
  • Structural - Combines all three flags for a full structural commit.

Flags can be combined using bitwise OR to trigger multiple actions at once.

Usage

 import helios.engine.runtime.gameloop.GameLoop;
 import helios.engine.runtime.world.GameWorld;
 
 
 // Register state types with session
 gameWorld.session().trackState<GameState>();
 
 // Configure Pre phase (state-filtered passes)
 gameLoop.phase(PhaseType::Pre)
  .addPass<GameState>(GameState::Any)
  .addSystem<InputSystem>()
  .addCommitPoint(CommitPoint::Structural)
  .addPass<GameState>(GameState::Running)
  .addSystem<MovementSystem>()
  .addSystem<SteeringSystem>();
 
 // Configure Main phase with commit points
 gameLoop.phase(PhaseType::Main)
  .addPass<GameState>(GameState::Running)
  .addSystem<CollisionDetectionSystem>()
  // Commit pass events so collision responses can read them
  .addCommitPoint()
  .addPass<GameState>(GameState::Running)
  .addSystem<CollisionResponseSystem>()
  // Full structural commit: events, commands, and managers
  .addCommitPoint(CommitPoint::Structural);
 
 // Configure Post phase
 gameLoop.phase(PhaseType::Post)
  .addPass<GameState>(GameState::Any)
  .addSystem<SceneSyncSystem>()
  .addSystem<TransformClearSystem>();
 
 // Initialize and run
 gameWorld.init();
 gameLoop.init(gameWorld);
 
 while (running) {
  gameLoop.update(gameWorld, deltaTime, inputSnapshot, viewportSnapshots);
  renderer.render(scene);
 }

Event Synchronization

The game loop provides three levels of event synchronization:

Pass-level events are synchronized at commit points within a phase. This allows systems in the next pass to react to events generated by the previous pass - within the same phase. Pass-level events are discarded at the end of the phase and do not carry over to the next phase.

Phase-level events are synchronized after each phase completes. Only events written via pushPhase() are available to systems in the following phase. Commands are flushed and managers process their requests at phase boundaries.

Frame-level events are synchronized at the end of the Post phase. Events written via pushFrame() become readable in the next frame via readFrame(). This is useful for cross-frame communication such as audio/VFX triggers, UI updates, or analytics events.

CommitPoint Configuration

Commit points provide fine-grained control over synchronization within a phase. By default, addCommitPoint() uses CommitPoint::PassEvents which only synchronizes pass-level events.

For more control, specify the desired flags explicitly:

 // Only synchronize pass events (default)
 pass.addCommitPoint(CommitPoint::PassEvents);
 
 // Flush commands after this pass, but defer manager processing
 pass.addCommitPoint(CommitPoint::FlushCommands);
 
 // Full structural commit: events + commands + managers
 pass.addCommitPoint(CommitPoint::Structural);
 
 // Custom combination
 pass.addCommitPoint(CommitPoint::PassEvents | CommitPoint::FlushManagers);

The execution order within a commit point is deterministic: 1. Pass events are synchronized (if PassEvents is set) 2. Commands are flushed (if FlushCommands is set) 3. Managers process requests (if FlushManagers is set)

This ordering ensures that commands can generate manager requests before managers are flushed.

 ┌─────────────────────────────────────────────────────────────────────────┐
 │ FRAME UPDATE │
 ├─────────────────────────────────────────────────────────────────────────┤
 │ │
 │ ┌─────────────── PRE PHASE ───────────────┐ │
 │ │ Pass 1 Pass 2 │ │
 │ │ ┌──────┐ ┌──────┐ │ │
 │ │ │Sys A │──┬────▶│Sys B │ │ │
 │ │ └──────┘ │ └──────┘ │ │
 │ │ │ │ │
 │ │ passPush() │ │
 │ │ (commit point) │ │
 │ └─────────────────────────────────────────┘ │
 │ │ │
 │ phasePush() │
 │ ▼ │
 │ ┌────────────── MAIN PHASE ───────────────┐ │
 │ │ Pass 1 Pass 2 │ │
 │ │ ┌──────┐ ┌──────┐ │ │
 │ │ │Sys C │──┬────▶│Sys D │ │ ◀── reads phase events │
 │ │ └──────┘ │ └──────┘ │ from Pre phase │
 │ │ │ │ │
 │ │ passPush() │ │
 │ │ (commit point) │ │
 │ └─────────────────────────────────────────┘ │
 │ │ │
 │ phasePush() │
 │ ▼ │
 │ ┌────────────── POST PHASE ───────────────┐ │
 │ │ Pass 1 │ │
 │ │ ┌──────┐ ┌──────┐ │ ◀── reads phase events │
 │ │ │Sys E │ │Sys F │ │ from Main phase │
 │ │ └──────┘ └──────┘ │ │
 │ └─────────────────────────────────────────┘ │
 │ │
 │ Legend: │
 │ passPush() → events available in next pass (same phase) │
 │ phasePush() → events available in next phase │
 │ ─────────── → pass events discarded at phase boundary │
 │ │
 └─────────────────────────────────────────────────────────────────────────┘


Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.