Game Engine Architecture: ECS, Scene Graphs & Module Design | Game Development Hub
Introduction
Game engine architecture is the foundation upon which all game systems are built. The architectural decisions made early in engine development cascade through every subsystem — rendering, physics, AI, networking, and tooling. This guide explores the three pillars of modern engine architecture: Entity-Component-System (ECS) design, scene graph management, and module/plugin boundaries.
Entity-Component-System (ECS) Architecture
ECS has become the dominant paradigm for high-performance game engines. Unlike traditional object-oriented inheritance hierarchies, ECS separates data (components) from behavior (systems) and uses composition over inheritance.
Core Concepts
Entities
— Unique identifiers (typically 64-bit integers) with no data or behavior of their own
Components
— Plain data structures (POD types) containing only state, no methods
Systems
— Stateless logic that operates on entities matching a component query
Archetype-Based Storage
Modern ECS implementations (flecs, EnTT, Bevy ECS) use archetype-based storage where entities with the same component set share contiguous memory layouts. This enables:
Cache-friendly iteration over component arrays
SIMD-friendly data layouts
Fast query filtering via archetype bitmasks
ECS vs Traditional Inheritance
Aspect
Inheritance (OOP)
ECS
Code Reuse
Inheritance hierarchies
Composition
Memory Layout
Scattered (vtable pointers)
Contiguous arrays
Adding Features
Modify class hierarchy
Add component + system
Cache Performance
Poor
Excellent
Parallelism
Difficult
Natural (system-level)
Scene Graph Design
The scene graph represents the hierarchical spatial relationships between entities in the game world. It serves multiple purposes: transform propagation, visibility culling, and logical grouping.
Transform Hierarchy
Each node maintains a local transform (position, rotation, scale) and computes a world transform by combining with its parent:
worldTransform = parent.worldTransform * localTransform
Dirty flags propagate down the hierarchy — when a parent changes, all descendants are marked for transform update. This enables efficient partial updates.
Scene Graph vs ECS
In pure ECS, the scene graph is just another component relationship:
Parent
component: stores parent entity ID
Children
component: stores vector of child entity IDs (or linked list)
LocalTransform
+
WorldTransform
components
A
TransformSystem
computes world transforms in topological order
This decouples spatial hierarchy from logical entity identity.
Spatial Partitioning Integration
Scene graphs often integrate with spatial acceleration structures:
Octrees / BVH for broad-phase collision and frustum culling
Portals / sectors for indoor visibility
Quadtree for 2D games
Module Boundaries & Plugin Architecture
Large engines require clear module boundaries to manage complexity, enable team parallelism, and support hot-reloading.
Core Module Categories
Module
Responsibilities
Dependencies
Core
Memory, logging, math, containers, reflection
None
ECS
Entity management, component storage, system scheduler
Core
Renderer
Graphics API abstraction, resource management, draw submission
Core, ECS
Physics
Collision detection, dynamics simulation, query API
Core, ECS
Audio
Spatial audio, DSP, middleware abstraction
Core, ECS
Input
Device abstraction, action mapping, input buffering
Core
Networking
Serialization, replication, prediction/reconciliation
Core, ECS
Scripting
Language binding, hot reload, sandbox
Core, ECS
Editor
Tools, inspectors, asset pipeline integration
All runtime modules
Plugin System Design
A plugin system enables extending engine functionality without modifying core code:
// Plugin interface
struct IPlugin {
virtual void initialize(Engine& engine) = 0;
virtual void shutdown() = 0;
virtual const char* getName() const = 0;
virtual Version getVersion() const = 0;
};
// Registration
Engine::registerPlugin
();
Engine::loadPlugin("path/to/plugin.dll");
Key considerations:
Version compatibility via semantic versioning
Dependency declaration between plugins
Hot-reload support via DLL unload/load cycles
Sandboxed memory allocators per plugin
System Scheduling & Parallelism
Modern ECS schedulers automatically parallelize systems based on component access patterns (read/write):
// System declares component access
struct MovementSystem : System {
Query
query; // Read Position, Write Velocity
void run(World& world, float dt) {
for (auto [pos, vel] : query.iter(world)) {
pos.value += vel.value * dt;
}
}
};
// Scheduler builds dependency graph
// Systems with no write conflicts run in parallel
This enables scaling across CPU cores without manual thread management.
Conclusion
Game engine architecture is a balance of performance, flexibility, and maintainability. ECS provides the data-oriented foundation for cache efficiency and parallelism. Scene graphs manage spatial relationships with efficient transform propagation. Clean module boundaries with plugin support enable large teams to work in parallel and extend the engine over time. Master these three pillars, and you'll build engines that scale from indie projects to AAA productions.
Comments
Post a Comment