Wolf3d - Raycasting

A recreation of the raycasting technique that was found in the original Wolfenstein 3d game.

There is only one level, and the game runs entirely on stack memory.

This project uses my libft library and the MLX graphic library.

Tools/Libraries: Libft, MLX

Language: C

Runs on Mac


Compiling:

-> make

-> ./wolf3d (To get the controls.)

-> ./wolf3d start (to start the game)

Controls:

Move: Arrow Keys or WASD

To Quit: Esc Key or Exit Icon

Git Repo

main.c

#include "wolf3d.h" void map(t_gg *g) { g->worldmap[0] = "1111111111"; g->worldmap[1] = "1003000201"; g->worldmap[2] = "1003000201"; g->worldmap[3] = "1100000001"; g->worldmap[4] = "1000330001"; g->worldmap[5] = "1000033001"; g->worldmap[6] = "1004004001"; g->worldmap[7] = "1104444001"; g->worldmap[8] = "1000000001"; g->worldmap[9] = "1111111111"; } int close_win(t_gg *g) { mlx_destroy_window(g->mlx, g->win); exitit("Exiting"); return (0); } unsigned int colormagic(int i, double x, double y) { unsigned int color; double magic; double i2; t_gg g; magic = sqrt(x * x + y * y); i2 = i + 1 - (log(2) / magic) / log(2); g.chan[0] = (unsigned char)(sin(0.026 * i2 + 4) * 230 + 25); g.chan[1] = (unsigned char)(sin(0.023 * i2 + 2) * 230 + 25); g.chan[2] = (unsigned char)(sin(0.01 * i2 + 1) * 230 + 25); color = (g.chan[0] << 16) + (g.chan[1] << 8) + (g.chan[2] + 255); return (color); } void novatempus(t_gg *g, int x) { int initioy; int mori; int initio; mori = g->drawend; if (mori > HEIGHT) mori = HEIGHT - 1; initioy = g->drawstart; if (initioy < 0) initioy = 0; initio = -1; while (++initio < (HEIGHT / 2)) g->imgpoke[x + (initio * g->sl / 4)] = 0xC00000AA; while (++initioy < mori) g->imgpoke[x + (initioy * g->sl / 4)] = colormagic(g-> color, x, initioy); initio = mori - 1; while (++initio < (HEIGHT - 1)) g->imgpoke[x + (initio * g->sl / 4)] = 0xC00000AA; } int main(int argc, char **argv) { t_gg g; if (argc < 2) printcontrols(2); if (argc > 2) exitit("Error - Too Much Input"); if (argc == 2) { errorcheck(argv[1]); map(&g); makewindow(&g); } }

init.c

#include "wolf3d.h" void player(t_gg *g) { int num; num = 200; g->character = mlx_xpm_file_to_image(g->mlx, "./xpm/sword.xpm", &(g->char_w), &(g->char_h)); g->imgchar = (int*)mlx_get_data_addr(g->character, &(g->char_bpp), &(g->char_sl), &(g->char_end)); g->healthbar = mlx_xpm_file_to_image(g->mlx, "./xpm/healthbar.xpm", &(g->health_w), &(g->health_h)); g->imghealth = (int*)mlx_get_data_addr(g->healthbar, &(g->health_bpp), &(g->health_sl), &(g->health_end)); if (g->upkey == 1 || g->downkey == 1) { while (num < 250) num += 25; while (num > 250) num -= 25; } mlx_put_image_to_window(g->mlx, g->win, g->character, 200, num); mlx_put_image_to_window(g->mlx, g->win, g->healthbar, 0, 525); } void colorpick(t_gg *g) { char initio; initio = g->worldmap[g->mapx][g->mapy]; if (initio == '1') g->color = 0x00FFFF; else if (initio == '2') g->color = 0x0000FF; else if (initio == '3') g->color = 0x9400D3; else if (initio == '4') g->color = 0xFF8C00; else if (initio == '0') g->color = 0x008080; } void initiodraw(t_gg *g) { g->posx = 6; g->posy = 8; g->dirx = -1; g->diry = 0; g->planex = 0; g->planey = 0.66; g->time = 0; g->oldtime = 0; g->w = WIDTH; g->h = HEIGHT; g->upkey = 0; g->downkey = 0; g->leftkey = 0; g->rightkey = 0; g->rotspeed = .2; g->movespeed = .2; } void printcontrols(int i) { ft_putendl("Controls:\nArrow Keys & WASD to Move"); ft_putendl("Esc Key to Exit\nType start to begin the game"); if (i == 2) exitit("Exiting"); } void errorcheck(char *str) { if (ft_strcmp(str, "start") == 0) ft_putendl("Starting"); else exitit("Exiting"); }

