Last active
November 10, 2022 16:08
-
-
Save EdwardDowling/01a872cca79e1404bbc2 to your computer and use it in GitHub Desktop.
Maze generation and raycasting.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <ncurses.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#define WIDTH 63 | |
#define HEIGHT 31 | |
typedef struct position{ | |
int x; | |
int y; | |
}position; | |
char room[HEIGHT][WIDTH]; | |
int c; | |
int keys; | |
position dir; | |
position p; | |
int random(int min,int max){ | |
unsigned int temp = rand()%(max-min)+min; | |
return temp; | |
} | |
void divide(int x,int y,int height,int width, char room[HEIGHT][WIDTH],char side){ | |
int rx ; | |
int ry; | |
if(width > 5 && height > 5){ | |
rx = 2*(random(x+2,x+width-2)/2); | |
ry = 2*(random(y+2,y+height-2)/2); | |
}else{ | |
rx = x+2; | |
ry = y+2; | |
} | |
for(int j = 0;j<height;j++){ | |
room[j+y][rx] = side; | |
} | |
for(int i = 0;i<width;i++){ | |
room[ry][i+x] = side; | |
} | |
int gap = rand()%4; | |
if(gap != 0){ | |
if(rx - x > 5){ | |
room[ry][2*((1+random(x+1,rx-1))/2)-1] = 0; | |
}else{room[ry][x+1] = 0;} | |
} | |
if(gap != 1){ | |
if(x + width - rx > 5){ | |
room[ry][2*((1+random(rx+1,x+width-1))/2)-1] = 0; | |
}else{room[ry][rx+1] = 0;} | |
} | |
if(gap != 2){ | |
if(ry-y> 5){ | |
room[2*((1+random(y+1,ry-1)/2))-1][rx] = 0; | |
}else{room[y+1][rx] = 0;} | |
} | |
if(gap != 3){ | |
if(y + height - ry > 5){ | |
room[2*((1+random(ry+1,y+height-1))/2)-1][rx] = 0; | |
}else{room[ry+1][rx] = 0;} | |
} | |
if(ry-y>3 && rx-x>3)divide(x,y,ry-y,rx-x,room,'#'); | |
if(ry-y>3 && width-(rx-x)>3)divide(rx,y,ry-y,width-(rx-x),room,'#'); | |
if(height-(ry-y)>3 && rx-x>3)divide(x,ry,height-(ry-y),rx-x,room,'#'); | |
if(height-(ry-y)>3 && width-(rx-x)>3)divide(rx,ry,height-(ry-y),width-(rx-x),room,'#'); | |
} | |
void maze(int height, int width ,char room[height][width]){ | |
for(int i = 0;i<height;i++){ | |
room[i][0] = '#'; | |
room[i][width - 1] = '#'; | |
} | |
for(int j = 0;j<width;j++){ | |
room[0][j] = '#'; | |
room[height - 1][j] = '#'; | |
} | |
divide(0,0,height,width,room,'#'); | |
} | |
int main(){ | |
initscr(); | |
srand(time(NULL)); | |
//fill array | |
for(int i = 0;i<HEIGHT;i++){ | |
for(int j = 0;j < WIDTH;j++){ | |
room[i][j] = 0 ; | |
} | |
} | |
maze(HEIGHT,WIDTH,room); | |
p.x = 01; | |
p.y = 01; | |
dir.x = 0; | |
dir.y = 0; | |
WINDOW *win; | |
win = newwin(HEIGHT,WIDTH,0,0); | |
raw(); | |
keypad(stdscr,TRUE); | |
curs_set(0); | |
//get input | |
while(1){ | |
c = getch(); | |
werase(win); | |
wrefresh(win); | |
switch(c){ | |
case KEY_UP: | |
dir.y--; | |
break; | |
case KEY_RIGHT: | |
dir.x++; | |
break; | |
case KEY_LEFT: | |
dir.x--; | |
break; | |
case KEY_DOWN: | |
dir.y++; | |
break; | |
} | |
switch(room[p.y + dir.y][p.x + dir.x]){ | |
case 0: | |
p.y += dir.y; | |
p.x += dir.x; | |
break; | |
} | |
dir.y = 0; | |
dir.x = 0; | |
if(p.x >= WIDTH - 1)p.x--; | |
if(p.x < 1)p.x++; | |
if(p.y >= HEIGHT -1)p.y--; | |
if(p.y < 1)p.y++; | |
wmove(win,p.y,p.x); | |
wprintw(win,"X"); | |
//draw level | |
for(int j = 0; j< WIDTH;j++){ | |
for(int i = 0;i < HEIGHT; i++){ | |
if(room[i][j]!=0){ | |
wmove(win,i,j); | |
wprintw(win,&room[i][j]); | |
} | |
} | |
} | |
wrefresh(win); | |
if((c)== ' '){ | |
break; | |
} | |
} | |
endwin(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "raylib.h" | |
#include "testHeader.h" | |
#include <math.h> | |
int main() | |
{ | |
// Initialization | |
//-------------------------------------------------------------------------------------- | |
screenWidth = W_WIDTH; | |
screenHeight = W_HEIGHT; | |
InitWindow(screenWidth, screenHeight, "Test Game"); | |
initGame(); | |
double planeX = 0, planeY = 0.66; //the 2d raycaster version of camera plane | |
HideCursor(); | |
SetTargetFPS(60); | |
// Main game loop | |
while (!WindowShouldClose()) | |
{ | |
updateGame(); | |
// Draw | |
//---------------------------------------------------------------------------------- | |
BeginDrawing(); | |
ClearBackground(RAYWHITE); | |
for(int x = 0; x < W_WIDTH; x++){ | |
//converts screen coodinates to camera plane | |
double cameraX = ((2 * x) / (double)W_WIDTH) - 1; | |
//ray direction for this vertical slice | |
double rayDirX = player.dirX + planeX * cameraX; | |
double rayDirY = player.dirY + planeY * cameraX; | |
//map coordinates | |
player.mapX = (int)player.x; | |
player.mapY = (int)player.y; | |
//length of ray from current position to next x or y-side | |
double sideDistX; | |
double sideDistY; | |
//distance travelled when traversing an x or y value | |
//deltaDistX^2 = (rayDirX * 1/rayDirX)^2 + (rayDirY * 1/rayDirx)^2 | |
double deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX)); | |
//deltaDisty^2 = (rayDirY * 1/rayDirY)^2 + (rayDirX * 1/rayDirY)^2 | |
double deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY)); | |
double perpWallDist; | |
//direction travelled | |
int stepX; | |
int stepY; | |
int hit = 0; | |
int side; | |
//direction and initial distance to next x or y value | |
if (rayDirX < 0) | |
{ | |
stepX = -1; | |
sideDistX = (player.x - player.mapX) * deltaDistX; | |
} | |
else | |
{ | |
stepX = 1; | |
sideDistX = (player.mapX + 1.0 - player.x) * deltaDistX; | |
} | |
if (rayDirY < 0) | |
{ | |
stepY = -1; | |
sideDistY = (player.y - player.mapY) * deltaDistY; | |
} | |
else | |
{ | |
stepY = 1; | |
sideDistY = (player.mapY + 1.0 - player.y) * deltaDistY; | |
} | |
//check each coordinate for wall | |
while (hit == 0) | |
{ | |
//move to next possible wall location | |
if (sideDistX < sideDistY) | |
{ | |
sideDistX += deltaDistX; | |
player.mapX += stepX; | |
side = 0; | |
} | |
else | |
{ | |
sideDistY += deltaDistY; | |
player.mapY += stepY; | |
side = 1; | |
} | |
//Check if map coordinate is occupied | |
if (room[player.mapX][player.mapY]) hit = 1; | |
} | |
//Calculate distance to camera plane. | |
if (side == 0) perpWallDist = (player.mapX - player.x + (1 - stepX) / 2) / rayDirX; | |
else perpWallDist = (player.mapY - player.y + (1 - stepY) / 2) / rayDirY; | |
//Calculate height of line to draw on screen | |
int lineHeight = (int)(W_HEIGHT / perpWallDist); | |
//calculate start and end of line | |
int drawStart = (-lineHeight + W_HEIGHT) / 2; | |
if(drawStart < 0)drawStart = 0; | |
int drawEnd = (lineHeight + W_HEIGHT) / 2; | |
if(drawEnd >= W_HEIGHT)drawEnd = W_HEIGHT - 1; | |
//darken side | |
Color wallColor; | |
switch(side) | |
{ | |
case 0: wallColor = LIGHTGRAY; break; | |
case 1: wallColor = DARKGRAY; break; | |
default: wallColor = BLUE; break; | |
} | |
//draw the line | |
DrawLine(x, drawStart,x, drawEnd, wallColor); | |
} | |
//draw overlay | |
DrawText(FormatText("Test game FPS %f",GetFPS()), 10, 10, 20, MAROON); | |
drawGameMap(); | |
drawReticle(20); | |
EndDrawing(); | |
//input---------------------------------------------------------------------------------- | |
if(IsKeyDown(KEY_W)){ | |
if(room[(int)(player.x + player.dirX * 5*GetFrameTime())][(int)(player.y)] == false) | |
player.x += player.dirX * 5*GetFrameTime(); | |
if(room[(int)(player.x)][(int)(player.y + player.dirY * 5*GetFrameTime())] == false) | |
player.y += player.dirY * 5*GetFrameTime(); | |
} | |
//move backwards if no wall behind you | |
if (IsKeyDown(KEY_S)) | |
{ | |
if(room[(int)(player.x - player.dirX * 5*GetFrameTime())][(int)(player.y)] == false) | |
player.x -= player.dirX * 5*GetFrameTime(); | |
if(room[(int)(player.x)][(int)(player.y - player.dirY * 5*GetFrameTime())] == false) | |
player.y -= player.dirY * 5*GetFrameTime(); | |
} | |
//store old values | |
double oldDirX = player.dirX; | |
double oldDirY = player.dirY; | |
double oldPlaneX = planeX; | |
double oldPlaneY = planeY; | |
//rotate plane and dir to the left | |
if(IsKeyDown(KEY_LEFT) && !IsKeyDown(KEY_RIGHT)){ | |
player.dirX = oldDirX * cos(5*GetFrameTime()) - oldDirY * sin(5*GetFrameTime()); | |
player.dirY = oldDirX * sin(5*GetFrameTime()) + oldDirY * cos(5*GetFrameTime()); | |
planeX = oldPlaneX * cos(5*GetFrameTime()) - oldPlaneY * sin(5*GetFrameTime()); | |
planeY = oldPlaneX * sin(5*GetFrameTime()) + oldPlaneY * cos(5*GetFrameTime()); | |
} | |
//rotate plane and dir to the right | |
if(IsKeyDown(KEY_RIGHT) && !IsKeyDown(KEY_LEFT)){ | |
player.dirX = oldDirX * cos(-5*GetFrameTime()) - oldDirY * sin(-5*GetFrameTime()); | |
player.dirY = oldDirX * sin(-5*GetFrameTime()) + oldDirY * cos(-5*GetFrameTime()); | |
planeX = oldPlaneX * cos(-5*GetFrameTime()) - oldPlaneY * sin(-5*GetFrameTime()); | |
planeY = oldPlaneX * sin(-5*GetFrameTime()) + oldPlaneY * cos(-5*GetFrameTime()); | |
} | |
} | |
CloseWindow(); | |
return 0; | |
} | |
void initGame(){ | |
//initialization | |
//Player starting values---------------------------------------------------------------- | |
player.x =1; | |
player.y = 1; | |
player.dirX = -1; | |
player.dirY = 0; | |
//obstacles----------------------------------------------------------------------------- | |
for(int i = 0;i<MAX_BLOCKS;i++){ | |
blocks[i].rectangle.x = 0; | |
blocks[i].rectangle.y = 0; | |
blocks[i].rectangle.width = 0; | |
blocks[i].rectangle.height = 0; | |
blocks[i].color = DARKGRAY; | |
} | |
for(int i = 0;i < HEIGHT;i++){ | |
for(int j = 0; j <WIDTH;j++){ | |
room[i][j] = 0; | |
} | |
} | |
//maze generation--------------------------------------------------------------------------- | |
maze(HEIGHT,WIDTH,room); | |
//asigning blocks to maze | |
int blockIndex = 0; | |
for(int i = 0;i < HEIGHT;i++){ | |
for(int j = 0; j < WIDTH;j++){ | |
if(room[i][j]){ | |
blocks[blockIndex].rectangle.x = j*TILE_WIDTH; | |
blocks[blockIndex].rectangle.y = i*TILE_HEIGHT; | |
blocks[blockIndex].rectangle.width = TILE_WIDTH; | |
blocks[blockIndex].rectangle.height = TILE_HEIGHT; | |
blocks[blockIndex].color = BLACK; | |
blockIndex++; | |
} | |
} | |
} | |
} | |
void updateGame(){ | |
} | |
void drawGameMap(){ | |
//draw blocks | |
for(int i = 0;i < MAX_BLOCKS;i++){ | |
DrawRectangle(blocks[i].rectangle.x + MAP_OFFSET_X ,blocks[i].rectangle.y + MAP_OFFSET_Y, | |
blocks[i].rectangle.width,blocks[i].rectangle.height, | |
Fade(blocks[i].color,0.5f)); | |
} | |
//draw player | |
DrawRectangle((int)player.y*TILE_HEIGHT + MAP_OFFSET_X,(int)player.x*TILE_WIDTH + MAP_OFFSET_Y,TILE_WIDTH,TILE_HEIGHT,MAROON); | |
} | |
//----------------------------------------------------------------------------------------------- | |
//maze stuff | |
void divide(int x,int y,int height,int width,char room[HEIGHT][WIDTH]){ | |
int rx; | |
int ry; | |
if(width > 5 && height > 5){ | |
rx = 2*(GetRandomValue(x+2,x+width-2)/2); | |
ry = 2*(GetRandomValue(y+2,y+height-2)/2); | |
}else{ | |
rx = x+2; | |
ry = y+2; | |
} | |
for(int j = 0; j<height; j++){ | |
room[j+y][rx] = 1; | |
} | |
for(int i = 0;i<width;i++){ | |
room[ry][i+x] = 1; | |
} | |
int gap = GetRandomValue(0,4); | |
if(gap != 0){ | |
if(rx - x > 5){ | |
room[ry][2*((1+GetRandomValue(x+1,rx-1))/2)-1] = 0; | |
}else{room[ry][x+1] = 0;} | |
} | |
if(gap != 1){ | |
if(x + width - rx > 5){ | |
room[ry][2*((1+GetRandomValue(rx+1,x+width-1))/2)-1] = 0; | |
}else{room[ry][rx+1] = 0;} | |
} | |
if(gap != 2){ | |
if(ry-y> 5){ | |
room[2*((1+GetRandomValue(y+1,ry-1)/2))-1][rx] = 0; | |
}else{room[y+1][rx] = 0;} | |
} | |
if(gap != 3){ | |
if(y + height - ry > 5){ | |
room[2*((1+GetRandomValue(ry+1,y+height-1))/2)-1][rx] = 0; | |
}else{room[ry+1][rx] = 0;} | |
} | |
if(ry-y>3 && rx-x>3)divide(x,y,ry-y,rx-x,room); | |
if(ry-y>3 && width-(rx-x)>3)divide(rx,y,ry-y,width-(rx-x),room); | |
if(height-(ry-y)>3 && rx-x>3)divide(x,ry,height-(ry-y),rx-x,room); | |
if(height-(ry-y)>3 && width-(rx-x)>3)divide(rx,ry,height-(ry-y),width-(rx-x),room); | |
} | |
void maze(int height, int width ,char room[height][width]){ | |
for(int i = 0;i<height;i++){ | |
room[i][0] = 1; | |
room[i][width - 1] = 1; | |
} | |
for(int j = 0;j<width;j++){ | |
room[0][j] = 1; | |
room[height - 1][j] = 1; | |
} | |
divide(0,0,height,width,room); | |
} | |
void drawReticle(int size){ | |
DrawLine(W_WIDTH/2,W_HEIGHT/2-size/2,W_WIDTH/2,W_HEIGHT/2+size/2,MAROON); | |
DrawLine(W_WIDTH/2-size/2,W_HEIGHT/2,W_WIDTH/2 + size/2,W_HEIGHT/2,MAROON); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MAX_BLOCKS 100000 | |
#define HEIGHT 35 | |
#define WIDTH 55 | |
#define TILE_WIDTH 5 | |
#define TILE_HEIGHT 5 | |
#define W_WIDTH 800 | |
#define W_HEIGHT 480 | |
#define MAP_OFFSET_X 500 | |
#define MAP_OFFSET_Y 20 | |
typedef struct Player{ | |
int mapX, mapY; | |
double x,y, dirX,dirY; | |
}Player; | |
typedef struct Circle { | |
int radius; | |
Vector2 centre; | |
} Circle; | |
typedef struct Block { | |
Rectangle rectangle; | |
Color color; | |
}Block; | |
int screenWidth, screenHeight; | |
Player player; | |
Block blocks[MAX_BLOCKS]; | |
char room[HEIGHT][WIDTH]; | |
static void updateGame(void); | |
static void initGame(void); | |
static void drawGameMap(void); | |
static void divide(int x,int y,int height,int width,char room[HEIGHT][WIDTH]); | |
static void maze(int height, int width ,char room[height][width]); | |
static void drawReticle(int size); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment