Created
June 23, 2020 11:22
-
-
Save RedactedProfile/949cda9cfc1d7b798d03004c5c83ba2a to your computer and use it in GitHub Desktop.
3DSage Make Your Own Raycaster Game source
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 <stdlib.h> | |
#include <GL\glew.h> | |
#include <GL\freeglut.h> | |
#include <math.h> | |
#define PI 3.1415926535 | |
#define PI6 PI*2 | |
#define PI2 PI/2 | |
#define PI3 3*PI2 | |
#define DR 0.0174533 // one degree in radians | |
float px, py, pdx, pdy, pa; // player position | |
void drawPlayer() { | |
glColor3f(1, 1, 0); | |
glPointSize(8); | |
glBegin(GL_POINTS); | |
glVertex2i(px, py); | |
glEnd(); | |
glLineWidth(3); | |
glBegin(GL_LINES); | |
glVertex2i(px, py); | |
glVertex2i(px + pdx * 5, py + pdy * 5); | |
glEnd(); | |
} | |
int mapX = 8, mapY = 8, mapS = 64; | |
int map[] = | |
{ | |
1,1,1,1,1,1,1,1, | |
1,0,1,0,0,0,1,1, | |
1,0,0,0,0,1,0,1, | |
1,0,0,0,1,1,0,1, | |
1,0,0,0,1,0,0,1, | |
1,0,1,0,0,0,0,1, | |
1,0,0,0,0,0,0,1, | |
1,1,1,1,1,1,1,1, | |
}; | |
void drawMap2D() { | |
int x, y, xo, yo; | |
for (y = 0; y < mapY; y++) { | |
for (x = 0; x < mapX; x++) { | |
// 1 = white | |
// 0 = black | |
if (map[y * mapX + x] == 1) { | |
glColor3f(1, 1, 1); | |
} | |
else { | |
glColor3f(0, 0, 0); | |
} | |
xo = x * mapS; | |
yo = y * mapS; | |
// draw | |
glBegin(GL_QUADS); | |
glVertex2i(xo +1, yo +1); | |
glVertex2i(xo + 1, yo + mapS - 1); | |
glVertex2i(xo + mapS - 1, yo + mapS - 1); | |
glVertex2i(xo + mapS - 1, yo + 1); | |
glEnd(); | |
} | |
} | |
} | |
float dist(float ax, float ay, float bx, float by, float ang) { | |
return ( sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay) ) ); | |
} | |
void drawRays2D() { | |
int r, mx, my, mp, dof; | |
float rx, ry, ra, xo, yo, disT; | |
// set ray's angle to the player's angle | |
ra = pa - DR * 30; | |
if (ra < 0) { | |
ra += PI6; } | |
if (ra > PI6) { | |
ra -= PI6; } | |
for (r = 0; r < 60; r++) { | |
// Check Horizontal Grid Lines | |
dof = 0; | |
float disH = 1000000, hx = px, hy = py; | |
float aTan = -1 / tan(ra); // negative inverse of tangent | |
// are we looking up | |
if (ra > PI) { | |
// find out the ray's first hit position | |
// round the ray's y position to the nearest 64th value | |
ry = (((int)py >> 6) << 6) - 0.001; | |
// ray x value is the distance between the player and the ray's y position, multiplied by inverse of tan and player's x position | |
rx = (py - ry) * aTan + px; | |
// we need the next x and y offset | |
yo = -64; | |
xo = -yo * aTan; | |
} | |
// are we looking down | |
if (ra < PI) { | |
// find out the ray's first hit position | |
// round the ray's y position to the nearest 64th value | |
ry = (((int)py >> 6) << 6) + 64; | |
// ray x value is the distance between the player and the ray's y position, multiplied by inverse of tan and player's x position | |
rx = (py - ry) * aTan + px; | |
// we need the next x and y offset | |
yo = 64; | |
xo = -yo * aTan; | |
} | |
// looking straight left or right | |
if (ra == 0 || ra == PI) { | |
rx = px; | |
ry = py; | |
dof = 8; | |
} | |
// depth of field check to 8 maximum | |
while (dof < 8) { | |
// find the quadrant in the map array | |
mx = (int)(rx) >> 6; | |
my = (int)(ry) >> 6; | |
mp = my * mapX + mx; | |
// if the map position is less than the array size, then we can check it inside the map | |
if (mp > 0 && mp < mapX * mapY && map[mp] == 1) { // hit wall | |
// save the ray's coordiantes | |
hx = rx; | |
hy = ry; | |
// calc distance from player | |
disH = dist(px, py, hx, hy, ra); | |
dof = 8; | |
} else { | |
// if we didn't hit a wall, check the next horizontal line (add the x and y offset) | |
rx += xo; | |
ry += yo; | |
dof += 1; // next line | |
} | |
} | |
// Check Vertical Grid Lines | |
dof = 0; | |
float disV = 1000000, vx = px, vy = py; | |
float nTan = -tan(ra); // negative inverse of tangent | |
// are we looking left | |
if (ra > PI2 && ra < PI3) { | |
// find out the ray's first hit position | |
// round the ray's y position to the nearest 64th value | |
rx = (((int)px >> 6) << 6) - 0.001; | |
// ray x value is the distance between the player and the ray's y position, multiplied by inverse of tan and player's x position | |
ry = (px - rx) * nTan + py; | |
// we need the next x and y offset | |
xo = -64; | |
yo = -xo * nTan; | |
} | |
// are we looking right | |
if (ra < PI2 || ra > PI3) { | |
// find out the ray's first hit position | |
// round the ray's y position to the nearest 64th value | |
rx = (((int)px >> 6) << 6) + 64; | |
// ray x value is the distance between the player and the ray's y position, multiplied by inverse of tan and player's x position | |
ry = (px - rx) * nTan + py; | |
// we need the next x and y offset | |
xo = 64; | |
yo = -xo * nTan; | |
} | |
// looking straight up or down | |
if (ra == 0 || ra == PI) { | |
rx = px; | |
ry = py; | |
dof = 8; | |
} | |
// depth of field check to 8 maximum | |
while (dof < 8) { | |
// find the quadrant in the map array | |
mx = (int)(rx) >> 6; | |
my = (int)(ry) >> 6; | |
mp = my * mapX + mx; | |
// if the map position is less than the array size, then we can check it inside the map | |
if (mp > 0 && mp < mapX * mapY && map[mp] == 1) { // hit wall | |
// save the ray's coordiantes | |
vx = rx; | |
vy = ry; | |
// calc distance from player | |
disV = dist(px, py, vx, vy, ra); | |
dof = 8; | |
} | |
else { | |
// if we didn't hit a wall, check the next horizontal line (add the x and y offset) | |
rx += xo; | |
ry += yo; | |
dof += 1; // next line | |
} | |
} | |
// vertical wall hit | |
if (disV < disH) { | |
rx = vx; | |
ry = vy; | |
disT = disV; | |
glColor3f(0.9, 0, 0); | |
} | |
// horizontal wall hit | |
else { | |
rx = hx; | |
ry = hy; | |
disT = disH; | |
glColor3f(0.7, 0, 0); | |
} | |
glLineWidth(3); | |
glBegin(GL_LINES); | |
glVertex2i(px, py); | |
glVertex2i(rx, ry); | |
glEnd(); | |
////// 3D Wall Time | |
// fix fish eye by finding the distance between the player angle and the ray angle | |
float ca = pa - ra; | |
if (ca < 0) { | |
ca += PI6; } | |
if (ca > PI6) { | |
ca -= PI6; } | |
disT = disT * cos(ca); // multiply ray distance by cos of the new angle | |
// cap the line height | |
float lineH = (mapS * 320) / disT; | |
if (lineH > 320) { | |
lineH = 320; } | |
// correct the line offsets | |
float lineO = 160 - lineH / 2; | |
// Draw the lines | |
glLineWidth(8); | |
glBegin(GL_LINES); | |
glVertex2i(r * 8 + 530, lineO); | |
glVertex2i(r * 8 + 530, lineH + lineO); | |
glEnd(); | |
// spread the fan | |
ra += DR; | |
if (ra < 0) { | |
ra += PI6; | |
} | |
if (ra > PI6) { | |
ra -= PI6; | |
} | |
} | |
} | |
void display(void) { | |
glClear(GL_COLOR_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |
drawMap2D(); | |
drawRays2D(); | |
drawPlayer(); | |
glutSwapBuffers(); | |
} | |
void updatePlayerDelta() { | |
pdx = cos(pa) * 5; | |
pdy = sin(pa) * 5; | |
} | |
void buttons(unsigned char key, int x, int y) { | |
switch (key) | |
{ | |
case 'a': | |
pa -= 0.1; | |
if (pa < 0) { | |
pa += PI * 2; } | |
updatePlayerDelta(); | |
break; | |
case 'd': | |
pa += 0.1; | |
if (pa > (2 * PI)) { | |
pa -= 2 * PI; } | |
updatePlayerDelta(); | |
break; | |
case 'w': | |
px += pdx; | |
py += pdy; | |
break; | |
case 's': | |
px -= pdx; | |
py -= pdy; | |
break; | |
default: break; | |
} | |
glutPostRedisplay(); | |
} | |
void init() { | |
glClearColor(0.3, 0.3, 0.3, 0); | |
gluOrtho2D(0, 1024, 512, 0); | |
px = 300; py = 300; | |
updatePlayerDelta(); | |
} | |
int main(int argc, char** argv) { | |
glutInit(&argc, argv); | |
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); | |
glutInitWindowSize(1012, 512); | |
glutInitWindowPosition(0, 0); | |
glutCreateWindow("Test"); | |
init(); | |
glutDisplayFunc(display); | |
glutKeyboardFunc(buttons); | |
glutMainLoop(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment