Skip to content

gabcollet/cub3d

Repository files navigation

cub3d

Table of Contents

Presentation
How to run it
Commands
Development process
Resources

Presentation

The goal of this project was to create a basic first-person maze like the old Wolfenstein 3D, using raycasting.

Features

Mandatory part:

  • A custom map can be create using a .cub file including :
    • Different wall textures that vary depending on which side the wall is facing (North, South, East, West).
    • Different floor and ceiling colors using RGB.
    • Doors and enemies position (X, Y).
    • The map file itself. (1 = wall, 0 = floor).
    • A player facing a direction (N, S, E, W)
  • A 3D rendering of a map file.

Bonus part:

  • Wall collisions.
  • A minimap system.
  • Doors which can open and close.
  • Animated sprite (gun and enemies).
  • Rotate the point of view with the mouse.
  • Custom transparency.

How to run it

First clone the git repo:

git clone [email protected]:gabcollet/cub3d.git; cd cub3D;

Then make and launch using a map file in "./maps/.cub"
Mac mandatory :

make; ./cub3D maps/m_complex.cub

Mac bonus :

make bonus; ./cub3D maps/b_complex.cub

Linux mandatory : (Dont forget to change keys in the include file)

make linux; ./cub3D maps/m_complex.cub

Linux bonus :

make b_linux; ./cub3D maps/b_complex.cub

Commands

Key must be change between mac or linux in includes/cub3d.h or includes/cub3d_bonus.h

Key Command
<-- or --> Look left and right
W, A, S, D Move
ESC Quit
E Open doors
Space bar Shoot
Shift Jump
M Toggle map

Development process

  • To begin we created the MLX windows.
  • Added movement using key pressed and released.
  • Added collision between the player and walls.
  • Raycasting :
    • First we've checked every intersection of the grid to see if the collision was with a wall.
    • Then we calculate for that distance.

Screenshot-from-2022-02-13-15-06-42 Screenshot-from-2022-02-13-15-07-12 Screenshot-from-2022-02-13-15-09-43
It gave us a function like that where pos is the player position, rot is the angle of the specific ray, coll is the collision point with the wall and angle is the rotation of the player minus the current ray rotation.

double	get_draw_distance(t_pos pos, double rot, t_pos coll, double angle)
{
	double	d_x;
	double	d_y;
	double	sin_result;
	double	cos_result;
	double	dist;

	d_x = (int)fabs(pos.x - coll.x);
	d_y = (int)fabs(pos.y - coll.y);
	cos_result = fabs(cos(deg_to_rad((int)rot)));
	sin_result = fabs(sin(deg_to_rad((int)rot)));
	dist = d_x * cos_result + d_y * sin_result;
	dist = dist * cos((deg_to_rad((int)angle)));
	dist = (TILE_SIZE * g_game.res_h) / dist;
	return (dist);
}

1

  • Using the previously found distance we build the 3D rendering of the wall. Here's a part of the final function for a north wall. We can see that the function call for another fill_with_texture function that calculate the step in between each pixel that needed to be put.
int	draw3d(float height, t_coll coll, int x)
{
   int		y;
   float	offset;

   offset = 0;
   if (height > WIN_H)
   {
   	offset = (height - WIN_H);
   	height = WIN_H;
   }
   y = (WIN_H - height) / 2;
   if (coll.dir & NORTH)
   	fill_with_texture(&g_game.texture[NO], new_pos(x, y, 0),
   		height, textures_index(coll.pos, offset, height, 1));
   ...
  • Added shadow

3

  • Correct fish-eye effect
  • Correct jerky walls caused by conversion float to int

5589dafaba77a99b0.gif

  • Added texture on wall just to see how it fit

6

  • Added real texture without offset so it only work when you see the complete wall. The wall didn't look good up close

7

  • Correct the offset so you can now zoom in on the wall and it still look good. To do so we used the fill_with_texture function that calculate an appropriate step between the wall height and the texture image.
void	fill_with_texture(t_img *text, t_pos pos, float height, t_pos index)
{
	t_img	*img;
	double	y_step;
	int		bytes;
	int		color;

	img = &g_game.game_img;
	y_step = ((float)text->height - (index.y * 2))
		/ (height + (img->height - height) / TILE_SIZE);
	bytes = (text->bpp / 8);
	color = 0;
	while (pos.y < height + (img->height - height) / 2)
	{
		color = color_get(*text, (int)index.x, (int)index.y);
		color = color_shift_int(color, BLACK, ((WIN_H - height) / WIN_H) / 2);
		if (pos.x >= 0 && pos.x < img->width)
			my_mlx_pixel_put(*img, pos.x, pos.y + g_game.player.pos.z, color);
		index.y += y_step;
		pos.y++;
	}
}
  • Added a gun sprite that animate when key is pressed.
  • At this stage we also added the parsing part where the program read a .cub file and determined if all requirement are met to load it properly.

9c46c8d48067558f3.gif

  • Added a minimap in the top corner.
  • Since using the mlx transparency was'nt working very well, we create a function for custom transparency that shifted the present color using the pixel right under it.
int	color_shift_int(int base, int shift, double force)
{
   t_rgb	rgb;
   t_rgb	base_rgb;
   t_rgb	shift_rgb;

   if (base == TRANS)
   	return (base);
   base_rgb = color_int_to_rgb(base);
   shift_rgb = color_int_to_rgb(shift);
   rgb = color_shift_rgb(base_rgb, shift_rgb, force);
   return (color_rgb_to_int(rgb));
}
  • Added an animated enemy sprite that can be position in the .cub file.
  • Added doors that position themselves like the enemies but use a new character in the .cub map for their positions. They also can be interact with using a key pressed and the distance between the player and the door.
  • Added a script that calculate which sprite is the closest and draw them in last so they are not superposed.
  • Finally we added the mouse movement using mlx events.

11e9a6cc7adb451779.gif

Thanks for reading!

Resources

About

RayCaster inspiré du jeu Wolfeinstein3D

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published