Skip to main content

System Architecture

Cub3D is a Wolf3D-style raycasting game engine built in C with SDL2. The architecture follows a modular design with clear separation of concerns across rendering, entity management, input handling, and game logic.

High-Level Architecture

┌─────────────────────────────────────────────────────────┐
│                     Main Loop (loop.c)                   │
│  - Event Processing (key_hook, mouse_hook)              │
│  - Frame Updates (call_entity_frames)                   │
│  - Rendering Pipeline (render_players_game)             │
└─────────────────────────────────────────────────────────┘

        ┌───────────────────┴───────────────────┐
        │                                       │
┌───────▼────────┐                     ┌───────▼────────┐
│   Game State   │                     │  Window/MLX    │
│   (t_game)     │◄────────────────────┤  (t_ftm_window)│
└───────┬────────┘                     └────────────────┘

        ├─────► Entities System (t_list *entities)
        ├─────► Map System (t_map)
        ├─────► Render System (HUD, Camera, Sprites)
        ├─────► Audio System (t_hashmap *sounds)
        └─────► Threading (camera_threads[4])

Module Structure

Core Modules

Location: src/ft_utils/Provides fundamental data structures and utilities:
  • Hashmap: Key-value storage for sprites, fonts, sounds
  • Linked Lists: Dynamic entity management
  • Time Utilities: Delta time, FPS tracking
  • Math Utilities: Vector operations, angle calculations
  • String Operations: Parsing, manipulation
Key types:
typedef struct s_coords {
    double x;
    double y;
    double yaw;  // Rotation angle
} t_coords;

typedef struct s_hashmap {
    t_element *table;
} t_hashmap;

typedef struct s_list {
    void *data;
    struct s_list *next;
} t_list;
Location: src/ft_mlx_utils/SDL2 wrapper providing:
  • Window Management: Creation, event handling, rendering
  • Image Operations: Loading, manipulation, pixel operations
  • Text Rendering: Bitmap font support
  • Input Controllers: Keyboard, mouse, gamepad
Subdirectories:
  • window/: Window lifecycle management
  • image/: Image loading and manipulation
  • text/: Font rendering (IBM VGA 8x16)
  • controllers/: Input handling
Location: src/ft_audio/Audio playback using miniaudio library:
  • Sound effect management
  • Background music
  • 3D positional audio support
  • Audio resource loading/cleanup
Location: src/ft_threads/Pthread wrapper for parallel processing:
typedef struct s_ftt_thread {
    pthread_t thread;
    bool running;
    bool active;
    void (*routine)(void *);
    void *data;
} t_ftt_thread;
Used primarily for parallel raycasting across CPU cores.
Location: src/utils/entities/Entity Component System managing all game objects:
  • entity/: Base entity implementation
  • billboard/: Sprite-based entities
  • character/: Living entities with health/inventory
  • player/: Player-controlled characters
  • wall/: Static wall entities
  • door/: Interactive door entities
  • elevator/: Map transition entities
  • drop/: Item drops in the world
  • controller/: AI and player controllers
Location: src/utils/items/Item and inventory management:
  • item/: Base item implementation
  • weapon/: Weapons with damage/range
  • collectible/: Health/ammo/score pickups
Location: src/utils/render/Raycasting and rendering pipeline:
  • camera/: 3D raycasting engine
    • walls/: Wall rendering
    • billboards/: Sprite rendering
  • hud/: Heads-up display
    • minimap/: 2D map overlay
    • stats/: Health/ammo/score display
    • debug/: Debug information overlay
Location: src/utils/map/Map parsing and representation:
  • .cub file parser
  • Entity type mapping
  • Map validation
  • Dynamic map loading
Location: src/utils/loop/Main game loop coordination:
  • Event processing
  • Frame timing
  • Entity updates
  • Rendering orchestration
Location: src/utils/sprites/Sprite and animation management:
  • Sprite loading/caching
  • Animation state machine
  • Directional sprites (8-way)

Threading Model

Parallel Raycasting

Cub3D uses 4 parallel threads for raycasting to maximize performance:
// headers/cub3d.h:96
#define CAMERA_THREADS 4

