Skip to main content

Spaceship Control Example

This example demonstrates a complete game loop using the component-based game system, input handling, logging, and ImGui debug overlay integration.

Features

  • Component System - GameObject with attachable components (Move2DComponent, SceneNodeComponent)
  • Gamepad Input - Control a spaceship using analog sticks via TwinStickInputComponent
  • Command Pattern - Input mapped to reusable command objects (Move2DCommand, Aim2DCommand)
  • ImGui Debug Overlay - Real-time logging, camera control, physics tuning via dockable widgets
  • Frame Pacing - Configurable target FPS with performance metrics
  • Scene Graph Camera - Camera follows spaceship using transform inheritance
  • Units System - Object sizes defined in meters (1 hu = 1 m)

Building

cmake -S . -B build
cmake --build build --target spaceship_control

Running

./build/bin/spaceship_control

Controls

InputAction
Left StickMove spaceship / Rotate
ESCExit application

Code Structure

FilePurpose
main.cppApplication entry point and game loop
SpaceshipWidget.ixxImGui widget for physics parameter tuning

The spaceship behavior is implemented via engine components:

ComponentPurpose
SceneNodeComponentLinks GameObject to scene graph
Move2DComponent2D physics with rotation and dampening
TwinStickInputComponentTranslates gamepad input to commands
TransformComponentStores local/world transform state
ScaleComponentUnit-based sizing (meters)

Systems Used

SystemPurpose
ScaleSystemApplies ScaleComponent sizing
Move2DSystemPhysics simulation (rotation, velocity)
SceneSyncSystemSyncs transforms to scene graph
TransformClearSystemClears dirty flags post-frame
ScaleClearSystemClears scale dirty flags

Camera System

The camera is attached to the spaceship in the scene graph and uses selective transform inheritance:

// Create camera as child of spaceship
auto cameraNode = std::make_unique<CameraSceneNode>(std::move(camera));
auto* camPtr = spaceshipNode->addNode(std::move(cameraNode));

// Inherit only position, not rotation
camPtr->setInheritance(helios::math::TransformType::Translation);
camPtr->lookAtLocal(vec3f(0.0f, 0.0f, 0.0f), vec3f(0.0f, 1.0f, 0.0f));

ImGui Integration

The example includes a complete ImGui setup with multiple widgets:

// Backend and overlay
auto imguiBackend = ImGuiGlfwOpenGLBackend(window->nativeHandle());
auto imguiOverlay = ImGuiOverlay::forBackend(&imguiBackend);

// Add widgets
imguiOverlay.addWidget(new MainMenuWidget()); // Settings menu
imguiOverlay.addWidget(new FpsWidget(&metrics)); // FPS display
imguiOverlay.addWidget(new GamepadWidget(&input)); // Gamepad state
imguiOverlay.addWidget(new LogWidget()); // Log console
imguiOverlay.addWidget(new CameraWidget()); // Camera control
imguiOverlay.addWidget(new SpaceshipWidget()); // Physics tuning

Component-Based Game System

The example uses helios's component-based game framework with dedicated systems:

// Create game world and command buffer
auto gameWorld = GameWorld{};
auto commandBuffer = CommandBuffer{};
auto updateContext = UpdateContext{&commandBuffer, &gameWorld};

// Create spaceship as GameObject with components
auto shipGameObject = std::make_unique<GameObject>();
shipGameObject->add<SceneNodeComponent>(spaceshipSceneNode);
shipGameObject->add<Move2DComponent>();
shipGameObject->add<TwinStickInputComponent>();
shipGameObject->add<TransformComponent>();
shipGameObject->add<ScaleComponent>(5.0f, 5.0f, 0.0f, Unit::Meter);

auto* ship = gameWorld.addGameObject(std::move(shipGameObject));

// Register game systems
gameWorld.add<ScaleSystem>();
gameWorld.add<Move2DSystem>();
gameWorld.add<SceneSyncSystem>(scene.get());
gameWorld.add<TransformClearSystem>();
gameWorld.add<ScaleClearSystem>();

// Game loop
updateContext.setDeltaTime(deltaTime);
updateContext.setInputSnapshot(&inputSnapshot);
gameWorld.update(updateContext);
commandBuffer.flush(gameWorld);

Physics Tuning

Use the Spaceship Physics widget to adjust movement parameters at runtime:

  • Movement: Max speed, acceleration, dampening
  • Rotation: Max rotation speed, dampening
  • Reset: Restore default physics values