PVG
11. Simple Collisions — Program Video Games

11. Simple Collisions

Every wall that blocks your path, every treasure chest you can't walk through, every invisible boundary that keeps you from falling off the world - all of these rely on collision detection.

In our System Stack, the Collision system sits in the World Layer, building upon our foundation systems to create boundaries and interactions in our game world.

The Fractal Code Cycle Applied to Collisions

Recall our fundamental pattern:

Input → Processing → Output

For our collision system:

  • Input: Entity positions, movement vectors, collision geometry data
  • Processing: Check for overlaps, calculate collision responses
  • Output: Valid positions, collision events, movement constraints

What Are Collisions Good For?

Boundary Enforcement

  • Preventing players from walking through walls
  • Keeping entities within playable areas
  • Creating invisible barriers for level design

Interaction Triggers

  • Detecting when players approach NPCs
  • Triggering events when entering specific areas
  • Proximity-based gameplay mechanics

Physical Simulation

  • Objects bouncing off surfaces
  • Realistic movement constraints
  • Environmental storytelling through physical space

Collision Detection vs Collision Response

It's important to distinguish between these two concepts:

Collision Detection: Determining if two objects overlap
Collision Response: Deciding what happens when they do

Our simple system focuses on detection first, with a basic response of "don't allow the movement".

Collision System in the System Stack

Recall our System Stack organisation:

  • Base Layer: Entities, Input, Time, Assets, Save/Load
  • Presentation: Camera, Shaders, Animation, UI, Particles
  • Interaction: Player, Collisions, AI, Scenes
  • Game Systems: Stats, Combat, Inventory, Abilities
  • Content: Dialogue, Quests, NPC Schedules

The Collision system sits in the World Layer because:

  1. It depends on entities (for positions and colliders)
  2. It depends on input (for movement vectors)
  3. It depends on assets (level meshes, etc)
  4. It provides constraints for player and NPCs
  5. It enables interaction detection for higher-level systems (dialogue, quests, combat, etc)

Types of Collision Shapes

Circles/Spheres

  • Simple and fast to calculate
  • Good for characters and round objects
  • Distance-based calculations

Rectangles/Rectangular Prisms (Axis-Aligned Bounding Boxes)

  • Perfect for walls, doors, and rectangular objects
  • Easy to understand and debug
  • Efficient for static geometry

Arbitrary Shapes

  • More accurate but computationally expensive
  • Usually built from combinations of triangles
  • May need an acceleration structure - depending on profiling

Design Considerations

Performance

For our RPG with dozens of entities, we can afford simple collision checks. However, some techniques to keep in mind:

  • Broad Phase: Quickly eliminate obviously non-colliding pairs
  • Spatial Partitioning: Divide the world into regions to reduce checks
  • Static vs Dynamic: Separate geometry that never moves from moving entities

Collision Response Strategies

Stop Movement: Our current approach - simply don't allow invalid positions
Sliding: Allow movement along surfaces when hitting corners
Bouncing: Reflect movement vectors off surfaces
Push Apart: Separate overlapping objects

Visual Debugging

Always include visual debugging for collision systems:

  • Draw collision boundaries
  • Highlight active collisions
  • Show movement vectors and responses

This makes it much easier to tune and debug collision behaviour.

The Physics Struct

In our implementation, we've added a physics struct to the game state:

physics: struct {
    static_geometry: [dynamic]Rect,
},

This separates collision data from other systems, making it easy to:

  • Add new types of collision geometry
  • Implement different collision layers
  • Optimise collision data separately from entity data

Entity Collision Properties

We've added collision-specific data directly to entities:

movement_speed: f32,
collider_radius: f32,

This megastruct approach keeps collision data with the entities that need it, ensuring good cache locality for collision checks.

Implementation Pattern

Our collision checking follows a predictive pattern:

  1. Calculate where the entity wants to move
  2. Check if that position would cause collisions
  3. If so, keep the entity at its current position
  4. If not, allow the movement

This prevents entities from ever being in an invalid state, rather than detecting and correcting overlaps after they happen.

The Big Idea

Collision systems transform abstract mathematical spaces into tangible game worlds with boundaries, obstacles, and interactions.

Our simple circle-vs-rectangle approach provides a solid foundation that we can extend with arbitrary shapes, and then into 3D with spheres.

The key insight is starting simple and extending, rather than trying to b-line the perfect solution and becoming overwhelmed.