move.c

#include "wolf3d.h" void upmove(t_gg *g) { int x; int y; x = (int)(g->posx + g->dirx * g->movespeed); y = (int)(g->posy + g->diry * g->movespeed); if (g->upkey == 1 && g->downkey == 0) { if (g->worldmap[x][y] == '0') { ft_putendl("up"); g->posx += g->dirx * g->movespeed; g->posy += g->diry * g->movespeed; redraw(g); } } } void downmove(t_gg *g) { int x; int y; x = (int)(g->posx - g->dirx * g->movespeed); y = (int)(g->posy - g->diry * g->movespeed); if (g->downkey == 1 & g->upkey == 0) { if (g->worldmap[x][y] == '0') { ft_putendl("down"); g->posx -= g->dirx * g->movespeed; g->posy -= g->diry * g->movespeed; redraw(g); } } } void rightmove(t_gg *g) { if (g->rightkey == 1 && g->leftkey == 0) { ft_putendl("right"); g->olddirx = g->dirx; g->dirx = g->dirx * cos(-g->rotspeed) - g->diry * sin(-g->rotspeed); g->diry = g->olddirx * sin(-g->rotspeed) + g->diry * cos(-g->rotspeed); g->oldplanex = g->planex; g->planex = g->planex * cos(-g->rotspeed) - g->planey * sin(-g->rotspeed); g->planey = g->oldplanex * sin(-g->rotspeed) + g->planey * cos(-g->rotspeed); redraw(g); } } void leftmove(t_gg *g) { if (g->leftkey == 1 && g->rightkey == 0) { ft_putendl("left"); g->olddirx = g->dirx; g->dirx = g->dirx * cos(g->rotspeed) - g->diry * sin(g->rotspeed); g->diry = g->olddirx * sin(g->rotspeed) + g->diry * cos(g->rotspeed); g->oldplanex = g->planex; g->planex = g->planex * cos(g->rotspeed) - g->planey * sin(g->rotspeed); g->planey = g->oldplanex * sin(g->rotspeed) + g->planey * cos(g->rotspeed); redraw(g); } } int keyhooks(int key, t_gg *g) { (void)(g); if (key == 53) exitit("Exiting"); else if (g->upkey == 1) upmove(g); else if (g->downkey == 1) downmove(g); else if (g->leftkey == 1) leftmove(g); else if (g->rightkey == 1) rightmove(g); return (0); }

draw.c

