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:
- It depends on entities (for positions and colliders)
- It depends on input (for movement vectors)
- It depends on assets (level meshes, etc)
- It provides constraints for player and NPCs
- 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:
- Calculate where the entity wants to move
- Check if that position would cause collisions
- If so, keep the entity at its current position
- 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.