]> PatchyGit - allbombson/PatchyCaster.git/commitdiff
Ray intercepts
authorSam Smith <sam@patchysicp.xyz>
Tue, 10 Nov 2026 04:34:22 +0000 (21:34 -0700)
committerSam Smith <sam@patchysicp.xyz>
Tue, 10 Nov 2026 04:34:22 +0000 (21:34 -0700)
README.md [new file with mode: 0644]
src/game.c [new file with mode: 0644]
src/game.h [new file with mode: 0644]
src/sdl.c [new file with mode: 0644]
src/sdl.h [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
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 (file)
index 0000000..5607883
--- /dev/null
@@ -0,0 +1,256 @@
+#include "game.h"
+#include "sdl.h"
+
+/* to be removed */
+#define M_PI 3.14159265358979323846
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* 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<SCREEN_WIDTH;++i) {
+               int newVector = scanVector - i*FOV/SCREEN_WIDTH;
+               /* Debug */
+               drawLine2(Player.x, Player.y, Player.x+128*bam_cos(newVector), Player.y+128*bam_sin(newVector));
+               if(castRay(&Player, newVector) != NULL) {
+                       drawLine(i, 20, 180);
+               }
+               //scanVector-=FOV/SCREEN_WIDTH;
+       }
+
+       /* Debug */
+       setColour(0xAA,0x00,0x00);
+       for (x = 0; x < 10; x++) {
+               for (y = 0; y < 10; y++) {
+                       if (map[9-y][x]) {
+                               /* Horizontal lines */
+                               drawLine2(64*x, 64*y, 64*x+64, 64*y);
+                               drawLine2(64*x, 64*y+64, 64*x+64, 64*y+64);
+                               /* Vertical lines */
+                               drawLine2(64*x, 64*y, 64*x, 64*y+64);
+                               drawLine2(64*x+64, 64*y, 64*x+64, 64*y+64);
+                       }
+               }
+       }
+       /* Actual Vector */
+       drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing), Player.y+128*bam_sin(Player.bearing));
+       /* FOV as a 2 vectors for min and max */
+       drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing-(FOV/2)), Player.y+128*bam_sin(Player.bearing-(FOV/2)));
+       drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing+(FOV/2)), Player.y+128*bam_sin(Player.bearing+(FOV/2)));
+       /* Box */
+       drawLine2(Player.x-20, Player.y-20, Player.x-20, Player.y+20);
+       drawLine2(Player.x-20, Player.y+20, Player.x+20, Player.y+20);
+       drawLine2(Player.x+20, Player.y+20, Player.x+20, Player.y-20);
+       drawLine2(Player.x+20, Player.y-20, Player.x-20, Player.y-20);
+
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..bfa42b8
--- /dev/null
@@ -0,0 +1,18 @@
+/* TODO: make adjustable */
+//#define SCREEN_WIDTH (320)
+//#define SCREEN_HEIGHT (200)
+#define SCREEN_WIDTH (1280)
+#define SCREEN_HEIGHT (720)
+#define TEXTURE_SIZE (64)
+
+struct Input {
+       int xmove;
+       int ymove;
+       int yaw;
+       int pitch;
+};
+typedef struct Input input;
+extern input Input;
+
+void game_init(void);
+void game_loop(void);
diff --git a/src/sdl.c b/src/sdl.c
new file mode 100644 (file)
index 0000000..00d207e
--- /dev/null
+++ b/src/sdl.c
@@ -0,0 +1,76 @@
+#include "sdl.h"
+#include "game.h"
+#include <SDL2/SDL.h>
+#include <stdio.h>
+
+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 (file)
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);