#include "raycaster.h" #include "constants.h" GLdouble degToRad(GLdouble a) { return a * 3.14159 / 180; } float calculateWallDistance(GLfloat* positions, float rayAngle) { float px = (positions[0] + 1.0f) / tileSize; float py = (1.0f - positions[1]) / tileSize; float rayDirX = sinf(degToRad(rayAngle)); float rayDirY = -cosf(degToRad(rayAngle)); int mapXpos = static_cast<int>(px); int mapYpos = static_cast<int>(py); float deltaDistX = (fabsf(rayDirX) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirX); float deltaDistY = (fabsf(rayDirY) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirY); int stepX, stepY; float sideDistX, sideDistY; if (rayDirX < 0) { stepX = -1; sideDistX = (px - mapXpos) * deltaDistX; } else { stepX = 1; sideDistX = (mapXpos + 1.0f - px) * deltaDistX; } if (rayDirY < 0) { stepY = -1; sideDistY = (py - mapYpos) * deltaDistY; } else { stepY = 1; sideDistY = (mapYpos + 1.0f - py) * deltaDistY; } bool hit = false; int side = 0; // 0: x-side, 1: y-side while (!hit) { if (sideDistX < sideDistY) { sideDistX += deltaDistX; mapXpos += stepX; side = 0; } else { sideDistY += deltaDistY; mapYpos += stepY; side = 1; } if (mapXpos < 0 || mapXpos >= mapX || mapYpos < 0 || mapYpos >= mapY) { return 1e30f; // No wall hit } if (map[mapYpos * mapX + mapXpos] == 1) { hit = true; } } float perpWallDist; if (side == 0) { perpWallDist = (sideDistX - deltaDistX); } else { perpWallDist = (sideDistY - deltaDistY); } return perpWallDist; } void drawLine(Renderer& renderer, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, Renderer::ColorRGB color) { GLfloat width = 0.0025f; Renderer::QuadVertices quadVertices = { x1 + width, y1 + width, // Top right x2 + width, y2 - width, // Bottom right x1 - width, y1 + width, // Top left x2 - width, y2 - width // Bottom left }; renderer.drawQuad(quadVertices, color, 0); } void drawMap(Renderer& renderer) { for (int y = 0; y < mapY; y++) { for (int x = 0; x < mapX; x++) { if (map[y * mapX + x] == 1) { GLfloat x0 = -1.0f + x * tileSize; GLfloat y0 = 1.0f - y * tileSize; GLfloat x1 = x0 + tileSize; GLfloat y1 = y0 - tileSize; Renderer::QuadVertices quadVertices = { x1, y0, x1, y1, x0, y0, x0, y1 }; Renderer::ColorRGB quadColor = Renderer::ColorRGB(0, 0, 0); renderer.drawQuad(quadVertices, quadColor, 0); } } } } GLfloat drawRaycastLine(Renderer& renderer, double rayAngle, double playerAngleX, double playerAngleY, GLfloat *positions) { //player angle is direction of our player //ray angle is angle at which we do raycast float px = (positions[0] + 1.0f) / tileSize; float py = (1.0f - positions[1]) / tileSize; float rayDirX = sinf(degToRad(rayAngle)); float rayDirY = -cosf(degToRad(rayAngle)); int mapplayerAngle = static_cast<int>(px); int mapYpos = static_cast<int>(py); float deltaDistX = (fabsf(rayDirX) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirX); float deltaDistY = (fabsf(rayDirY) < 0.00001f) ? 1e30f : fabsf(1.0f / rayDirY); int stepX, stepY; float sideDistX, sideDistY; float perpWallDist; if (rayDirX < 0) { stepX = -1; sideDistX = (px - mapplayerAngle) * deltaDistX; } else { stepX = 1; sideDistX = (mapplayerAngle + 1.0f - px) * deltaDistX; } if (rayDirY < 0) { stepY = -1; sideDistY = (py - mapYpos) * deltaDistY; } else { stepY = 1; sideDistY = (mapYpos + 1.0f - py) * deltaDistY; } bool hit = false; int side = 0; // 0: x-side, 1: y-side float rayLength = 0.0f; while (!hit) { if (sideDistX < sideDistY) { mapplayerAngle += stepX; rayLength = sideDistX; sideDistX += deltaDistX; side = 0; } else { mapYpos += stepY; rayLength = sideDistY; sideDistY += deltaDistY; side = 1; } if (mapplayerAngle < 0 || mapplayerAngle >= mapX || mapYpos < 0 || mapYpos >= mapY) { break; } if (map[mapYpos * mapX + mapplayerAngle] == 1) { hit = true; } } float hitX = px + rayDirX * rayLength; // positions for world float hitY = py + rayDirY * rayLength; float normHitX = hitX * tileSize - 1.0f; // positions for the map float normHitY = 1.0f - hitY * tileSize; if (side == 0) { perpWallDist = (sideDistX - deltaDistX); } else { perpWallDist = (sideDistY - deltaDistY); } float screenX = -1.0f + (rayAngle - (playerAngleX - (0.5 * RAY_NUM))) * angularSlice; // position on screen considering input angle float lineHeight = 2.0f / perpWallDist * 0.5f; // height considering distance from camera float lineStart = -lineHeight + (playerAngleY * 0.03f); float lineEnd = lineHeight + (playerAngleY * 0.03f); int wallColor = (side == 0) ? 200 : 150; // draw wall line renderer.drawQuad( Renderer::QuadVertices{ screenX, lineStart, screenX, lineEnd, screenX + angularSlice, lineStart, screenX + angularSlice, lineEnd }, Renderer::ColorRGB(wallColor, 0, 0), 0 ); drawLine(renderer, positions[0], positions[1], normHitX, normHitY, Renderer::ColorRGB(0, 200, 0)); return perpWallDist; } bool drawPlayer(Renderer& renderer, float relativeAngle, float angleToOther, double playerAngleY, GLfloat *otherPlayerPositions, GLfloat * positions, int health) { if (fabs(relativeAngle) <= (RAY_NUM / 2)) { //drawLine(positions[0], positions[1], otherPlayerPositions[0], otherPlayerPositions[1], shaderProgram, 3); float playerDistance = (sqrt(pow((otherPlayerPositions[0] - positions[0]), 2) + pow((otherPlayerPositions[1] - positions[1]), 2))) / tileSize; float angleToOtherDegrees = angleToOther * (180.0f / 3.14159f); //float wallDistance = drawRaycastLine(renderer, angleToOtherDegrees, angleToOtherDegrees, positions); float wallDistance = calculateWallDistance(positions, angleToOtherDegrees); //cout << "wallDistance = " << wallDistance << " playerDistance = " << playerDistance << " angleToOtherDegrees = " << angleToOtherDegrees << endl; if (playerDistance <= wallDistance) { float screenX = (relativeAngle / (RAY_NUM * 0.5f)); float CHARACTER_SIZE = (0.1f / playerDistance); float Ystart = (0.6 / playerDistance) + (playerAngleY * 0.03f); float Yend = (-0.9 / playerDistance) + (playerAngleY * 0.03f); float Ystartbar = (0.8 / playerDistance) + (playerAngleY * 0.03f); float Yendbar = (0.7 / playerDistance) + (playerAngleY * 0.03f); float startPlus = Ystartbar + (0.008f); float endPlus = Yendbar - (0.008f); //onscreen player renderer.drawQuad( Renderer::QuadVertices{ screenX - CHARACTER_SIZE, Ystart, screenX + CHARACTER_SIZE, Ystart, screenX - CHARACTER_SIZE, Yend, screenX + CHARACTER_SIZE, Yend }, Renderer::ColorRGB(0, 0, 255), 2 ); // Health bar background renderer.drawQuad( Renderer::QuadVertices{ screenX - (2.05f * CHARACTER_SIZE), startPlus, screenX + (2.05f * CHARACTER_SIZE), startPlus, screenX - (2.05f * CHARACTER_SIZE), endPlus, screenX + (2.05f * CHARACTER_SIZE), endPlus }, Renderer::ColorRGB(0, 0, 0), 0 ); // Health bar renderer.drawQuad( Renderer::QuadVertices{ screenX - (2.0f * CHARACTER_SIZE), Ystartbar, screenX + (2.0f * CHARACTER_SIZE), Ystartbar, screenX - (2.0f * CHARACTER_SIZE), Yendbar, screenX + (2.0f * CHARACTER_SIZE), Yendbar }, Renderer::ColorRGB(0, 255, 0), 0 ); // Health bar current renderer.drawQuad( Renderer::QuadVertices{ screenX + (2.0f * CHARACTER_SIZE), Ystartbar, screenX + (2.0f * CHARACTER_SIZE * (1.0f - static_cast<float>(health) * 2 / maxHealth)), Ystartbar, screenX + (2.0f * CHARACTER_SIZE), Yendbar, screenX + (2.0f * CHARACTER_SIZE * (1.0f - static_cast<float>(health) * 2 / maxHealth)), Yendbar }, Renderer::ColorRGB(255, 0, 0), 0 ); // drawPlayerQuad renderer.drawQuad( Renderer::QuadVertices{ positions[0] + PLAYER_SIZE, positions[1] + PLAYER_SIZE, positions[0] + PLAYER_SIZE, positions[1] - PLAYER_SIZE, positions[0] - PLAYER_SIZE, positions[1] + PLAYER_SIZE, positions[0] - PLAYER_SIZE, positions[1] - PLAYER_SIZE }, Renderer::ColorRGB(0, 0, 255), 0 ); // drawCrosshair renderer.drawQuad( Renderer::QuadVertices{ 0.01f, 0.01f, 0.01f, -0.01f, -0.01f, 0.01f, -0.01f, -0.01f }, Renderer::ColorRGB(255, 255, 255), 0 ); return true; } } return false; } void drawPlayerQuad(Renderer& renderer, GLfloat* positions, Renderer::ColorRGB color) { Renderer::QuadVertices quadVertices = { positions[0] + PLAYER_SIZE, positions[1] + PLAYER_SIZE, positions[0] + PLAYER_SIZE, positions[1] - PLAYER_SIZE, positions[0] - PLAYER_SIZE, positions[1] + PLAYER_SIZE, positions[0] - PLAYER_SIZE, positions[1] - PLAYER_SIZE }; renderer.drawQuad(quadVertices, color, 2); } void drawCrosshair(Renderer& renderer, Renderer::ColorRGB color) { Renderer::QuadVertices quadVertices = { 0.01f, 0.01f, // Top right 0.01f, -0.01f, // Bottom right -0.01f, 0.01f, // Top left -0.01f, -0.01f // Bottom left }; renderer.drawQuad(quadVertices, color, 2); }