What it did
Build the classic Snake game in SDL2 + modern C++. Fixed-timestep game loop, keyboard input, collision detection on a grid, score persistence to a text file, scaling difficulty.
The C++ nanodegree’s foundations capstone is meant to demonstrate the
RAII + smart-pointer + STL patterns from the first half of the course —
Snake fits well because the SDL handles need cleanup on exit and the
data structures (deque for snake body, point for food) come straight
from <deque> and <utility>.
What was actually tricky
- Fixed-timestep vs. variable-timestep. Variable timestep makes the snake “slip” at low frame rates. Fixed timestep with an accumulator (a la Glenn Fiedler’s “Fix Your Timestep!”) makes movement consistent across machines.
- SDL resource lifetimes.
SDL_Window*andSDL_Renderer*are raw pointers; wrapping them instd::unique_ptrwith a custom deleter is the modern-C++ way. Without it, every earlyreturnleaks. - The snake’s collision-with-self check is O(n) per frame — fine for n=20 but the lesson is real: O(n²) creeps in if you’re not paying attention to the inner loop.
What I’d do differently with hindsight
- Decouple input + simulation + render into three layers. This project has them tangled in one game loop. Even Snake benefits from a clean ECS-lite split.
- Use
enttor similar if you want to scale this pattern. For Snake it’s overkill; for any next game it’s correct. - WebAssembly export. SDL2 cross-compiles to WASM via Emscripten; ship the game as a single HTML page instead of a binary.
What it taught me
Real-time loops have a different feeling than batch programs. The game loop’s tight constraint (16 ms budget at 60 fps, regardless of state) trains a different kind of discipline. Every later real-time-ish project (the EKF in the simulator, the perception pipeline) inherited the same intuition: the loop has a budget; spend it carefully.