Educational examples demonstrating C++ reflection and serialization techniques for game engines, based on the "Reflection & Serialization" lecture.
This project demonstrates various approaches to reflection and serialization in C++ game engines, from basic RTTI to advanced meta-programming systems. Each example is self-contained and progressively builds understanding of how modern game engines achieve data-driven design.
reflection-examples/
├── CMakeLists.txt # Root build configuration
├── README.md # This file
├── common/ # Shared types and utilities
│ ├── types.hpp # Vector3, Quaternion, Transform
│ └── json_helpers.hpp # JSON serialization for common types
└── examples/ # Individual examples
├── 01_basic_rtti/ # C++ built-in RTTI
├── 02_visit_struct/ # Macro-based reflection
├── 03_entt_meta/ # EnTT meta system
├── 04_entt_snapshots/ # ECS serialization
├── 05_generic_serialization/ # Engine/game separation ⭐
├── 06_cereal_serialization/ # Serialization-only library
├── 08_lua_integration/ # Lua scripting integration
└── 09_wren_integration/ # Wren scripting integration
- CMake 3.20 or later
- C++20 compatible compiler (GCC 10+, Clang 11+, MSVC 2019+)
# Create build directory
mkdir build && cd build
# Configure
cmake ..
# Build all examples
cmake --build .
# Or build specific example
cmake --build . --target 03_entt_metaFrom the build directory:
# Windows
.\examples\01_basic_rtti\01_basic_rtti.exe
# Linux/Mac
./examples/01_basic_rtti/01_basic_rttiOr use CMake to build and run:
cmake --build . --target 03_entt_meta && ./examples/03_entt_meta/03_entt_metaWhat it demonstrates: C++'s built-in Runtime Type Information
- Using
typeidandstd::type_info - Type comparison and name retrieval
- Limitations: No member iteration, no introspection
- Why RTTI is insufficient for game engines
Key takeaway: RTTI provides minimal type info; game engines need full reflection.
What it demonstrates: Macro-based reflection system
VISITABLE_STRUCTmacro for member registration- Iterating over struct members with
visit_struct::for_each - Generic serialization to/from JSON
- Simple and lightweight approach
Key takeaway: Macros enable reflection, but require listing members twice.
What it demonstrates: EnTT's powerful meta reflection system
- Runtime type registration with
entt::meta<T>() - Dynamic member access without compile-time type knowledge
- Iterating all registered types and their members
- Foundation for generic engine code
Key takeaway: Meta systems enable runtime introspection and manipulation.
What it demonstrates: Proper ECS serialization
entt::snapshotfor saving registry stateentt::continuous_loaderfor restoring state- Binary archive adapters
- Preserving entity IDs and component data
Key takeaway: EnTT provides dedicated serialization, but must specify component types.
What it demonstrates: Engine/game separation pattern (MOST IMPORTANT!)
- engine.hpp: Generic code that serializes ANY registered component type
- game_components.hpp: Game-specific components (PlayerController, EnemyAI, etc.)
- main.cpp: Demonstrates complete separation and includes console property inspector
- Engine serializes components it doesn't know about at compile time!
Key takeaway: This is how real game engines work! Add new components without recompiling the engine.
Special feature: Interactive console-based property inspector demonstrating editor functionality.
What it demonstrates: Serialization WITHOUT reflection
- JSON and binary serialization with Cereal library
- Clear demonstration that Cereal is NOT reflection
- Comparison: what Cereal can and cannot do
- Why game engines need true reflection systems
Key takeaway: Cereal is great for simple save/load, but can't build editor UI or expose to scripting.
What it demonstrates: Scripting language integration via reflection
- Binding C++ types to Lua using Sol3
- Creating and modifying C++ objects from Lua scripts
- Calling C++ methods from Lua
- Reading Lua-modified data back in C++
- Implementing game logic in Lua
Key takeaway: Reflection enables exposing C++ to scripting languages for runtime-modifiable game logic.
What it demonstrates: Lightweight scripting alternative
- Binding C++ types to Wren using foreign class API
- Similar integration pattern to Lua
- Comparing Wren vs Lua for game scripting
- Multiple scripting language support
Key takeaway: Same reflection system can power different scripting languages - choice depends on project needs.
All dependencies are automatically downloaded via CMake FetchContent:
- EnTT (v3.12.2) - Entity Component System with meta reflection
- nlohmann/json (v3.11.3) - JSON serialization
- visit-struct (v1.1.0) - Macro-based struct reflection
- cereal (v1.3.2) - Serialization library
- Sol3 (v3.3.0) - Modern C++ Lua binding library
- Lua (5.4.6) - Scripting language
- Wren (latest) - Lightweight scripting language
Reflection: Runtime introspection and manipulation of types
- List member names and types
- Get/set member values dynamically
- Iterate all registered types
- Build editor UI, scripting integration
Serialization: Converting objects to/from storable format
- Save to file (JSON, binary, XML)
- Load from file
- Network transmission
Key insight: Serialization is a subset of reflection! Full reflection enables serialization PLUS much more.
Modern game engines achieve data-driven design through reflection:
- Game registers types at startup with meta system
- Engine works generically without knowing types at compile time
- Add new components without recompiling engine
- Same system powers:
- Serialization (save/load) - Examples 5, 6
- Editor UI (property inspectors) - Example 5
- Scripting (expose C++ to Lua/Wren) - Examples 8, 9
- Networking (component replication)
See Example 5 for engine/game separation and Examples 8-9 for scripting integration!
These techniques are used in:
- Unity: C# reflection (built-in)
- Unreal Engine: UHT (Unreal Header Tool) code generation
- Godot: GDScript property system
- Custom Engines: EnTT meta, rttr, Ponder
Recommended order:
- Start with Example 1 - Understand RTTI limitations
- Example 2 - See how macros enable reflection
- Example 3 - Learn EnTT meta basics
- Example 4 - Understand ECS serialization
- Example 5 ⭐ - Master engine/game separation (THE MOST IMPORTANT!)
- Example 6 - Understand serialization vs reflection
- Example 8 - See reflection enable Lua scripting integration
- Example 9 - Compare with Wren for scripting alternatives
Note: Example 7 (RTTR) was skipped as it requires complex setup. Examples 8-9 demonstrate the same core concepts using EnTT meta.
If you encounter build errors:
- Ensure C++20 is supported by your compiler
- Update CMake to 3.20 or later
- Check that FetchContent can access GitHub (firewall/proxy issues)
All dependencies are downloaded automatically. If FetchContent fails:
# Clean build directory and retry
rm -rf build
mkdir build && cd build
cmake ..This educational project is provided as-is for learning purposes.
This is an educational project. Feel free to use and modify for learning!
Happy Learning! 🎮
Master these patterns and you'll understand how modern game engines achieve data-driven design!