Skip to main content

Collision Detection Example

This example demonstrates the grid-based collision detection system with multiple entity types, collision responses, and the SpawnSystemFactory DSL for complex spawn patterns including cyclic edge spawning.

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
  • SpawnSystemFactory DSL - Declarative spawn configuration with custom placers and cyclic schedulers
  • Projectile System - Twin-stick shooting with bullet pooling via PrefabId
  • State Management - Game state tracking via Session with typed GameState transitions
  • Automated Rendering - SceneRenderingSystem handles viewport-based rendering
  • AI Chase System - Blue enemies chase the player using ChaseSystem
  • Typed Passes - Systems execute conditionally based on GameState
  • Complete GameLoop - Full Pre/Main/Post phase pipeline with commit points

Building

cmake -S . -B build
cmake --build build --target collision_detectionmain

Running

./build/examples/collision_detection/main

Controls

InputAction
Left StickMove spaceship / Rotate
Right StickAim direction / Fire projectiles
ESCExit application
~ (Tilde)Toggle ImGui overlay

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
CollisionStateComponentPer-frame collision results
AabbColliderComponentWorld-space bounding box
LevelBoundsBehaviorComponentArena boundary response
Move2DComponent2D physics simulation
SteeringComponentDirection-based rotation
ShootComponentProjectile firing with cooldown
Aim2DComponentAiming direction and fire frequency
SpinComponentContinuous rotation animation
ChaseComponentAI chasing behavior
PrefabIdComponentIdentifies prefab type for pooling
Active / InactiveEntity activation state tags

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
GameObjectSpawnSystemProcesses spawn schedulers
ChaseSystemAI pursuit behavior
HierarchyPropagationSystemPropagates transforms through hierarchies
StateToViewportPolicyUpdateSystemActivates viewports based on game state
SceneSyncSystemSyncs transforms to scene graph
SceneRenderingSystemRenders scenes to associated viewports

Collision Layer System

Entities are assigned collision layers and masks via the GameObjectFactory:

.withCollision([](auto& cb) {
cb.collision()
.layerId(CollisionId::Player)
.useBoundingBox()
.hitPolicy(HitPolicy::OneHit)
.reportCollisions(true)
.solidCollisionMask(CollisionId::Enemy)
.onSolidCollision(CollisionId::Enemy, CollisionBehavior::Despawn);

cb.levelBoundsCollision()
.onCollision(CollisionBehavior::Bounce);
})

Spawn System Configuration (DSL)

The example uses complex spawn patterns including cyclic edge spawning:

SpawnSystemFactory::configure(poolManager, spawnManager)
// Projectiles: emitter-relative placement
.pool(ProjectilePoolId, ProjectilePrefabId, 50)
.profile(ProjectileSpawnProfileId)
.emitterPlacement()
.done()
.commit()

// Purple enemies: random placement, timed
.pool(PurpleEnemyPoolId, PurpleEnemyPrefabId, 50)
.profile(RandomSpawnProfileId)
.randomPlacement()
.randomDirectionInitializer()
.scheduledBy(PurpleSpawnRuleId)
.timerCondition(5.0f)
.fixedAmount(1)
.done()
.done()
.commit()

// Orange enemies: cyclic edge spawning from four directions
.pool(OrangeEnemyPoolId, OrangeEnemyPrefabId, OBJECT_AMOUNT_X)
.profile(LeftColumnProfileId)
.axisPlacement(vec3f(0, -1, 0).normalize(), TOP_LEFT)
.moveInitializer(X_AXISf)
.scheduledBy(LeftColumnRuleId)
.timerWithAvailabilityCondition(15.0f)
.fixedAmount(OBJECT_AMOUNT_Y)
.done()
.done()
// ... profiles for Top, Right, Bottom edges
.commitCyclic<4>();

Collision Behaviors

Different entities respond differently to collisions:

EntityLevel BoundsEntity Collision
PlayerBounceDespawn on enemy hit
Purple EnemyReflectDespawn on player/projectile
Orange EnemyBounce + align headingDespawn on player/projectile
Blue EnemyReflect + align headingDespawn on player/projectile
ProjectileDespawnDespawn on enemy hit

GameLoop Phase Configuration

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

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

// Post-Phase: Transform and Rendering
gameLoop.phase(PhaseType::Post)
.addPass<GameState>(GameState::Any)
.addSystem<ComposeTransformSystem>()
.addSystem<StateToViewportPolicyUpdateSystem<GameState, MatchState>>(stateToViewportMap)
.addSystem<SceneSyncSystem>(sceneToViewportMap)
.addSystem<SceneRenderingSystem>(renderingDevice, sceneToViewportMap)
.addSystem<TransformClearSystem>()
.addSystem<DelayedComponentEnablerSystem>()
.addSystem<CollisionStateClearSystem>();

See Also