A “realistic” 3D graphical representation of the inside of a maze from a first-person perspective using the Ray-Casting principles.
Built in miniLibX, inspired on Wolfenstein 3D which is the ancestor of games like Doom (Id Software, 1993), Doom II (Id Software, 1994), Duke Nukem 3D (3D Realm, 1996) and Quake (Id Software, 1996), that are additional eternal milestones in the world of video games.
Note
- Debian or Ubuntu base distro
- gcc
- make
- X11 include files (package xorg)
- XShm extension must be present (package libxext-dev)
- Utility functions from BSD systems - development files (package libbsd-dev)
Setup the miniLibX
Install required packages:
sudo apt-get install gcc make xorg libxext-dev libbsd-dev
After running make, the miniLibX will have generated some files that you must install:
- libmlx.a and/or libmlx_$(HOSTTYPE).a in
/usr/X11/lib
or/usr/local/lib
- mlx.h in
/usr/X11/include
or/usr/local/include
- man/man3/mlx*.1 in
/usr/X11/man/man3
or/usr/local/man/man3
Compile cub3D
Just runmake
and let the magic happen 🪄
make
There are 3 types of elements to be configured inside a configuration file:
Where the map element must always be the last element declared on the configuration file.
The wall textures and the floor and ceiling colors configuration:
- Can be set in any order.
- Can be separated by one or more empty lines.
- Can have it's second argument separated by one or more spaces.
Here's an example of a minimalist configuration file.
sample.cub
:
NO ./path_to_the_north_texture
SO ./path_to_the_south_texture
WE ./path_to_the_west_texture
EA ./path_to_the_east_texture
F 220,100,0
C 225,30,0
1111111111111111111111111
1000000000110000000000001
1011000001110000000000001
1001000000000000000000001
111111111011000001110000000000001
100000000011000001110111111111111
11110111111111011100000010001
11110111111111011101010010001
11000000110101011100000010001
10000000000000001100000010001
10000000000000001101010010001
11000001110101011111011110N0111
11110111 1110101 101111010001
11111111 1111111 111111111111
Wall textures 🧱
Wall textures vary depending on which side the wall is facing (North, South, East, West).
The texture elements must be declared in a specific order inside the configuration files.
<id> <./path_to_the_texture>
There are only 4 possible identifiers in the lexic of the texture elements:
ID | Description |
---|---|
NO | North texture. |
SO | South texture. |
WE | West texture. |
EA | East texture. |
Here is a valid example:
WE ./path_to_the_west_texture
Floor and ceiling colors 🎨
You can set the floor and ceiling colors inside the configuration file.
The texture elements must be declared in a specific order inside the configuration files.
<id> <[0,255],[0,255],[0,255]>
There are only 2 possible identifiers in the lexic of the floor and ceiling elements:
ID | Description |
---|---|
F | Floor. |
C | Ceiling. |
Here is a valid example:
C 225,30,0
Maps 🗺️
The program cub3D
needs a map (with the .cub
extension) as the first argument to generate the 3D world.
You can choose, create or modify an existent map.
There are only 6 possible characters in the lexic of the map:
Char | Description |
---|---|
0 | Empty space. |
1 | Wall. |
N | Player’s start position facing North. |
S | Player’s start position facing South. |
E | Player’s start position facing East. |
W | Player’s start position facing West. |
- The map must be closed/surrounded by walls, if not, the program returns an error.
- The map must be parsed as it looks in the file.
- Spaces are a valid part of the map. Here is a valid example of a simple map:
111111
100101
101001
1100N1
11111
⎋ Esc Close the window and quit the program cleanly. M Toggle mini map.
← Look left inside the maze.
→ Look right inside the maze.
W Move up the point of view through the maze.
A Move left the point of view through the maze.
S Move down the point of view through the maze.
D Move right the point of view through the maze.
Raycasting is a rendering technique used in computer graphics to simulate the path of light rays from a virtual camera into a scene.
![RUSS](https://private-user-images.githubusercontent.com/107457733/323214025-4e4bc2de-4323-4ec8-9b1d-1e59adc06870.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQxMjgzOTcsIm5iZiI6MTcyNDEyODA5NywicGF0aCI6Ii8xMDc0NTc3MzMvMzIzMjE0MDI1LTRlNGJjMmRlLTQzMjMtNGVjOC05YjFkLTFlNTlhZGMwNjg3MC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQwODIwJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MDgyMFQwNDI4MTdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT04ZGZiZDg4NTZiNTVlOTU5MzE2MWQ0ZTcyNzMwZDljNGEzMDNmNThkZmVhZDhlYTViMGFkNWI2ZGQ4ODYwZmEyJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.J1NTjJCU1tPuqNQ1AqNKZg8GALwVzSRv0UTmzuDFdnI)
The first step in Raycasting to cast one ray to determine the distance between the player and a wall.
We must have some information first:
// Ray starting position coordinates (player's position)
p->ray.xy[0] = p->mx;
p->ray.xy[1] = p->my;
// Unit vector of direction from the angle in radians.
p->ray.dir[0] = cos(angle);
p->ray.dir[1] = -sin(angle);
We also have to calculate the ray unit step size
on the player's direction's unit vector.
To know the lenght of each cell intersection happening on the X axis and on the Y axis, through the ray.
DeltaDist is our Ray Unit Step Size.
Note
This value is a percentage, taking a cell as a unit. It can be adapted as needed.
Let's say that the side AB = x
and AC = y
, then we have the hypotenuse step sizes as follow:
We can implement this functions in C like this:
// dir = {x, y} player direction's unit vector coordinates;
p->ray.russ[0] = sqrt(1 + pow(p->ray.dir[1], 2) / pow(p->ray.dir[0], 2));
p->ray.russ[1] = sqrt(1 + pow(p->ray.dir[0], 2) / pow(p->ray.dir[1], 2));