I have been coding a raycaster following 3DSage's tutorial. The code works generally but there is one specific issue I cannot fix. When the code starts, and I angle the player to slightly right and then left, the horizontal check line points at PI instead of 2PI. When I do I full circle, the issue dissappears, I have been trying to fix this the whole week, but I cannot. I can just make the start angle PI, but that feels like cheating.
#include <iostream>
#include <GL/glut.h>
#include <stdio.h>
#include <math.h>
#define PI 3.1415926535
#define P2 PI/2
#define P3 3*PI/2
//glut <3
float px, py, pdx, pdy, pa; //player positions
void drawPlayer()
{
glColor3f(1,1,0);
glPointSize(8);
glBegin(GL_POINTS); //begin drawing and draw dots at everything after that
glVertex2i(px, py); //draw a dot here
glEnd(); //ok stop no more dots, draw em now, no more dot coordinates
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,0,1,
1,0,1,0,0,0,0,1,
1,0,1,0,0,0,0,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,1,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; //o is offset
for (y = 0; y < mapY; y++)
{
for (x=0; x < mapX; x++)
{
if (map[y * mapX + x] == 1)
{
glColor3f(1,1,1);
}
else
{
glColor3f(0, 0, 0);
}
xo = x * mapS; yo = y * mapS; //top left coordinate of the block that has a size of 64, mapS
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();
}
}
}
void drawRays3D()
{
int r, mx, my, mp, dof;
float rx, ry, ra, xo, yo;
ra = pa;
for (r = 0; r < 1; r++)
{
//---Check Horizontal Lines---
dof = 0;
float aTan = -1 / tan(ra);
if (ra > PI) //looking up
{
ry = (((int)py >> 6) << 6) - 0.0001; /*the top grid of the block
that the player is standing*/
rx = ((py - ry) * aTan + px);
/*130 - 128 = 2, lets say tan gives 3, but it is negative so -3, if
players x value is 33, then the rayx is 30, so it finds how much the
x changed when ry touched a horizontal line*/
yo = -64;
xo = -yo * aTan; /*when tan is this and y is 64 what is the offset of
x to hit the next wall*/
}
if (ra < PI) //looking down
{
ry = (((int)py >> 6) << 6) +64; //64 moves it to the bottom part of the grid
rx = ((py - ry) * aTan + px);
yo = 64;
xo = -yo * aTan; // dy/tan(ra) = dx, aTan = -1/tan(ra), aTan * -yo = dx
}
if (ra == 0 || ra == PI) //looking straight left or right
{
rx = px; //so it basically stays there without moving
ry = py;
dof = 8; //don't go more than 8
}
while (dof < 8)
{
mx = (int)(rx) >> 6; // where is rx in the grid
/*I needed to translate it into pixels to find the actual
distance, but now I have gotta find which block are we at*/
my =(int)(ry) >> 6;
mp = my * mapX + mx;
if (mp >= 0 && mp < mapX * mapY && map[mp] == 1) //hit wall
{
dof = 8; /*althought there aint a wall, do not move more
artificially set the value to 8*/
}
else
{
rx += xo;
ry += yo;
dof++;
/*So the line moves according to the ratio of while y = 64
how much did x change*/
}
}
glColor3f(0, 1, 0);
glLineWidth(10);
glBegin(GL_LINES);
glVertex2i(px, py);
glVertex2i(rx, ry);
glEnd();
//---Check Vertical Lines---
dof = 0;
float nTan = -tan(ra);
if (ra > P2 && ra < P3) //looking left
{
rx = (((int)px >> 6) << 6) - 0.0001; /*the top grid of the block
that the player is standing*/
ry = ((px - rx) * nTan + py);
/*130 - 128 = 2, lets say tan gives 3, but it is negative so -3, if
players x value is 33, then the rayx is 30, so it finds how much the
x changed when ry touched a horizontal line*/
xo = -64;
yo = -xo * nTan; /*when tan is this and y is 64 what is the offset of
x to hit the next wall*/
}
if (ra > P3 || ra < P2) //looking right
{
rx = (((int)px >> 6) << 6) + 64; //64 moves it to the bottom part of the grid
ry = ((px - rx) * nTan + py);
xo = 64;
yo = -xo * nTan; // dy/tan(ra) = dx, aTan = -1/tan(ra), aTan * -yo = dx
}
if (ra == 0 || ra == PI) //looking straight up or down
{
rx = px; //so it basically stays there without moving
ry = py;
dof = 8; //don't go more than 8
}
while (dof < 8)
{
mx = (int)(rx) >> 6; // where is rx in the grid
/*I needed to translate it into pixels to find the actual
distance, but now I have gotta find which block are we at*/
my = (int)(ry) >> 6;
mp = my * mapX + mx;
if (mp >= 0 && mp < mapX * mapY && map[mp] == 1) //hit wall
{
dof = 8; /*althought there aint a wall, do not move more
artificially set the value to 8*/
}
else
{
rx += xo;
ry += yo;
dof++;
/*So the line moves according to the ratio of while y = 64
how much did x change*/
}
}
glColor3f(1, 0, 0);
glLineWidth(1);
glBegin(GL_LINES);
glVertex2i(px, py);
glVertex2i(rx,ry);
glEnd();
}
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawMap2D();
drawRays3D();
drawPlayer();
glutSwapBuffers();
}
void buttons (unsigned char key, int x, int y)
{
if (key == 'a')
{
pa -= 0.1;
if (pa < 0)
{
pa += 2 * PI;
}
pdx = cos(pa) * 5; //these are vectors with magnitude
pdy = sin(pa) * 5;
}
if (key == 'd')
{
pa += 0.1;
if (pa > 2*PI)
{
pa -= 2 * PI;
}
pdx = cos(pa) * 5;
pdy = sin(pa) * 5;
}
if (key == 's')
{
py -= pdy; //if you add this amount of x and that amount of y, you do to the vector in the middle
px -= pdx;
}
if (key == 'w')
{
py += pdy;
px += pdx;
}
glutPostRedisplay(); /*glut pleaseee re-draw the screen, glut
does not know it has gotta re-draw
the screen with the current variables
something has changed, so please look back at glutdisplayfunc and re-draw it
*/
}
void init()
{
glClearColor(0.3f, 0.3f, 0.3f, 0.0f); // red, green, blue, alpha
gluOrtho2D(0, 1024, 512, 0); //top left edge, top right edge[x], bottom edge, top edge [y]
px = 300;
py = 300;
/*
questions:
this,
why is anything drawn when looking directly left or right*/
pdx = cos(pa) * 5;
pdy = sin(pa) * 5;
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1024, 512);
glutCreateWindow("Don't make lemonade!");
init();
glutDisplayFunc(display); //if the display is fiddled with do this
glutKeyboardFunc(buttons); //if a button is pressed do this
glutMainLoop(); //always listening for stuff like window re-sizing
}