Skip to main content

Collision Detection Example

This example demonstrates the grid-based collision detection system with multiple entity types, collision responses, and visual feedback for debugging.

Features

  • Grid-Based Collision Detection - Spatial partitioning with GridCollisionDetectionSystem
  • Multiple Collision Behaviors - Bounce, Reflect, Despawn based on entity type
  • Collision Events - TriggerCollisionEvent and SolidCollisionEvent for game logic
  • Entity Spawning - Timed enemy spawning with configurable spawn rules
  • Projectile System - Twin-stick shooting with bullet pooling
  • Visual Collision Feedback - Color changes on collision for debugging
  • Complete GameLoop - Full Pre/Main/Post phase pipeline with commit points

Building

cmake -S . -B build
cmake --build build --target collision_detection

Running

./build/bin/collision_detection

Controls

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

Code Structure

FilePurpose
main.cppApplication entry point with collision setup
CollisionId.ixxCollision layer identifiers
_module.ixxModule aggregation

Components Used

ComponentPurpose
CollisionComponentCollision layer and mask configuration
AabbColliderComponentWorld-space bounding box
LevelBoundsBehaviorComponentArena boundary response
Move2DComponent2D physics simulation
ShootComponentProjectile firing with cooldown
Aim2DComponentAiming direction and fire frequency
SpinComponentContinuous rotation animation

Systems Used

SystemPurpose
GridCollisionDetectionSystemSpatial grid broadphase + AABB narrowphase
CollisionStateResponseSystemProcesses collision events
CollisionStateClearSystemClears collision flags per frame
BoundsUpdateSystemUpdates AABB from transforms
LevelBoundsBehaviorSystemHandles arena boundary collisions
ProjectileSpawnSystemSpawns projectiles from ShootComponent
GameObjectSpawnSystemTimed enemy spawning

Collision Layer System

Entities are assigned collision layers and masks to control which entities can collide:

// Define collision layers
enum class CollisionId : uint32_t {
Player = 1 << 0,
Enemy = 1 << 1,
Projectile = 1 << 2,
Boundary = 1 << 3
};

// Configure player collision
shipGameObject.get<CollisionComponent>()
->setLayer(CollisionId::Player)
->setMask(CollisionId::Enemy | CollisionId::Boundary);

// Configure enemy collision
enemyPrefab->get<CollisionComponent>()
->setLayer(CollisionId::Enemy)
->setMask(CollisionId::Player | CollisionId::Projectile);

Grid-Based Collision Detection

The GridCollisionDetectionSystem uses spatial partitioning for efficient broadphase:

// Add collision detection system with grid cell size
gameLoop.phase(PhaseType::Main)
.addPass()
.addSystem<GridCollisionDetectionSystem>(cellSize)
.addSystem<CollisionStateResponseSystem>()
.addCommitPoint()
.addPass()
.addSystem<CollisionStateClearSystem>();

Collision Behaviors

Different entities respond differently to collisions:

EntityLevel BoundsEntity Collision
PlayerBouncePush back
EnemyReflectContinue
ProjectileDespawnDespawn on hit
// Player bounces off walls
shipBuilder.withCollision([](auto& cb) {
cb.collision().useBoundingBox();
cb.levelBoundsCollision()
.onCollision(CollisionBehavior::Bounce);
});

// Projectiles despawn at boundaries
projectileBuilder.withCollision([](auto& cb) {
cb.collision().useBoundingBox();
cb.levelBoundsCollision()
.onCollision(CollisionBehavior::Despawn);
});

GameLoop Phase Configuration

// Pre-Phase: Input, Spawning, Physics
gameLoop.phase(PhaseType::Pre)
.addPass()
.addSystem<TwinStickInputSystem>(shipGameObject)
.addCommitPoint(CommitPoint::Structural)
.addPass()
.addSystem<ProjectileSpawnSystem>(ProjectileSpawnProfileId)
.addSystem<GameObjectSpawnSystem>(spawnSchedulers)
.addCommitPoint(CommitPoint::Structural)
.addPass()
.addSystem<ScaleSystem>()
.addSystem<SteeringSystem>()
.addSystem<SpinSystem>()
.addSystem<Move2DSystem>();

// Main-Phase: Collision Detection and Response
gameLoop.phase(PhaseType::Main)
.addPass()
.addSystem<BoundsUpdateSystem>()
.addSystem<GridCollisionDetectionSystem>(cellSize)
.addSystem<CollisionStateResponseSystem>()
.addSystem<LevelBoundsBehaviorSystem>()
.addCommitPoint()
.addPass()
.addSystem<CollisionStateClearSystem>();

// Post-Phase: Transform and Rendering
gameLoop.phase(PhaseType::Post)
.addPass()
.addSystem<ComposeTransformSystem>()
.addSystem<SceneSyncSystem>(scene.get())
.addSystem<TransformClearSystem>();

Collision Events

The collision system emits events that can be consumed by game logic:

// Read collision events in a system
void update(UpdateContext& ctx) {
for (const auto& event : ctx.readPhaseEvents<TriggerCollisionEvent>()) {
// Handle trigger collision (e.g., pickup, damage zone)
}

for (const auto& event : ctx.readPhaseEvents<SolidCollisionEvent>()) {
// Handle solid collision (e.g., physics response)
}
}

ImGui Integration

Full debug overlay with:

  • FPS monitoring and frame pacing
  • Gamepad state visualization
  • Log console with scope filtering
  • Camera manipulation
  • Physics parameter tuning
imguiOverlay.addWidget(new MainMenuWidget());
imguiOverlay.addWidget(new FpsWidget(&metrics, &framePacer));
imguiOverlay.addWidget(new GamepadWidget(&inputManager));
imguiOverlay.addWidget(new LogWidget());
imguiOverlay.addWidget(new CameraWidget());