From bce640219f209eab9aee266a80747218dec4a1de Mon Sep 17 00:00:00 2001 From: Sheldon Lee Date: Sun, 16 Apr 2023 02:17:11 +0100 Subject: [PATCH] Refactor 2D map drawing. 2D level represntation now drawn as minimap in it's own texture. --- camera.cpp | 62 ++---------------------------------- camera.h | 3 +- level.cpp | 88 ++++++++++++++++++++++----------------------------- level.h | 4 +-- main.cpp | 2 +- minimap.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ minimap.h | 10 ++++++ view.cpp | 28 ++++++++++------- 8 files changed, 162 insertions(+), 125 deletions(-) create mode 100644 minimap.cpp create mode 100644 minimap.h diff --git a/camera.cpp b/camera.cpp index 1f87b34..4af2a26 100644 --- a/camera.cpp +++ b/camera.cpp @@ -4,73 +4,17 @@ #include "level.h" #define ROTATION_SPEED PI -#define TRANSLATIONAL_SPEED 100.f +#define TRANSLATIONAL_SPEED 1.f -static void draw(Camera* camera, sf::RenderWindow* window); -static void drawRays(Camera* camera, sf::RenderWindow* window); -static void drawLine(sf::RenderWindow* window, sf::Vector2f pos, float angle, float length, sf::Color color); static void move(Camera* camera, float t); -void camera_update(Camera* camera, sf::RenderWindow* window, float t) +void camera_update(Camera* camera, float t) { - if (!camera || !window) return; + if (!camera) return; - draw(camera, window); move(camera, t); } -static void draw(Camera* camera, sf::RenderWindow* window) -{ - const float circleRadius = 5.f; - sf::CircleShape circle(circleRadius); - circle.setPosition(camera->pos); - circle.setOrigin(circleRadius, circleRadius); - circle.setFillColor(sf::Color::Green); - - drawRays(camera, window); - drawLine(window, camera->pos, camera->direction, 100, sf::Color::Red); - window->draw(circle); -} - -static void drawRays(Camera* camera, sf::RenderWindow* window) -{ - float rayDirection = 0; - float rayDirectionStep = camera->fov / (float)camera->resolution; - bool isOddResolution = (camera->resolution % 2); - float rayDirectionOffset = isOddResolution? 0 : rayDirectionStep / 2.f; - - for (unsigned int i = 0; i < camera->resolution; i++) { - if (isOddResolution && i == 0) - rayDirection = camera->direction; - else if (i % 2) - rayDirection = camera->direction - rayDirectionOffset; - else - rayDirection = camera->direction + rayDirectionOffset; - - float distance = level_rayCastDistance(camera->pos, rayDirection); - - drawLine(window, camera->pos, rayDirection, distance, sf::Color(150, 150, 100)); - - if ((i + isOddResolution) % 2) rayDirectionOffset += rayDirectionStep; - } -} - -static void drawLine(sf::RenderWindow* window, sf::Vector2f pos, float angle, float length, sf::Color color) -{ - if (!window) return; - - sf::Vector2f endOffset(length * cos(angle), length * sin(angle)); - sf::Vertex start(pos); - sf::Vertex end(pos + endOffset); - - start.color = color; - end.color = color; - - sf::Vertex line[] = { start, end }; - - window->draw(line, 2, sf::Lines); -} - static void move(Camera* camera, float t) { int forward = 0; diff --git a/camera.h b/camera.h index 5ae43ea..145b011 100644 --- a/camera.h +++ b/camera.h @@ -9,8 +9,9 @@ typedef struct float direction; unsigned int resolution; float fov; + float drawScale; } Camera; -void camera_update(Camera* camera, sf::RenderWindow* window, float t); +void camera_update(Camera* camera, float t); #endif diff --git a/level.cpp b/level.cpp index c89da22..b1d1842 100644 --- a/level.cpp +++ b/level.cpp @@ -6,35 +6,32 @@ #define WIDTH 5 #define HEIGHT 5 -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 drawGrid(sf::RenderTarget* renderTarget, unsigned int tileSize); +static void drawGridLine(sf::RenderTarget* renderTarget, float step, bool isHorizontal); +static sf::Vertex getGridLineVertex(float n, float maxDimension, bool isStart, bool isHorizontal); 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, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 1, - 0, 0, 0, 0, 0, - 0, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 1, 1, 1, }; -int level_init(sf::RenderWindow* renderWindow) +int level_init() { printf("level_init()\n"); - window = renderWindow; return 1; } -int level_update() +void level_update(sf::RenderTarget* renderTarget, unsigned int drawSize) { - if (!window) return 0; - drawGrid(); - return 1; + if (!renderTarget) return; + + drawGrid(renderTarget, drawSize/WIDTH); } void level_end() @@ -48,46 +45,41 @@ float level_rayCastDistance(sf::Vector2f point, float direction) return castRay(point, direction); } -static void drawGrid() +static void drawGrid(sf::RenderTarget* renderTarget, unsigned int tileSize) { - const sf::Vector2u windowSize = window->getSize(); - const unsigned int stepX = windowSize.x/WIDTH; - const unsigned int stepY = windowSize.y/HEIGHT; - for (unsigned int x = 0; x < WIDTH; x++) { for (unsigned int y = 0; y < HEIGHT; y++) { if (!level[y * HEIGHT + x]) continue; - sf::RectangleShape rectangle(sf::Vector2f(stepY, stepY)); - rectangle.setPosition(x * stepX, y * stepY); - - window->draw(rectangle); + sf::RectangleShape rectangle(sf::Vector2f(tileSize, tileSize)); + rectangle.setPosition((float)x * tileSize, (float)y * tileSize); + renderTarget->draw(rectangle); } } - drawGridLine(stepX, true); - drawGridLine(stepY, false); + drawGridLine(renderTarget, tileSize, true); + drawGridLine(renderTarget, tileSize, false); } -static void drawGridLine(unsigned int step, bool isHorizontal) +static void drawGridLine(sf::RenderTarget* renderTarget, float step, bool isHorizontal) { unsigned int lines = isHorizontal? WIDTH : HEIGHT; for (unsigned int n = 0; n < lines; n++) { if (n == 0) continue; - unsigned int offset = n * step; - unsigned int maxDimension = lines * step; + float offset = (float)n * step; + float maxDimension = (float)lines * step; sf::Vertex line[] = { getGridLineVertex(offset, maxDimension, true, isHorizontal), getGridLineVertex(offset, maxDimension, false, isHorizontal) }; - window->draw(line, 2, sf::Lines); + renderTarget->draw(line, 2, sf::Lines); } } -static sf::Vertex getGridLineVertex(unsigned int offset, unsigned int maxDimension, bool isStart, bool isHorizontal) +static sf::Vertex getGridLineVertex(float offset, float maxDimension, bool isStart, bool isHorizontal) { sf::Vertex start; sf::Vertex end; @@ -101,17 +93,14 @@ static sf::Vertex getGridLineVertex(unsigned int offset, unsigned int maxDimensi end = sf::Vertex(sf::Vector2f(maxDimension, offset)); } - start.color = sf::Color(100, 100, 100); - end.color = sf::Color(100, 100, 100); + sf::Color color(100, 100, 100); + start.color = color; + end.color = color; return isStart? start : end; } 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; - int indexX, indexY; getGridIndex(point, &indexX, &indexY); @@ -135,13 +124,13 @@ static float castRay(sf::Vector2f point, float direction) bool goingDown = direction < PI; int signDown = goingDown? 1 : -1; - float horizontalDy = (float)((indexY + goingDown) * tileHeight) - point.y; + float horizontalDy = (float)(indexY + goingDown) - point.y; float horizontalDx = horizontalDy/tan(direction); - float horizontalStepX = (float)(signDown * (tileWidth/tan(direction))); - float horizontalStepY = (float)(signDown * (int)tileHeight); + float horizontalStepX = ((float)signDown * (1.f/tan(direction))); + float horizontalStepY = (float)signDown; float horizontalProjectedX = point.x + horizontalDx; - float horizontalProjectedY = (indexY + goingDown) * tileHeight; + float horizontalProjectedY = indexY + goingDown; float horizontalDistCoeff = sin(direction); float horizontalRayDist = std::abs(horizontalDy/horizontalDistCoeff); @@ -150,18 +139,19 @@ static float castRay(sf::Vector2f point, float direction) bool goingRight = direction < PI; int signRight = goingRight? 1 : -1; - float verticalDx = (float)((indexX + goingRight) * tileWidth) - point.x; + float verticalDx = (float)(indexX + goingRight) - point.x; float verticalDy = -verticalDx/tan(direction); // y axis needs to be flipped - float verticalStepY = -(float)(signRight * (tileHeight/tan(direction))); // y axis also flipped here - float verticalStepX = (float)(signRight * (int)tileHeight); + float verticalStepY = -((float)signRight * (1.f/tan(direction))); // y axis also flipped here + float verticalStepX = (float)signRight; float verticalProjectedY = point.y + verticalDy; - float verticalProjectedX = (indexX + goingRight) * tileWidth; + float verticalProjectedX = indexX + goingRight; float verticalDistCoeff = sin(direction); float verticalRayDist = std::abs(verticalDx/verticalDistCoeff); - while (true) { + unsigned int tries = WIDTH * HEIGHT; + while (tries--) { 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); @@ -201,10 +191,8 @@ static float castRay(sf::Vector2f point, float direction) static void getGridIndex(sf::Vector2f point, int* x, int* y) { - const sf::Vector2u windowSize = window->getSize(); - - *x = point.x / (int)(windowSize.x / WIDTH); - *y = point.y / (int)(windowSize.y / HEIGHT); + *x = point.x; + *y = point.y; if (*x < 0 || WIDTH <= *x) *x = -1; if (*y < 0 || HEIGHT <= *y) *y = -1; diff --git a/level.h b/level.h index c4c5b9d..5724dc7 100644 --- a/level.h +++ b/level.h @@ -3,8 +3,8 @@ #include -int level_init(sf::RenderWindow* renderWindow); -int level_update(); +int level_init(); +void level_update(sf::RenderTarget* renderTarget, unsigned int drawSize); void level_end(); float level_rayCastDistance(sf::Vector2f point, float direction); diff --git a/main.cpp b/main.cpp index 7ecdd48..8030e68 100644 --- a/main.cpp +++ b/main.cpp @@ -4,7 +4,7 @@ int main() { - view_init(); + if (!view_init()) return 1; while (view_update()); view_end(); diff --git a/minimap.cpp b/minimap.cpp new file mode 100644 index 0000000..34d6d9d --- /dev/null +++ b/minimap.cpp @@ -0,0 +1,90 @@ +#include "minimap.h" +#include + +#include "maths.h" +#include "level.h" + +static void drawCamera(sf::RenderTarget* renderTarget, Camera* camera); +static void drawRays(sf::RenderTarget* renderTarget, Camera* camera); +static void drawLine(sf::RenderTarget* renderTarget, sf::Vector2f pos, float angle, float length, sf::Color color); + +static sf::RenderTexture minimap; + +static unsigned int minimapSize; + +int minimap_init(unsigned int size) +{ + printf("minimap_init()\n"); + minimapSize = size; + if (!minimap.create(size, size)) return 0; + level_init(); + return 1; +} + +void minimap_update(sf::RenderTarget* renderTarget, Camera* camera) +{ + if (!renderTarget || !camera) return; + minimap.clear(); + level_update(&minimap, minimapSize); + drawCamera(&minimap, camera); + minimap.display(); + + sf::Sprite sprite(minimap.getTexture()); + renderTarget->draw(sprite); +} + +static void drawCamera(sf::RenderTarget* renderTarget, Camera* camera) +{ + const sf::Vector2f scaledPos = camera->pos * camera->drawScale; + const float circleRadius = 0.02f * minimapSize; + sf::CircleShape circle(circleRadius); + circle.setPosition(scaledPos); + circle.setOrigin(circleRadius, circleRadius); + circle.setFillColor(sf::Color::Green); + + drawRays(renderTarget, camera); + drawLine(renderTarget, scaledPos, camera->direction, minimapSize / 5.f, sf::Color::Red); + renderTarget->draw(circle); +} + +static void drawRays(sf::RenderTarget* renderTarget, Camera* camera) +{ + const sf::Vector2f scaledPos = camera->pos * camera->drawScale; + + float rayDirection = 0; + float rayDirectionStep = camera->fov / (float)camera->resolution; + bool isOddResolution = (camera->resolution % 2); + float rayDirectionOffset = isOddResolution? 0 : rayDirectionStep / 2.f; + + for (unsigned int i = 0; i < camera->resolution; i++) { + if (isOddResolution && i == 0) + rayDirection = camera->direction; + else if (i % 2) + rayDirection = camera->direction - rayDirectionOffset; + else + rayDirection = camera->direction + rayDirectionOffset; + + float distance = level_rayCastDistance(camera->pos, rayDirection) * camera->drawScale; + + drawLine(renderTarget, scaledPos, rayDirection, distance, sf::Color(150, 150, 100)); + + if ((i + isOddResolution) % 2) rayDirectionOffset += rayDirectionStep; + } +} + +static void drawLine(sf::RenderTarget* renderTarget, sf::Vector2f pos, float angle, float length, sf::Color color) +{ + if (!renderTarget) return; + + sf::Vector2f endOffset(length * cos(angle), length * sin(angle)); + sf::Vertex start(pos); + sf::Vertex end(pos + endOffset); + + start.color = color; + end.color = color; + + sf::Vertex line[] = { start, end }; + + renderTarget->draw(line, 2, sf::Lines); +} + diff --git a/minimap.h b/minimap.h new file mode 100644 index 0000000..4c50837 --- /dev/null +++ b/minimap.h @@ -0,0 +1,10 @@ +#ifndef MINIMAP_H +#define MINIMAP_H + +#include +#include "camera.h" + +int minimap_init(unsigned int size); +void minimap_update(sf::RenderTarget* renderTarget, Camera* camera); + +#endif diff --git a/view.cpp b/view.cpp index 4a9f42b..69482ff 100644 --- a/view.cpp +++ b/view.cpp @@ -2,22 +2,26 @@ #include #include -#include "level.h" -#include "camera.h" #include "maths.h" +#include "camera.h" +#include "minimap.h" + +#define MINIMAP_SIZE 300 +#define HALF_MINIMAP_SIZE MINIMAP_SIZE/2.f +#define DRAW_SCALE MINIMAP_SIZE/5.f static int handleKeyCode(sf::Keyboard::Key key); -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(5.f/2.f, 5.f/2.f), 0.f, 300, 0.5f*PI, DRAW_SCALE }; -static Camera camera = { sf::Vector2f(300.f, 250.f), 0.f, 100, 2.0f*PI }; +static sf::Uint32 style = sf::Style::Titlebar; +static sf::RenderWindow window(sf::VideoMode(MINIMAP_SIZE + camera.resolution, MINIMAP_SIZE), "Raycasting", style); +static sf::Clock timer; int view_init() { printf("view_init()\n"); - level_init(&window); + minimap_init(MINIMAP_SIZE); return 1; } @@ -38,11 +42,12 @@ int view_update() } } - window.clear(); - sf::Time t = timer.restart(); - if (!level_update()) return 0; - camera_update(&camera, &window, t.asSeconds()); + + camera_update(&camera, t.asSeconds()); + + window.clear(); + minimap_update(&window, &camera); window.display(); return 1; @@ -51,7 +56,6 @@ int view_update() void view_end() { printf("view_end()\n"); - level_end(); window.close(); }