The Low-Level Logic: Deconstructing a C/CSFML RPG Engine

gif

collage

The Finn Fisherman RPG was a massive project for our first year at Epitech. The challenge was not just to create an RPG with mandatory features like inventory, quests, and combat, but to build the entire engine using pure C and the CSFML library.

I personally drove the implementation of the physics, combat, environment graphics, and menu systems. This deep dive into low-level logic taught me exactly how game architecture works when you can’t rely on a pre-built engine.


1. The Architectural Foundation: C and Module Isolation

At 92.8% C, the project demanded extreme structural discipline. Every major game system was isolated into its own module, enforcing a clean structure that made group collaboration possible.

Key Architectural Concepts

  • API-First Design: The include/ directory served as our official contract. By defining functions like combat_calculate_damage() and physics_handle_collision() in the headers first, we ensured that every module had a stable, well-defined API before implementation even began.
  • Custom Utility Layer: Instead of relying on external libraries, we built a foundational utility layer (a custom ‘lib’ structure) for common needs like vector mathematics, memory handling, and data structures. This ensured our code was consistent and highly performant for the specific needs of the game.
  • State Machine Management: The entire application runs on a Finite State Machine (FSM). A central game context manages switching between states like MAIN_MENU, IN_GAME, PAUSED_MENU, and COMBAT, ensuring only the necessary systems (e.g., rendering, input) are active at any given moment.

2. The Physics of a Fake 3D World

Implementing collision and depth perception without a game engine was a significant hurdle. We had to write custom math for every interaction.

Advanced Physics Logic

  • Isometric Projection & Depth Scaling: To create the “fake 3D” look, we used a specific mathematical transformation to map 2D coordinates into a screen projection. Crucially, we implemented Depth Scaling: objects rendered closer to the bottom of the screen are drawn on top of objects above them, correctly simulating depth and ensuring the player character walks behind a tree trunk.
  • Time-Independent Movement: All movement is calculated using delta time ($\Delta\text{Time}$) from a system clock. This is essential for frame rate independence, guaranteeing that a character’s speed remains constant whether the game is running at 30 FPS or 120 FPS.
  • Complex Collision Resolution: We had to handle collisions for static maps and dynamic entities (like NPCs or the player) using shapes like Axis-Aligned Bounding Boxes (AABBs). The code determines the Minimum Translation Vector (MTV) to resolve overlaps—the precise distance needed to push a character back out of a wall—leading to smooth, reliable interaction.

fight


3. Data-Driven Combat and UI Polish

The core RPG mechanics and UI systems were designed to be flexible and maintainable, separating game balance from the compiled C code.

Flexible Game Systems

  • Externalized Game Logic (XML Parser): The xml_parser module was a non-negotiable component. We used XML to store mutable, non-code data like item stats, enemy characteristics, and quest triggers. This allowed us to balance the game (e.g., adjusting a boss’s HP or a sword’s damage multiplier) without ever recompiling the core executable.
  • The Damage Formula: The combat system involves calculating damage based on the player’s characteristics (Strength, Defense, etc.). The C code implements a simple but robust formula, often involving random factors, that ensures character growth translates directly into meaningful combat effectiveness.
  • Multi-State Button Logic: As a UI requirement, all menu buttons must have at least three states (IDLE, HOVERED, CLICKED). Each button object holds a state variable and three distinct textures. The menu system constantly checks mouse position and click events to drive these transitions, giving the UI a polished, professional feel.

Conclusion: The Value of Low-Level Work

I learned more about software development from this project than from any theory course. Building an engine from C—where you control memory, time, and every pixel transformation—reveals the true architecture of modern applications.

While I’ve since moved on to other projects, the principles of modularity, data-driven design, and meticulous resource management remain core to my approach.


Code Repository

The full C/CSFML code is available on GitHub:

TekPlace

death screen