// Game structure contains thread pool
struct s_game {
    // ...
    t_ftt_thread *camera_threads[CAMERA_THREADS];
};

Thread Distribution

Each thread renders a vertical slice of the screen:
typedef struct s_raycasting_slice {
    t_ftm_image *canvas;      // Target render surface
    t_player *player;          // Player viewport
    int starting_index;        // First column to render
    int ending_index;          // Last column to render
} t_raycasting_slice;
Example: For a 1024px wide screen with 4 threads:
  • Thread 0: columns 0-255
  • Thread 1: columns 256-511
  • Thread 2: columns 512-767
  • Thread 3: columns 768-1023

Synchronization

The main game state is protected by a mutex:
struct s_cub3d {
    pthread_mutex_t game_mutex;  // Protects game state
    t_game *game;                // Shared game state
    // ...
};
Thread safety is critical when accessing shared game state. Always acquire the game_mutex before modifying entities, maps, or other shared resources.

Data Flow

Frame Update Cycle

Entity Update Flow

void call_entity_frames(t_game *game, t_fps *fps)
{
    t_list *current = game->entities;
    
    while (current) {
        t_entity *entity = (t_entity *)current->data;
        
        if (entity->active && entity->frame) {
            // Call entity-specific frame update
            entity->frame(game, entity, fps->delta_time);
        }
        
        current = current->next;
    }
}
Each entity type has its own frame() implementation:
  • Player: Process input, move, update camera
  • Character: AI decision making, weapon usage
  • Door: Animation state, auto-close timer
  • Billboard: Sprite animation updates
  • Drop: Item pickup detection

Rendering Pipeline

1

Clear Canvas

Fill background with floor/ceiling colors from environment.

Raycast Walls

For each screen column (parallelized across 4 threads):
  1. Cast ray from player position
  2. Find wall intersection
  3. Calculate wall height on screen
  4. Sample texture and draw vertical strip

Render Billboards

  1. Sort billboards by distance (painter’s algorithm)
  2. For each billboard:
    • Project 3D position to screen space
    • Draw sprite with depth-based scaling
    • Apply transparency

Render HUD

Draw UI elements on top of 3D view:
  • Stats (health, ammo, score)
  • Minimap
  • Debug info (FPS, position)
  • Action prompts

Present Frame

Flip buffers and display completed frame to screen.

Memory Management

Resource Lifecycle

// Entity creation pattern
t_player *player_new(t_game *game, t_ftm_window *window, char identifier)
{
    t_player *player = malloc(sizeof(t_player));
    if (!player)
        return (NULL);
    
    init_player(game, window, player, identifier);
    return (player);
}

Hashmap Usage

Hashmaps provide O(1) resource lookup:
game->sprites
t_hashmap*
2D sprite cache (icons, UI elements)
game->sprites_3d
t_hashmap*
3D directional sprites (8-way character sprites)
game->sounds
t_hashmap*
Audio clip cache
game->fonts
t_hashmap*
Loaded font resources
map->identifiers
t_hashmap*
Entity type constructors keyed by map character

Performance Characteristics

FPS Management

struct s_fps {
    t_time beginning;           // Game start time
    t_time fps_update_time;     // Last FPS calculation
    t_time last_frame_time;     // Previous frame timestamp
    double delta_time;          // Seconds since last frame
    int fps_limit;              // Target FPS (1000 default)
    int frame_count;            // Frames this second
    int fps;                    // Current FPS
    int max;                    // Peak FPS
    int min;                    // Lowest FPS
};

Frame Time

Delta time starts at 0.016s (62.5 FPS) and dynamically adjusts based on actual frame timing for consistent physics.

Raycasting Optimization

PLAYER_RAY_SUBRAYS
int
default:"5"
Number of sub-rays cast per screen column for anti-aliasing and hit detection accuracy.
PLAYER_RAY_HIT_ENTITIES_NUMBER
int
default:"5"
Maximum entities tracked per ray for shooting/interaction.
PLAYER_RAYS_NO_HIT_LENGTH
double
default:"50.0"
Maximum ray distance when no wall is hit (prevents infinite rays).

See Also

Build docs developers (and LLMs) love