diff --git a/camera.cpp b/camera.cpp index 436bffe..1f87b34 100644 --- a/camera.cpp +++ b/camera.cpp @@ -49,7 +49,7 @@ static void drawRays(Camera* camera, sf::RenderWindow* window) float distance = level_rayCastDistance(camera->pos, rayDirection); - drawLine(window, camera->pos, rayDirection, distance, sf::Color::Blue); + drawLine(window, camera->pos, rayDirection, distance, sf::Color(150, 150, 100)); if ((i + isOddResolution) % 2) rayDirectionOffset += rayDirectionStep; } diff --git a/level.cpp b/level.cpp index 199f38b..c89da22 100644 --- a/level.cpp +++ b/level.cpp @@ -10,17 +10,17 @@ static void drawGrid(); static void drawGridLine(unsigned int step, bool isHorizontal); static sf::Vertex getGridLineVertex(unsigned int n, unsigned int maxDimension, bool isStart, bool isHorizontal); -static void castRay(sf::Vector2f point, float direction); +static float castRay(sf::Vector2f point, float direction); static void getGridIndex(sf::Vector2f point, int* x, int* y); static sf::RenderWindow* window = nullptr; static unsigned int level[WIDTH * HEIGHT] = { 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, - 1, 0, 1, 0, 1, - 1, 0, 0, 0, 0, - 1, 0, 1, 0, 1, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, }; int level_init(sf::RenderWindow* renderWindow) @@ -45,8 +45,7 @@ void level_end() float level_rayCastDistance(sf::Vector2f point, float direction) { - castRay(point, direction); - return 1000.f; + return castRay(point, direction); } static void drawGrid() @@ -107,73 +106,97 @@ static sf::Vertex getGridLineVertex(unsigned int offset, unsigned int maxDimensi return isStart? start : end; } -static void castRay(sf::Vector2f point, float direction) +static float castRay(sf::Vector2f point, float direction) { const sf::Vector2u windowSize = window->getSize(); const unsigned int tileWidth = windowSize.x/WIDTH; const unsigned int tileHeight = windowSize.y/HEIGHT; - // dx and dy are the delta x and delta y of closest grid intersection int indexX, indexY; - float dx, dy; - getGridIndex(point, &indexX, &indexY); - direction = maths_modulo(direction, 2.0f*PI); + // The horizontal* and vertical* variables correspond to variables, that + // are used to calculate the horizontal and vertical grid intersection points + // respectively. The horizontal and vertical grid intersections are done + // separately. + // + // The *Dy and *Dx variables are the deltas to the nearest grid boundary. + // + // The *StepX and *StepY variables are the regular x and y steps from the + // initial boundary intersection along the ray. + // + // The *ProjectedX and *ProjectedY variables are projected coordinates of the + // grid intersections along the ray. + // + // The *DistCoeff variables store the coefficient of sin(direction) used to + // calculate distance travelled along the ray, without having to do extra + // calls to sin(), as the direction doesn't change. + direction = maths_modulo(direction, 2.0f*PI); // modulo to keep the angle between 0 and 2 PI radians bool goingDown = direction < PI; int signDown = goingDown? 1 : -1; - dy = (float)((indexY + goingDown) * tileHeight) - point.y; - dx = dy/tan(direction); + float horizontalDy = (float)((indexY + goingDown) * tileHeight) - point.y; + float horizontalDx = horizontalDy/tan(direction); float horizontalStepX = (float)(signDown * (tileWidth/tan(direction))); float horizontalStepY = (float)(signDown * (int)tileHeight); - float horizontalProjectedX = point.x + dx; + float horizontalProjectedX = point.x + horizontalDx; float horizontalProjectedY = (indexY + goingDown) * tileHeight; - direction = maths_modulo(direction + 0.5f*PI, 2.0f*PI); + float horizontalDistCoeff = sin(direction); + float horizontalRayDist = std::abs(horizontalDy/horizontalDistCoeff); + + direction = maths_modulo(direction + 0.5f*PI, 2.0f*PI); // rotate angle by 90 degrees for ease of calaculation bool goingRight = direction < PI; int signRight = goingRight? 1 : -1; - dx = (float)((indexX + goingRight) * tileWidth) - point.x; - dy = -dx/tan(direction); + float verticalDx = (float)((indexX + goingRight) * tileWidth) - point.x; + float verticalDy = -verticalDx/tan(direction); // y axis needs to be flipped - float verticalStepY = -(float)(signRight * (tileHeight/tan(direction))); + float verticalStepY = -(float)(signRight * (tileHeight/tan(direction))); // y axis also flipped here float verticalStepX = (float)(signRight * (int)tileHeight); - float verticalProjectedY = point.y + dy; + float verticalProjectedY = point.y + verticalDy; float verticalProjectedX = (indexX + goingRight) * tileWidth; - bool inLevel; - do { - const float circleRadius = 3.f; - sf::CircleShape circle(circleRadius); + float verticalDistCoeff = sin(direction); + float verticalRayDist = std::abs(verticalDx/verticalDistCoeff); - circle.setFillColor(sf::Color::Red); - - circle.setPosition(sf::Vector2f(horizontalProjectedX, horizontalProjectedY)); - circle.setOrigin(circleRadius, circleRadius); - window->draw(circle); - - circle.setPosition(sf::Vector2f(verticalProjectedX, verticalProjectedY)); - circle.setOrigin(circleRadius, circleRadius); - window->draw(circle); - - horizontalProjectedX += horizontalStepX; - horizontalProjectedY += horizontalStepY; - - verticalProjectedX += verticalStepX; - verticalProjectedY += verticalStepY; - - int indexX0, indexY0; - int indexX1, indexY1; + while (true) { + int indexX0, indexY0; // store grid indices for horizontal intersections + int indexX1, indexY1; // store grid indices for vertical intersections getGridIndex(sf::Vector2f(horizontalProjectedX, horizontalProjectedY), &indexX0, &indexY0); getGridIndex(sf::Vector2f(verticalProjectedX, verticalProjectedY), &indexX1, &indexY1); - bool inLevel0 = ((indexX0 >= 0 && indexX0 < WIDTH) && (indexY0 >= 0 && indexY0 < HEIGHT)); - bool inLevel1 = ((indexX1 >= 0 && indexX1 < WIDTH) && (indexY1 >= 0 && indexY1 < HEIGHT)); + // If the ray going up or to left, the intersection points will give an index + // of the cells below or to the right of the cell boundaries. For those cases, + // the appropriate indices will be reduced by one. + indexY0 -= !goingDown; + indexX1 -= !goingRight; - inLevel = inLevel0 || inLevel1; - } while (inLevel); + bool inLevel0 = indexX0 != -1 && indexY0 != -1; + bool inLevel1 = indexX1 != -1 && indexY1 != -1; + + if (!(inLevel0 || inLevel1)) break; + + if (horizontalRayDist < verticalRayDist) { + if (level[indexY0 * WIDTH + indexX0]) return horizontalRayDist; + + horizontalProjectedX += horizontalStepX; + horizontalProjectedY += horizontalStepY; + + horizontalRayDist += std::abs(horizontalStepY/horizontalDistCoeff); + } + else { + if (level[indexY1 * WIDTH + indexX1]) return verticalRayDist; + + verticalProjectedX += verticalStepX; + verticalProjectedY += verticalStepY; + + verticalRayDist += std::abs(verticalStepX/verticalDistCoeff); + } + }; + + return 1000.f; } static void getGridIndex(sf::Vector2f point, int* x, int* y) diff --git a/view.cpp b/view.cpp index 3a40a0d..4a9f42b 100644 --- a/view.cpp +++ b/view.cpp @@ -12,7 +12,7 @@ static sf::Uint32 style = sf::Style::Titlebar; static sf::RenderWindow window(sf::VideoMode(500, 500), "Raycasting", style); static sf::Clock timer; -static Camera camera = { sf::Vector2f(300.f, 250.f), 0.f, 50, 2.0f*PI }; +static Camera camera = { sf::Vector2f(300.f, 250.f), 0.f, 100, 2.0f*PI }; int view_init() {