ECS = Data Locality + Component
rareicon (Unity DOTS) batches systems over packed component arrays — Component + Data Locality + Update Method, fused.
A Game Design Document describes what the game is. This page describes how the code is shaped to support it. The patterns below are the common architectural building blocks of game engines and gameplay code: ways to decouple systems, sequence frame work, model behavior, and squeeze out performance.
These are own-words summaries focused on intent, when to reach for it, and the trade-off you accept. They are not a substitute for the source material.
Classic Gang-of-Four patterns, reconsidered through a game-shaped lens — where they help and where they hurt.
Wrap an action in an object so it can be stored, queued, undone, or replayed. The caller fires a command without knowing what it does; the command knows how to do and undo it.
Share the data that is identical across many instances; keep only the per-instance data local. A thousand trees reference one shared mesh/texture and carry only their own transform.
Let objects announce events without knowing who listens. Subjects publish; observers subscribe. Decouples the thing that changes from the things that react.
Create new objects by cloning an existing instance rather than instantiating a class. Spawners hold a template and stamp out copies.
A single globally-accessible instance. The most over-used pattern in game code.
Patterns that govern time — how the game advances frame to frame.
Render or compute into a back buffer, then swap it with the front buffer atomically. Readers always see a complete, consistent frame; writers never tear.
The heartbeat: process input, update the world, render — forever, decoupled from the wall clock so the game runs the same on fast and slow hardware.
Each live entity gets an update() called once per frame to advance its own behavior by one tick. The loop walks a collection and ticks each.
Patterns for defining what entities do.
Encode behavior as data — instructions for a tiny virtual machine — instead of hardcoding it in the engine language. Designers/modders author behavior without recompiling.
A base class exposes a set of safe primitive operations; subclasses define behavior by combining those primitives, never touching the engine directly.
Move what would be subclasses into data instances of a single “type” class. A Monster holds a reference to a MonsterType (“Dragon”, “Goblin”) that carries shared stats/behavior.
Model an entity as a finite state machine — explicit states with explicit transitions — instead of a tangle of boolean flags.
Patterns that let one part of the program change without breaking others.
Build an entity by composing independent components (position, render, physics, health) instead of one deep inheritance tree. The entity is a bag of parts.
Decouple when an event is sent from when it is processed. Producers enqueue; a consumer drains the queue on its own schedule.
Provide global access to a service through an indirection layer, so callers find it without hardcoding the concrete implementation.
Patterns that trade complexity for speed — apply only after profiling.
Lay out data so the CPU cache stays hot: contiguous arrays of the data a loop actually touches, processed in order. The single biggest real-world game perf lever.
Defer expensive recomputation until the result is actually needed, and skip it entirely when nothing changed. Mark dirty on write; recompute lazily on read.
Reuse a fixed set of pre-allocated objects instead of allocating/freeing constantly. Take from the pool, return when done.
Organize objects by their position (grid, quadtree, BVH, BSP) so spatial queries touch only nearby candidates instead of every object.
ECS = Data Locality + Component
rareicon (Unity DOTS) batches systems over packed component arrays — Component + Data Locality + Update Method, fused.
State / StateTree
behavior_statetree models AI/units as typed-command state machines with a bounded queue boundary.
Object Pool
Combat events, bullets, and network packets reuse pooled buffers rather than per-frame allocation.
Event Queue
Cross-system messaging (chat relay, combat pipeline) drains queues on a fixed cadence rather than direct calls.