#include "wolf3d.h" void drawstuff1(t_gg *g) { g->camerax = 2 * g->x / (double)g->w - 1; g->rayposx = g->posx; g->rayposy = g->posy; g->raydirx = g->dirx + g->planex * g->camerax; g->raydiry = g->diry + g->planey * g->camerax; g->mapx = (int)g->rayposx; g->mapy = (int)g->rayposy; g->deltadistx = sqrt(1 + (g->raydiry * g->raydiry) / (g->raydirx * g->raydirx)); g->deltadisty = sqrt(1 + (g->raydirx * g->raydirx) / (g->raydiry * g->raydiry)); g->hit = 0; } void drawstuff2(t_gg *g) { if (g->raydirx < 0) { g->stepx = -1; g->sidedistx = (g->rayposx - g->mapx) * g->deltadistx; } else { g->stepx = 1; g->sidedistx = (g->mapx + 1.0 - g->rayposx) * g->deltadistx; } if (g->raydiry < 0) { g->stepy = -1; g->sidedisty = (g->rayposy - g->mapy) * g->deltadisty; } else { g->stepy = 1; g->sidedisty = (g->mapy + 1.0 - g->rayposy) * g->deltadisty; } } void drawstuff3(t_gg *g) { while (g->hit == 0) { if (g->sidedistx < g->sidedisty) { g->sidedistx += g->deltadistx; g->mapx += g->stepx; g->side = 0; } else { g->sidedisty += g->deltadisty; g->mapy += g->stepy; g->side = 1; } if (g->worldmap[g->mapx][g->mapy] != '0') g->hit = 1; } if (g->side == 0) g->perpwalldist = (g->mapx - g->rayposx + (1 - g->stepx) / 2) / g->raydirx; else g->perpwalldist = (g->mapy - g->rayposy + (1 - g->stepy) / 2) / g->raydiry; g->lineheight = (int)(g->h / g->perpwalldist); g->drawstart = -(g->lineheight) / 2 + g->h / 2; } void drawstuff4(t_gg *g) { g->drawstart = -(g->lineheight) / 2 + g->h / 2; if (g->drawstart < 0) g->drawstart = 0; g->drawend = g->lineheight / 2 + g->h / 2; if (g->drawend >= g->h) g->drawend = g->h - 1; colorpick(g); if (g->side == 1) g->color = g->color / 2; novatempus(g, g->x); } void drawstuff(t_gg *g) { g->x = -1; while (++g->x < g->w) { drawstuff1(g); drawstuff2(g); drawstuff3(g); drawstuff4(g); } }

redraw.c

#include "wolf3d.h" void exitit(char *str) { ft_putendl(str); exit(0); } void redraw(t_gg *g) { mlx_destroy_image(g->mlx, g->img); g->img = mlx_new_image(g->mlx, WIDTH, HEIGHT); g->skybox = mlx_xpm_file_to_image(g->mlx, "./xpm/skybox.xpm", &(g->sky_w), &(g->sky_h)); g->imgsky = (int*)mlx_get_data_addr(g->skybox, &(g->sky_bpp), &(g->sky_sl), &(g->sky_end)); g->deck = mlx_xpm_file_to_image(g->mlx, "./xpm/floor.xpm", &(g->deck_w), &(g->deck_h)); g->imgdeck = (int*)mlx_get_data_addr(g->deck, &(g->deck_bpp), &(g->deck_sl), &(g->deck_end)); g->imgpoke = (int*)mlx_get_data_addr(g->img, &(g->bpp), &(g->sl), &(g->end)); drawstuff(g); mlx_put_image_to_window(g->mlx, g->win, g->skybox, 0, 0); mlx_put_image_to_window(g->mlx, g->win, g->deck, 0, 300); mlx_put_image_to_window(g->mlx, g->win, g->img, 0, 0); player(g); } int vaultmovement(int key, t_gg *g) { if (key == 126 || key == 13) g->upkey = 1; else if (key == 125 || key == 1) g->downkey = 1; else if (key == 123 || key == 0) g->leftkey = 1; else if (key == 124 || key == 2) g->rightkey = 1; keyhooks(key, g); return (0); } int vaultmovementtoggle(int key, t_gg *g) { if (key == 126 || key == 13) g->upkey = 0; else if (key == 125 || key == 1) g->downkey = 0; else if (key == 123 || key == 0) g->leftkey = 0; else if (key == 124 || key == 2) g->rightkey = 0; keyhooks(key, g); return (0); } void makewindow(t_gg *g) { g->mlx = mlx_init(); g->img = mlx_new_image(g->mlx, WIDTH, HEIGHT); g->win = mlx_new_window(g->mlx, WIDTH, HEIGHT, "Wolf3D"); g->skybox = mlx_xpm_file_to_image(g->mlx, "./xpm/skybox.xpm", &(g->sky_w), &(g->sky_h)); g->imgsky = (int*)mlx_get_data_addr(g->skybox, &(g->sky_bpp), &(g->sky_sl), &(g->sky_end)); g->deck = mlx_xpm_file_to_image(g->mlx, "./xpm/floor.xpm", &(g->deck_w), &(g->deck_h)); g->imgdeck = (int*)mlx_get_data_addr(g->deck, &(g->deck_bpp), &(g->deck_sl), &(g->deck_end)); g->imgpoke = (int*)mlx_get_data_addr(g->img, &g->bpp, &(g->sl), &(g->end)); initiodraw(g); drawstuff(g); mlx_put_image_to_window(g->mlx, g->win, g->skybox, 0, 0); mlx_put_image_to_window(g->mlx, g->win, g->deck, 0, 300); mlx_put_image_to_window(g->mlx, g->win, g->img, 0, 0); player(g); mlx_loop_hook(g->mlx, repeat, g); mlx_loop(g->mlx); }

