Lower-level game code breaks down when timing, input, rendering, state updates, and shutdown are blurred together; the project needed a readable loop with explicit system boundaries.
Retro Game
A terminal retro game with a C game loop, map generation, monster timing, rendering, and multiplayer-oriented branches.
Built and organized the C gameplay loop across input handling, map generation, frame rendering, timed monster movement, move resolution, multiplayer branches, and cleanup.
I kept the main lifecycle explicit rather than abstracting it too early, because readable control flow is more valuable than clever structure in this kind of C system.
The result is lower-level proof that I can reason about state, timing, lifecycle cleanup, and system boundaries outside a web application stack.
- Improves workflow reliability by keeping input, render, timer, multiplayer, and shutdown paths explicit.
- Tested as a lower-level C systems exercise across map generation, timed monster movement, and multiplayer-oriented branches.
- Reduces debugging ambiguity by making lifecycle cleanup and state transitions visible in the main loop.
The loop processes input, advances monster timing, rebuilds map state, renders the frame, applies player movement, and shuts down cleanly.
- Input
- Game state
- Timed monsters
- Map render
- Move result
- Shutdown
What changed in the proof surface.
- Framed the private source excerpt around lifecycle clarity instead of exposing private repository details.
- Identified deterministic scripted tests as the most useful next hardening step.
What this project demonstrates.
- Coordinates input, rendering, and game-state updates.
- Uses timed monster movement through a thread manager.
- Keeps multiplayer server behavior in the main gameplay flow.
The result is lower-level proof that I can reason about state, timing, lifecycle cleanup, and system boundaries outside a web application stack.
void play_game(GameState* state, GameMode mode){ThreadManager tm = { 0 };threading_manager_start(&tm);timeout(32);while (state->is_alive){InputAction action = process_input(state);if (action == INPUT_QUIT)break;if (!move_monster_on_timer(state, &tm))break;create_map(state);render_game(state);int result = move_hero(state);apply_move_result(state, result);if (mode == MODE_MULTIPLAYER_SERVER){int result_2 = move_hero_2(state);apply_move_result(state, result_2);}}render_game_over(state);threading_manager_shutdown(&tm);}
Input, timed movement, rendering, state application, and shutdown remain visible in the main loop.