diff --git a/raycaster.c b/raycaster.c index a3b7c61..0b82724 100644 --- a/raycaster.c +++ b/raycaster.c @@ -7,9 +7,15 @@ #define PI3 3 * PI / 2 #define DR 0.0174533f // One degree in radians -#define gameHeight 160 #define gameWidth 320 -#define aspectRatio 3.2 +#define gameHeight 160 + +#define GAP 20 + +#define MAP_WIDTH (mapX * mapSize) +#define MAP_HEIGHT (mapY * mapSize) +#define TOTAL_WIDTH (MAP_WIDTH + GAP + gameWidth) +#define TOTAL_HEIGHT (MAP_HEIGHT > gameHeight ? MAP_HEIGHT : gameHeight) // 0° => 0 radians (RIGHT) // 90° => π/2 radians (TOP) @@ -17,8 +23,8 @@ // 270° => 3π/2 radians (BOTTOM) // 360° => 2π radians (RIGHT) -// * Player position (playerX, playerY), delta (pdx, pdy), and angle (pa) -float playerX, playerY, pdx, pdy, playerAngle; +// * Player position (playerX, playerY), delta (playerDeltaX, playerDeltaY), and angle (pa) +float playerX, playerY, playerDeltaX, playerDeltaY, playerAngle; // * Draw the player on the screen void drawPlayer() @@ -34,12 +40,12 @@ void drawPlayer() glLineWidth(3); glBegin(GL_LINES); glVertex2i(playerX, playerY); - glVertex2i(playerX + pdx * 5, playerY + pdy * 5); + glVertex2i(playerX + playerDeltaX * 5, playerY + playerDeltaY * 5); glEnd(); } // * Define the world -int mapX = 8, mapY = 8, mapS = 64; +int mapX = 8, mapY = 8, mapSize = 64; // clang-format off int map[] = @@ -75,15 +81,15 @@ void drawMap2D() glColor3f(0, 0, 0); } - xo = x * mapS; - yo = y * mapS; + xo = x * mapSize; + yo = y * mapSize; glBegin(GL_QUADS); // Draw each block; the +-1 creates the outline glVertex2i(xo + 1, yo + 1); - glVertex2i(xo + 1, yo + mapS - 1); - glVertex2i(xo + mapS - 1, yo + mapS - 1); - glVertex2i(xo + mapS - 1, yo + 1); + glVertex2i(xo + 1, yo + mapSize - 1); + glVertex2i(xo + mapSize - 1, yo + mapSize - 1); + glVertex2i(xo + mapSize - 1, yo + 1); glEnd(); } } @@ -334,27 +340,26 @@ void drawRays3D() // Correct the fish-eye effect float correctedAngle = playerAngle - rayAngle; - if (rayAngle < 0) + if (correctedAngle < 0) { - rayAngle += 2 * PI; + correctedAngle += 2 * PI; } - if (rayAngle > 2 * PI) + if (correctedAngle > 2 * PI) { - rayAngle -= 2 * PI; + correctedAngle -= 2 * PI; } disT = disT * cos(correctedAngle); - // The window will be 320x160 px (windowW x windowH) // The formula for each line height will be the cube size (64) times our // screen height, divided by the ray distance (disT). // The further away, the larger the distance and the shorter the final line // height will be. - float lineHeight = (mapS * gameWidth) / disT; - - // We need to offset the line to the middle of the screen - // That's the full window height, minus half the line height - float lineOffset = gameHeight - lineHeight / 2; + float lineHeight = (mapSize * gameHeight) / disT; + if (lineHeight > gameHeight) + { + lineHeight = gameHeight; + } // Let's make sure the line doesn't exceed our vertical space, so we cap it if (lineHeight > gameWidth) @@ -362,12 +367,21 @@ void drawRays3D() lineHeight = gameWidth; } + // We need to offset the line to the middle of the screen + // That's the full window height, minus half the line height + float lineOffset = (gameHeight / 2.0f) - (lineHeight / 2.0f); + + // Calculate dynamic column width and horizontal starting offset + float rayWidth = (float)gameWidth / 60.0f; + float rayX3D = MAP_WIDTH + GAP + (r * rayWidth); + // * Draw the "wall" line - glLineWidth(8); - glBegin(GL_LINES); - // Draw the line every 8th pixel, and shift the viewport to the right by 530 - glVertex2i(r * 8 + gameWidth + 210, lineOffset); - glVertex2i(r * 8 + gameWidth + 210, lineHeight + lineOffset); + // Draw solid wall column using QUADS instead of GL_LINES + glBegin(GL_QUADS); + glVertex2f(rayX3D, lineOffset); + glVertex2f(rayX3D + rayWidth, lineOffset); + glVertex2f(rayX3D + rayWidth, lineOffset + lineHeight); + glVertex2f(rayX3D, lineOffset + lineHeight); glEnd(); // * Increase the ray angle to draw the next ray @@ -415,8 +429,8 @@ void buttons(unsigned char key, int x, int y) // The values returned from sin() and cos() are very small, so we'll just // artificialy inflate them by multilying by 5. This is our actual movement. - pdx = cos(playerAngle) * 5.0f; - pdy = sin(playerAngle) * 5.0f; + playerDeltaX = cos(playerAngle) * 5.0f; + playerDeltaY = sin(playerAngle) * 5.0f; } // ? Move right @@ -429,8 +443,8 @@ void buttons(unsigned char key, int x, int y) playerAngle -= 2 * PI; } - pdx = cos(playerAngle) * 5.0f; - pdy = sin(playerAngle) * 5.0f; + playerDeltaX = cos(playerAngle) * 5.0f; + playerDeltaY = sin(playerAngle) * 5.0f; } // ? Move forward @@ -438,15 +452,15 @@ void buttons(unsigned char key, int x, int y) { // We change the X and Y values based on our delta, which is calculated // during our rotation. - playerX += pdx; - playerY += pdy; + playerX += playerDeltaX; + playerY += playerDeltaY; } // ? Move backwards if (key == 's') { - playerX -= pdx; - playerY -= pdy; + playerX -= playerDeltaX; + playerY -= playerDeltaY; } glutPostRedisplay(); } @@ -458,22 +472,24 @@ void init() // Sets the window to be 2D at a given size // gluOrtho2D(0, 1024, 512, 0); - gluOrtho2D(0, gameWidth * aspectRatio, gameHeight * aspectRatio, 0); + gluOrtho2D(0, TOTAL_WIDTH, TOTAL_HEIGHT, 0); - // Set the initial player location - playerX = 300; - playerY = 300; + // Spawn player centered in grid tile (1, 1) + playerX = 1.5f * mapSize; + playerY = 1.5f * mapSize; + + playerAngle = 0; // Calculate the initial player deltaX and deltaY - pdx = cos(playerAngle) * 5.0f; - pdy = sin(playerAngle) * 5.0f; + playerDeltaX = cos(playerAngle) * 5.0f; + playerDeltaY = sin(playerAngle) * 5.0f; } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - glutInitWindowSize(1024, 512); + glutInitWindowSize(TOTAL_WIDTH, TOTAL_HEIGHT); glutCreateWindow("Raycaster"); init();