Cub3d
Présentation
cub3D est un projet 42 qui consiste à recréer un rendu 3D “à l’ancienne” à partir d’une carte 2D, en implémentant un pipeline complet : parsing de fichier .cub, validation de map, gestion du joueur, DDA / raycasting, textures, interface, et boucle de jeu.
Ce dépôt va plus loin qu’un rendu minimal : le moteur intègre des éléments de gameplay (portes, sprites, ennemis) et des fonctionnalités techniques orientées performance/qualité (multi‑threading optionnel, post‑process vignette/blur, anti‑aliasing configurable, audio via OpenAL Soft).
Stack technique
- Langage : C
- Graphique : MiniLibX (backend macOS OpenGL / Linux X11)
- Audio : OpenAL Soft + chargement WAV via un wrapper interne autour de
dr_wav - Build :
make(Linux/macOS)
Fonctionnalités principales
- Raycasting DDA : rendu 3D temps réel depuis une grille 2D
- Textures : murs (NO/SO/WE/EA), sol/plafond (couleur ou texture), portes/sprites/ennemis via identifiants
- Contrôles joueur : déplacement (WASD / flèches) + actions (interaction porte)
- Minimap (toggle)
- Post‑process vignette/blur : réglage en runtime (radius/gradient), optimisé (cache + dirty flag)
- Anti‑aliasing : activation + réglages (intensity)
- Mirrors : surfaces miroir (réflexions limitées (configurable))
- Audio : musique/ambiance + SFX (structure de dossier attendue configurable via la map)
- Menus / state machine : séparation des états (menu, options, jeu)
Format de map (aperçu)
Le moteur charge un fichier .cub qui contient :
- Des lignes de configuration (textures/couleurs, assets optionnels)
- Puis la grille (map) composée de caractères (murs, sol, spawn, portes, etc.)
Exemples d’identifiants de config présents dans le projet :
- Murs :
NO,SO,WE,EA→ chemins.xpm - Sol / plafond :
FetC→R,G,Bou chemin de texture (./...) - Porte :
D→ texture de porte - Ennemi :
X→ texture d’ennemi - Sprites :
2..9→ textures associées à un id - Audio :
A→ chemin vers un dossier de sons
Objectif
Le projet met en avant des compétences “systèmes” et “moteur” : parsing robuste, validation, gestion mémoire, performance (optimisations ciblées), architecture modulaire, et intégration multi‑plateforme.
Compilation
make
Binaire généré : ./cub3D
Lancement
./cub3D maps/good/subject_map.cub
Contrôles (clavier)
- Quitter :
ESC - Déplacement :
W A S D(ou flèches↑ ↓ ← →) - Interaction porte :
E - Sprint / action (selon config) :
SHIFT
Toggles & réglages runtime
- Afficher/masquer minimap :
M - Ouvrir/fermer le menu TAB (overlay options) :
TAB - Multi‑threading (rendu) :
H(toggle) - Anti‑aliasing :
- Activer/désactiver :
K - Intensité :
L - Vignette/blur (post-process) :
- Gradient :
7(−) /8(+) - Rayon :
9(−) /0(+)
Audio (runtime)
- Play/Pause (source principale) :
P - Enable global audio :
O
Format .cub (structure)
Un fichier .cub est composé de :
1) Bloc configuration (textures / couleurs / assets)
2) Grille (la map), ligne par ligne
Identifiants de configuration supportés
- Textures de murs :
NO <path>(North),SO <path>(South),WE <path>(West),EA <path>(East)-
Extension attendue :
.xpm -
Sol / plafond :
F <R,G,B>ouF <./path_to_texture.xpm>-
C <R,G,B>ouC <./path_to_texture.xpm> -
Porte :
D <./path_to_door_texture.xpm> -
Ennemi (texture) :
X <./path_to_enemy_texture.xpm> -
Sprites (textures par id) :
-
2 <./path.xpm>…9 <./path.xpm> -
Audio (optionnel) :
A <./path_to_sound_folder>
Caractères de la grille (map)
1: mur0: sol / case videN,S,E,W: position + orientation de spawn du joueurD: porteM: miroir2..9: sprite (id)X: ennemi (spawn)(espace) : padding/void (utilisé dans certaines maps)
Vue d’ensemble
Le projet est organisé en modules clairs :
src/01_parser/: chargement.cub, validation, construction de la grille, init joueursrc/02_state_machine/: gestion des écrans/états (menu, options, jeu)src/03_game_engine/: moteur (raycasting, rendu, minimap, post-process, miroir, audio “in-game”)src/00_init/: bootstrap (init data, init mlx, events, textures, audio, cleanup)includes/: headers, types, keycodes, configlibs/:libft, dépendances audio, helpers mouvement, etc.
Pipeline “chargement → jeu”
- Init : allocations + init MLX + init systèmes (textures/audio) + hooks clavier/souris
- Parsing :
- lecture du fichier.cub
- parsing des identifiants (textures/couleurs/portes/sprites/ennemi, audio)
- parsing de la grille et validation (cohérence + fermeture de la map, flood fill) - Initialisation gameplay :
- spawn joueur (position/orientation)
- instanciation objets (portes, sprites, ennemis) - Boucle de rendu :
- calcul caméra + inputs
- raycasting (DDA) → distances, faces, sampling textures
- rendu sol/plafond, objets, overlays (minimap, menu TAB)
- post-process (vignette/blur) + AA (si activés)
Systèmes notables
- Raycasting DDA : cœur du rendu, avec option de rendu multi-thread (toggle)
- Miroir : réflexion de rayons avec limite de rebonds (
MAX_REFLECTIONS) - Vignette/blur : cache + dirty flag + optimisations (lookup, merge par blocs)
- Audio : abstraction
t_audio_system(OpenAL device/context, buffers, sources)
1) Compiler et lancer une map existante
make
./cub3D maps/good/dungeon.cub
Si vous voulez une map “baseline” simple :
./cub3D maps/good/subject_map.cub
2) Créer une map minimale .cub
Créez par exemple maps/my_map.cub :
NO ./textures/test/north.xpm
SO ./textures/test/south.xpm
WE ./textures/test/west.xpm
EA ./textures/test/east.xpm
F 220,100,0
C 225,30,0
111111
100001
10N001
100001
111111
Règles de base :
- exactement un spawn joueur (
N/S/E/W) - la map doit être fermée (pas de “trou” vers l’extérieur)
- murs obligatoires :
NO/SO/WE/EA - sol/plafond : couleur ou texture (au moins une définition valide pour
FetC)
3) Ajouter portes / sprites / miroir
Dans le bloc config :
D ./assets/castle/wooddoor.xpm
2 ./assets/castle/firecamp.xpm
X ./assets/castle/enemy.xpm
Dans la grille :
- placez
Dpour une porte (ouvrable avecE) - placez
2..9pour un sprite - placez
Mpour des surfaces miroir - placez
Xpour un ennemi
4) Activer l’audio via la map
Ajoutez une ligne A dans le bloc config :
A ./assets/sounds/test
Le dossier doit respecter une arborescence attendue (porte, mob, player + WAV). Si elle n’est pas respectée, le jeu bascule en mode “sans son”.
5) Arborescence audio obligatoire (tree)
Le projet attend une structure de dossier précise pour charger automatiquement les WAV (SFX + musiques). Exemple (identique à celle attendue par le parser) :
.
├── door
│ ├── Close_door.wav
│ └── Open_door.wav
├── Env.wav
├── Game_over.wav
├── Menu_effect.wav
├── Menu_exit.wav
├── Menu_option.wav
├── Menu_start_game.wav
├── Menu.wav
├── mob
│ ├── Mob_footsteps.wav
│ └── Mob_voice.wav
└── player
├── Breating_fast.wav
├── Breating_medium.wav
├── Breating_slow.wav
├── footsteps
│ ├── Player_footsteps_1.wav
│ ├── Player_footsteps_2.wav
│ ├── Player_footsteps_3.wav
│ ├── Player_footsteps_4.wav
│ ├── Player_footsteps_5.wav
│ ├── Player_footsteps_6.wav
│ ├── Player_footsteps_7.wav
│ └── Player_footsteps_8.wav
├── Heart.wav
└── Wall_collision.wav
Pourquoi cette structure est imposée ?
- Simplicité de parsing : au lieu de parcourir récursivement un dossier, de gérer des variantes de noms, ou de maintenir une table de correspondance, le loader sait exactement quels fichiers ouvrir.
- Moins de cas d’erreur : pas d’ambiguïté (ex: deux fichiers candidats pour le même son), et des messages d’erreur plus clairs si un fichier manque.
- Code plus léger et robuste : logique déterministe, sans dépendre d’un “scan filesystem” complexe (utile dans un projet C avec contraintes de temps/architecture).
Pourquoi un config.h ?
Le fichier includes/config.h centralise des paramètres compile-time (macros) pour éviter des “magic numbers” dispersés : résolution, vitesses, options de rendu, minimap, portes, miroirs, et une partie de la configuration audio.
L’avantage : on peut ajuster rapidement le comportement du moteur sans toucher aux fichiers du game loop.
Comment modifier la config (2 méthodes)
Méthode A — modifier directement includes/config.h
Simple pour un usage local.
Méthode B — surcharger au moment de la compilation (recommandé)
Beaucoup de macros sont protégées par #ifndef ... #define ... #endif, donc vous pouvez les override via des flags -D.
Exemples :
make fclean
make CFLAGS="-DWIN_WIDTH=1920 -DWIN_HEIGHT=1080 -DRENDER_THREADS=8 -DMOUSE_SENSITIVITY=0.03"
Réglages utiles (extraits)
Fenêtre & rendu
WIN_WIDTH,WIN_HEIGHT: résolution (par défaut 1280×720)RENDER_THREADS: nombre de threads pour le rendu (par défaut 8)FPS_MAX: cap FPS (défini à 20)
Déplacements & caméra
MOVE_SPEED: vitesse de déplacementROT_SPEED: vitesse de rotationSPRINT_FACTOR: multiplicateur sprintMOUSE_SENSITIVITY: sensibilité sourisTILE_SIZE: taille logique d’une case
Miroirs
MAX_REFLECTIONS: limite de rebonds (attention : valeur élevée = coût CPU)MIRROR_EPSILON: epsilon anti “self-hit” lors de la réflexion
Portes
MAX_DOORS: max portesDOOR_ANIM_STEP,DOOR_OPEN_SPEED: paramètres d’animationDOOR_OPEN_TIME,DOOR_CLOSE_DELAY: timingsDEFAULT_DOOR_TYPE: type par défaut
Minimap
Macros de taille/couleurs : MINIMAP_SCALE, MINIMAP_SIZE, MINIMAP_RADIUS, etc.
Anti-aliasing
AA_INTENSITY_DEFAULTAA_MERGE_MAX
Audio (volumes + limites)
- Limites :
MAX_AUDIO_SOURCES,MAX_AUDIO_BUFFER - Volumes (exemples) :
VOLUME_MENU,VOLUME_GAME_AMBIENT,VOLUME_OPENING_DOOR,VOLUME_MOB_CRY, etc. SLEEP_EXIT: durée (microsecondes) liée au son de sortie
Activer / régler les logs debug
Le fichier includes/debug.h expose des flags compile-time :
DEBUG_MODE: active le mode debug globalDEBUG_PARSER,DEBUG_POS,DEBUG_KEY,DEBUG_AA: logs ciblés
Exemple :
make fclean
make CFLAGS="-DDEBUG_MODE=1 -DDEBUG_PARSER=1 -DDEBUG_KEY=1"