Skip to main content

Spaceship Shooting Example

This example extends the spaceship control demo with a complete twin-stick shooting system, demonstrating the projectile pooling system, aiming components, and 2D collision detection via AABB.

Features

  • Twin-Stick Shooter Controls - Left stick for movement, right stick for aiming and shooting
  • Component-Based Architecture - Full integration with helios component/system framework
  • Projectile Pool System - Efficient projectile management with configurable pool size
  • Level Bounds System - Arena boundaries with bounce behavior
  • ShootComponent - Configurable cooldown and projectile speed parameters
  • Aim2DComponent - Direction tracking and firing frequency management
  • Physics Systems - Move2DSystem, ScaleSystem, BoundsUpdateSystem
  • Scene Synchronization - SceneSyncSystem bridges gameplay and rendering
  • Ellipse Shape - 2D ellipse primitive for projectile rendering
  • Colors Utility - Standard color palette (helios::util::Colors) for material properties

Building

cmake -S . -B build
cmake --build build --target spaceship_shooting

Running

./build/bin/spaceship_shooting

Controls

InputAction
Left StickMove spaceship / Rotate
Right StickAim direction / Fire projectiles
ESCExit application

Code Structure

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

Components Used

ComponentPurpose
SceneNodeComponentLinks GameObject to scene graph
Move2DComponent2D physics with acceleration, dampening, and rotation
TwinStickInputComponentTranslates dual analog stick input to movement/aim commands
TransformComponentStores local/world transform state
ScaleComponentUnit-based sizing (meters)
Aim2DComponentTracks aim direction and firing frequency
ShootComponentManages projectile firing with cooldown timer
LevelBoundsBehaviorComponentBounce behavior at arena boundaries
AabbColliderComponentWorld-space collision bounds

Systems Used

SystemPurpose
ProjectilePoolSystemObject pool for projectile spawning and recycling
ScaleSystemApplies ScaleComponent sizing
Move2DSystemPhysics simulation (rotation, velocity)
SceneSyncSystemSyncs transforms to scene graph
BoundsUpdateSystemUpdates AABB colliders from transforms
LevelBoundsBehaviorSystemHandles boundary collisions
TransformClearSystemClears dirty flags post-frame
ScaleClearSystemClears scale dirty flags

Projectile Pool System

The example demonstrates efficient projectile management with systems:

// Create projectile renderable with ellipse shape
auto projectile = Ellipse{1.0f, 0.4f, 8}; // width, height, segments
auto projectileMesh = std::make_shared<OpenGLMesh>(projectile, meshConfig);
auto projectilePrototype = std::make_shared<RenderPrototype>(material, projectileMesh);
auto projectileRenderable = std::make_shared<Renderable>(std::move(projectilePrototype));

// Add projectile pool system to game world
gameWorld.add<ProjectilePoolSystem>(std::move(projectileRenderable), 50);

// Register physics and cleanup systems
gameWorld.add<ScaleSystem>();
gameWorld.add<Move2DSystem>();
gameWorld.add<SceneSyncSystem>(scene.get());
gameWorld.add<BoundsUpdateSystem>();
gameWorld.add<LevelBoundsBehaviorSystem>();
gameWorld.add<TransformClearSystem>();
gameWorld.add<ScaleClearSystem>();

Color Palette

The example uses the standard color palette for material properties:

import helios.util.Colors;

// Use predefined colors
auto spaceshipMaterial = MaterialProperties(helios::util::Colors::Yellow);
auto gridMaterial = MaterialProperties(helios::util::Colors::Turquoise.withW(0.2f));
auto aimGizmo = MaterialProperties(helios::util::Colors::Magenta);

Aiming and Shooting

The shooting system uses components for clean separation of concerns:

// Add aiming and shooting components to spaceship
shipGameObject->add<Aim2DComponent>();
shipGameObject->add<ShootComponent>();

// ShootComponent automatically interacts with ProjectilePoolSystem
// when the right stick is active (via TwinStickInputComponent)

Debug Visualization

Gizmo lines visualize input and movement state:

  • Green Line - Left stick input scaled by throttle
  • Magenta Line - Right stick aim direction scaled by frequency
  • Red Line - Ship velocity direction scaled by speed ratio

ImGui Widgets

The example includes the same widget setup as spaceship_control:

  • MainMenuWidget - Application settings (transparency, docking, themes)
  • FpsWidget - Frame rate display and target FPS control
  • GamepadWidget - Real-time gamepad state and deadzone settings
  • LogWidget - Scrollable log console with scope filtering
  • CameraWidget - Camera parameter control
  • SpaceshipWidget - Physics parameter tuning for Move2DComponent

Technical Notes

Arena Collision

Projectiles and the spaceship are constrained to the arena bounds defined via the Level system:

// Create level with arena bounds
auto level = std::make_unique<Level>(&(scene->root()));
level->setBounds(
aabb{-72.5f, -47.5f, 0.0f, 72.5f, 47.5f, 0.0f},
Unit::Meter
);
gameWorld.setLevel(std::move(level));

// Spaceship bounces off arena edges via LevelBoundsBehaviorComponent
shipGameObject->add<LevelBoundsBehaviorComponent>();

Note: The grid's Z-index is at 0 (min/max), which works for 2D gameplay but should be made more flexible for 3D scenarios.

Unit System

Object sizes use the helios unit system (1 hu = 1 meter) via ScaleComponent:

// Set spaceship size to 5x5 meters
shipGameObject->add<ScaleComponent>(5.0f, 5.0f, 0.0f, Unit::Meter);