Skip to content

yuchi1025/cub3d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This project has been created as part of the 42 curriculum by yucchen, sileow.

cub3D 🧱

Description

cub3D renders a 3D-like view using raycasting from a 2D map.

cub3D is a graphic design project inspired by the world-famous Wolfenstein 3D game, which is considered the first true First Person Shooter (FPS) ever created.

The goal of this project is to create a "realistic" 3D graphical representation of the inside of a maze from a first-person perspective using the Raycasting principles.

Built with C and the miniLibX graphical library, this project serves as a deep dive into practical applications of mathematics, window management, and event handling.

Program Aspects:

  1. Parsing: Parse and validate the .cub file (textures, colors, map closure, single player).
    • .cub format:
      • NO SO WE EA textures
      • F C colors
      • Closed map with one player (N/S/W/E)
      Example .cub file:
      NO ./textures/north.xpm
      SO ./textures/south.xpm
      WE ./textures/west.xpm
      EA ./textures/east.xpm
      
      F 180,190,200
      C 90,95,105
      
      111111 
      100101
      101001
      1100N1
      111111
      
  2. Initialization: Set up the player's position, direction vectors, and the camera plane.
    • The camera plane is always perpendicular (90 degrees) to the direction vector:
      • Two vectors are perpendicular if their dot product is 0.
      • Camera plane's length (0.66) controls the field of view (around 66°):
        • 0.66 is not mathematically required.
        • It is just an optimal FOV constant that became the standard in Wolfenstein-style raycasters.
  3. MLX Setup: Initialize the MiniLibX window, image buffers, and key/render hooks.
    • mlx_loop_hook() registers a function that MLX will call repeatedly while the event loop is running
      • Difference from mlx_hook():
       mlx_hook      -> called only when an event happens
       (For key press/release, mouse, close)
      
       mlx_loop_hook -> called every frame
       (For movement + rendering every frame)
  4. Raycasting: Utilize the Digital Differential Analysis (DDA) to shoot rays, detect wall hits, and project distances to prevent fish-eye distortion.
  5. Rendering: Load .xpm images and map texture to walls (North/South/West/East)
    • [Bonus] Display a real-time minimap system to support player navigation.
    • [Bonus] Add animation to walls.
    • [Bonus] Show doors as open when player is near; closed when player is at least a set distance away.
  6. Interaction: Handle player movement (W, A, S, D), camera rotation(Left/Right)
    • To rotate a vector, multiply with the rotation matrix
    [ new_x ]   [ cos(a) -sin(a) ] [ x ]
    [ new_y ] = [ sin(a)  cos(a) ] [ y ]
    • [Bonus] Wall collisions detection to prevent player from 'entering' wall.
    • [Bonus] Rotate the point of view with the mouse.

Instructions

Compilation

To compile the mandatory part of the project, simply run:

make

To access the full game features including bonus features, run:

make bonus

Execution

Run the executable with a valid map file passed as an argument:

./cub3D maps/valid/small_N.cub

For bonus features, replace ./cub3D by ./cub3D_bonus.

Controls

Key Action
W Move Forward
S Move Backward
A Move Left
D Move Right
Rotate Camera Left
Rotate Camera Right
ESC Exit Game

Parser Design

The parser is implemented step by step. Each step validates its input before moving to the next step. If any step fails, the program safely frees allocated memory, prints a descriptive error, and exits.

Step 0 - Check Argument Count

  • Check argument count (argc == 2)

Step 1 - File Validation

  • Verify the .cub file extension
  • Ensure the file can be opened

Step 2 - Read File into Lines

  • Read the entire file using get_next_line
  • Strip trailing newline (\n)
  • Store into char **lines

Step 3 - Parse Configuration Lines, Locate Map Start & Parse Map Lines

  • Skip blank lines
  • Parse the 6 required identifiers in any order
    • Textures (NO, SO, WE, EA) and check the file paths
    • Colors (F, C) and ensure exactly 3 values in the range [0,255]
  • First line containing map tiles ( , 0, 1, N, S, W, E) marks map_start
  • No blank lines allowed inside the map
  • No configuration lines after the map starts
  • Only valid map characters are allowed

Step 4 - Check Configuration Identifiers Count

  • Each identifier must appear exactly once
    • Textures (NO, SO, WE, EA)
    • Colors (F, C)

Step 5 - Collect Map Lines

  • Extract map lines from map_start to EOF

Step 6 - Compute Map Dimensions

  • Compute max width among all map lines
  • Store the map width & height

Step 7 - Normalize Map

  • Allocate a rectangular map of size map_height x map_width
  • Pad shorter lines with spaces (' ')
  • Preserve original layout

Step 8 - Player Extraction

  • Locate exactly one player (N, S, W, E)
  • Store player position at tile center (+0.5) and direction
  • Replace player tile with '0'

Step 9 - Map Validation

  • Ensure the map is closed by walls
    • Border checks
      • If the top row contains any 0, N, S, W, E -> fail (Step 3)
      • If the bottom row contains any 0, N, S, W, E -> fail (Step 5)
      • If the first column contains any 0, N, S, W, E -> fail (Step 6)
      • If the last column contains any 0, N, S, W, E -> fail (Step 6)
    • Neighbor checks
      • For every '0', check its 4 neighbors != ' '
        • (x, y)
        • North: Up (x, y - 1)
        • South: Down (x, y + 1)
        • West: Left (x - 1, y)
        • East: Right (x + 1, y)

Resources

References

How AI was used

AI tools were used as a learning aid, for the following concepts:

  • The fundamental concept of DDA.
  • How simplifying delta_dist as the absolute reciprocal of ray direction allows us to directly obtain the perpendicular distance from DDA (instead of Euclidean distance).
  • Distinguishing between MLX functions mlx_hook and mlx_loop_hook.
  • Generate door textures and animated textures that are consistent with our wall textures (but not used eventually).
  • Debug memory leak issues.

Notes (Norm, Valgrind)

  • This project follows the 42 Norm rules.
  • Memory and file descriptor leaks are checked with Valgrind.
valgrind --leak-check=full --show-leak-kinds=all --track-fds=yes ./cub3D maps/valid/small_N.cub

About

A Wolfenstein 3D-inspired raycaster built in C with miniLibX. Features a custom map parser, DDA-based rendering, a real-time minimap, and mouse support.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors