From 3c076272c8cd13b42863e6913867f7665872109f Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Mon, 9 Nov 2026 21:34:22 -0700 Subject: [PATCH 1/1] Ray intercepts --- README.md | 2 + src/game.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/game.h | 18 ++++ src/sdl.c | 76 ++++++++++++++++ src/sdl.h | 3 + 5 files changed, 355 insertions(+) create mode 100644 README.md create mode 100644 src/game.c create mode 100644 src/game.h create mode 100644 src/sdl.c create mode 100644 src/sdl.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef1cbc4 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# PatchyCaster +We wuz wizzards n sheit diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..5607883 --- /dev/null +++ b/src/game.c @@ -0,0 +1,256 @@ +#include "game.h" +#include "sdl.h" + +/* to be removed */ +#define M_PI 3.14159265358979323846 +#include +#include +#include + +/* mostly from https://www.permadi.com/tutorial/raycast/rayc1.html */ + +/* Distance from player to plane = (WIDTH/2)/tan(FOV/2) */ +/* Center = (WIDTH/2, HEIGHT/2) */ +/* Angle between rays = FOV/WIDTH */ + +/* +Degrees: + 90 0x4000 + | +0x8000 180---+---0 0x0000 + | + 270 0xC000 +Cordinates: + (+y) + | +(-x)---+---(+x) + | + (-y) +*/ +#define ANGLE_0 (0x0000) +#define ANGLE_90 (0x4000) +#define ANGLE_180 (0x8000) +#define ANGLE_270 (0xC000) + +/* TODO: made adjustable */ +/* #define FOV (90) */ +#define FOV (ANGLE_90) + + +/* Y needs to be indexed as 9-y */ +int map[10][10] = { + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,2,2,2,0,0,0,0}, + {1,0,0,2,0,2,0,0,0,0}, + {1,0,0,2,2,2,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,1,1,1}, +}; +/* +int map[10][10] = { + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0}, +};*/ + +/* 16 bit unsigned number */ +typedef unsigned short bam; + +input Input; + +struct player { + int x; + int y; + /* TODO: can prob make this work with any size int */ + /* Needs to be 16bit binary angular measurement */ + /* 45/8192 of a degree, 1/65536 of a turn */ + /* 65536/2pi is 1 radian */ + bam bearing; +}; +typedef struct player player; +player Player; + +struct ray { + int wall_type; + int distance; + int offset; +}; +typedef struct ray ray; + +float bam_sin(bam bearing) { + return sin((bearing*M_PI)/32768); +} +float bam_cos(bam bearing) { + return cos((bearing*M_PI)/32768); +} +float bam_tan(bam bearing) { + return tan((bearing*M_PI)/32768); +} + +void game_init(void) { + /* Player pos is also in units (TEXTURE_SIZE) */ + Player.x = 129; + Player.y = 129; + /* 45 degrees */ + /*Player.bearing = 8192;*/ + Player.bearing = ANGLE_90/2; +} + +/* https://www.permadi.com/tutorial/raycast/rayc7.html + * Horizontal intersections: + * dy = TEXTURE_SIZE + * tan(bearing) = TEXTURE_SIZE/dx + * dx = TEXTURE_SIZE/tan(bearing) +*/ +ray *castRay(player *PlayerC, bam bearing) { + /* These need program lifetime, they are returned as pointers */ + static ray Xray; + static ray Yray; + int y, x, dy, dx; + + /* init */ + Xray.wall_type = 0; + Yray.wall_type = 0; + + /* TODO: force texture size to be a power of 2 and then have a macro for + * the bits needed to do * and / */ + + /* horizontal intersections */ + if (bearing != ANGLE_0 && bearing != ANGLE_180) { + if (bearing > ANGLE_0 && bearing < ANGLE_180) { + /* facing up */ + y = (PlayerC->y/TEXTURE_SIZE) * TEXTURE_SIZE + TEXTURE_SIZE; + dy = TEXTURE_SIZE; + } else { + /* facing down */ + y = (PlayerC->y/TEXTURE_SIZE) * TEXTURE_SIZE - 1; + dy = -TEXTURE_SIZE; + } + if (bearing == ANGLE_90 || bearing == ANGLE_270) { + x = PlayerC->x; + dx = 0; + } else { + x = PlayerC->x + (y-PlayerC->y)/bam_tan(bearing); + dx = dy/bam_tan(bearing); + } + + while(y/TEXTURE_SIZE >= 0 && y/TEXTURE_SIZE < 10 && x/TEXTURE_SIZE >= 0 && x/TEXTURE_SIZE < 10) { + if(map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE] != 0) { + /* TODO: actual fill out properly lol */ + Xray.wall_type = map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE]; + setColour(0xff,0xff,0); + drawLine2(PlayerC->x, PlayerC->y, x, y); + setColour(0,0xff,0xff); + break; + } + y+=dy; + x+=dx; + } + } + + /* vertical intersections */ + if (bearing != ANGLE_90 && bearing != ANGLE_270) { + if (bearing < ANGLE_90 || bearing > ANGLE_270) { + /* facing right */ + x = (PlayerC->x/TEXTURE_SIZE) * TEXTURE_SIZE + TEXTURE_SIZE; + dx = TEXTURE_SIZE; + } else { + /* facing left */ + x = (PlayerC->x/TEXTURE_SIZE) * TEXTURE_SIZE - 1; + dx = -TEXTURE_SIZE; + } + if (bearing == ANGLE_0 || bearing == ANGLE_180) { + y = PlayerC->y; + dy = 0; + } else { + y = PlayerC->y + (x-PlayerC->x)*bam_tan(bearing); + dy = dx*bam_tan(bearing); + } + + while(y/TEXTURE_SIZE >= 0 && y/TEXTURE_SIZE < 10 && x/TEXTURE_SIZE >= 0 && x/TEXTURE_SIZE < 10) { + if(map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE] != 0) { + /* TODO: actual fill out properly lol */ + Yray.wall_type = map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE]; + setColour(0xff,0xff,0); + drawLine2(PlayerC->x, PlayerC->y, x, y); + setColour(0,0xff,0xff); + break; + } + y+=dy; + x+=dx; + } + } + + if(Xray.wall_type != 0) { + return &Xray; + } + if(Yray.wall_type != 0) { + return &Xray; + } + + return NULL; +} + +void game_loop(void) { + int scanVector = Player.bearing+(FOV/2); + int i; + /* debug */ + int x, y; + + /* Handle Input */ + Player.x += Input.xmove; + Player.y += Input.ymove; + Player.bearing += Input.yaw; + Input.xmove = 0; + Input.ymove = 0; + Input.yaw = 0; + Input.pitch = 0; + + /* Render */ + for (i=0;i +#include + +SDL_Renderer *render; +int w, h; + +int drawLine(int x, int y, int y2) { + return SDL_RenderDrawLine(render, x, y, x, y2); +} +int drawLine2(int x, int y, int x2, int y2) { + return SDL_RenderDrawLine(render, x, h-y, x2, h-y2); +} + +int setColour(unsigned char r, unsigned char g, unsigned char b) { + return SDL_SetRenderDrawColor(render, r,g,b, 255); +} + +int main(int argc, char *argv[]) { + + SDL_Window *window; + SDL_Event event; + int quit = 0; + + game_init(); + + /* SDL shit */ + if(SDL_Init(SDL_INIT_VIDEO) == -1) { + puts(SDL_GetError()); + return 1; + } + window = SDL_CreateWindow("Raycasting test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, 0); + if (window == NULL) { + puts(SDL_GetError()); + return 1; + } + render = SDL_CreateRenderer(window, -1, 0); + if (render == NULL) { + puts(SDL_GetError()); + return 1; + } + + while(!quit) { + const Uint8 *KeyState; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + quit = 1; + } + } + + /* Handle Inputs */ + KeyState = SDL_GetKeyboardState(NULL); + if (KeyState[SDL_SCANCODE_W]) Input.ymove += 1; + if (KeyState[SDL_SCANCODE_S]) Input.ymove -= 1; + if (KeyState[SDL_SCANCODE_A]) Input.xmove -= 1; + if (KeyState[SDL_SCANCODE_D]) Input.xmove += 1; + if (KeyState[SDL_SCANCODE_LEFT]) Input.yaw += 20; + if (KeyState[SDL_SCANCODE_RIGHT]) Input.yaw -= 20; + + SDL_GetRendererOutputSize(render, &w, &h); + + SDL_SetRenderDrawColor(render, 0x00,0x00,0x00, 255); + SDL_RenderClear(render); + SDL_SetRenderDrawColor(render, 0x00,0xFF,0xFF, 255); + game_loop(); + SDL_RenderPresent(render); + } + + SDL_DestroyRenderer(render); + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +} + diff --git a/src/sdl.h b/src/sdl.h new file mode 100644 index 0000000..325afa5 --- /dev/null +++ b/src/sdl.h @@ -0,0 +1,3 @@ +int drawLine(int x, int y, int y2); +int drawLine2(int x, int y, int x2, int y2); +int setColour(unsigned char r, unsigned char g, unsigned char b); -- 2.56.0