chronos.c

#include "wolf3d.h" int repeat(t_gg *g) { mlx_hook(g->win, 2, 0, vaultmovement, g); mlx_hook(g->win, 3, 0, vaultmovementtoggle, g); mlx_hook(g->win, 17, 0, close_win, g); return (0); }

wolf3d.h

#ifndef WOLF3D_H # define WOLF3D_H # include <unistd.h> # include <stdlib.h> # include <fcntl.h> # include <math.h> # include "../libft/libft.h" # include "../minilibx/mlx.h" # define HEIGHT 600 # define WIDTH 600 # define MAPH 10 # define MAPW 10 typedef struct s_gg { char *worldmap[MAPH]; void *mlx; void *win; void *img; void *skybox; void *deck; void *character; void *healthbar; int *imgpoke; int *imgsky; int *imgdeck; int *imgchar; int *imghealth; int sl; int end; int bpp; int sky_sl; int sky_end; int sky_bpp; int sky_w; int sky_h; int deck_h; int deck_w; int deck_sl; int deck_end; int deck_bpp; int char_h; int char_w; int char_bpp; int char_sl; int char_end; int health_w; int health_h; int health_bpp; int health_sl; int health_end; double posx; double posy; double dirx; double diry; double planex; double planey; double time; double oldtime; double camerax; double rayposx; double rayposy; double raydirx; double raydiry; int mapx; int mapy; double sidedistx; double sidedisty; double deltadistx; double deltadisty; double perpwalldist; int stepx; int stepy; int hit; int side; int x; int y; int w; int d; int h; int color; int lineheight; int drawstart; int drawend; int ycolor; int xcolor; double movespeed; double rotspeed; double oldplanex; double olddirx; int upkey; int downkey; int leftkey; int rightkey; unsigned char chan[3]; } t_gg; void map(t_gg *g); void exitit(char *str); int close_win(t_gg *g); unsigned int colormagic(int i, double x, double y); void novatempus(t_gg *g, int x); void player(t_gg *g); void colorpick(t_gg *g); void initiodraw(t_gg *g); void drawstuff(t_gg *g); void printcontrols(int i); void errorcheck(char *str); void upmove(t_gg *g); void downmove(t_gg *g); void rightmove(t_gg *g); void leftmove(t_gg *g); int keyhooks(int key, t_gg *g); int vaultmovement(int key, t_gg *g); int vaultmovementtoggle(int key, t_gg *g); void makewindow(t_gg *g); void redraw(t_gg *g); int repeat(t_gg *g); #endif

makefile

NAME = wolf3d CC = gcc FLAGS = -Wall -Wextra -Werror FLAGS2 = -L minilibx -lmlx -framework OpenGL -framework AppKit SRC = srcs/main.c srcs/init.c srcs/move.c srcs/redraw.c srcs/draw.c srcs/chronos.c LIBFT_DIR = libft LIBS = libft/libft.a OBJS = $(SRC:.c=.o) HEADER = srcs/wolf3d.h all: $(NAME) $(LIBS): make -C $(LIBFT_DIR) $(NAME): $(SRC) $(LIBS) $(CC) $(FLAGS) $(FLAGS2) $(SRC) $(LIBS) -o wolf3d clean: $(MAKE) -C $(LIBFT_DIR) clean rm -rf $(OBJS) fclean: clean $(MAKE) -C $(LIBFT_DIR) fclean rm -f $(NAME) re: fclean all