From 8a49c12909da09c4fcca2e7a387bdc903e745ebb Mon Sep 17 00:00:00 2001 From: Jan Mrna Date: Sat, 4 Oct 2025 16:54:29 +0200 Subject: [PATCH] Refactor WorldPos, WindowsPos done --- cpp/src/entities.cpp | 1 - cpp/src/gameloop.cpp | 15 ++++++++--- cpp/src/map.cpp | 52 +++++++++++++++++++------------------ cpp/src/math.hpp | 22 +++++++++++----- cpp/src/pathfinder/gbfs.cpp | 2 +- cpp/src/pathfindingdemo.cpp | 6 ++--- cpp/src/pathfindingdemo.hpp | 3 +++ cpp/src/sprite.cpp | 4 +-- cpp/src/sprite.hpp | 4 +-- cpp/src/user_input.hpp | 7 +++-- cpp/src/window.cpp | 20 +++++++------- cpp/src/window.hpp | 8 +++--- cpp/test/test.cpp | 6 +++++ 13 files changed, 89 insertions(+), 61 deletions(-) diff --git a/cpp/src/entities.cpp b/cpp/src/entities.cpp index b8f78b8..d8e1ad2 100644 --- a/cpp/src/entities.cpp +++ b/cpp/src/entities.cpp @@ -5,7 +5,6 @@ #include "log.hpp" #include "math.hpp" #include "sprite.hpp" -#include "coorginates.hpp" Entity::Entity(WorldPos position) : m_Position(position) { LOG_DEBUG("spawning entity at position ", position); diff --git a/cpp/src/gameloop.cpp b/cpp/src/gameloop.cpp index 85d825e..0c0466f 100644 --- a/cpp/src/gameloop.cpp +++ b/cpp/src/gameloop.cpp @@ -26,10 +26,15 @@ void GameLoop::Run() { const auto &tiles = map.GetMapTiles(); for (size_t row = 0; row < tiles.size(); row++) { for (size_t col = 0; col < tiles[row].size(); col++) { + const auto& camera = m_Game->GetCamera(); // LOG_DEBUG("Drawing rect (", row, ", ", col, ")"); m_Window->DrawRect( - map.TileEdgeToWorld(TilePos{row, col}), - map.GetTileSize(), tiles[row][col]->R, tiles[row][col]->G, + camera.WorldToWindow( + map.TileEdgeToWorld( + TilePos{static_cast(row), static_cast(col)} + ) + ), + camera.WorldToWindow(map.GetTileSize()), tiles[row][col]->R, tiles[row][col]->G, tiles[row][col]->B, tiles[row][col]->A); } } @@ -37,13 +42,15 @@ void GameLoop::Run() { // draw the path, if it exists WorldPos start_pos = m_Game->GetPlayer()->GetPosition(); for (const auto& next_pos: m_Game->GetPath()) { - m_Window->DrawLine(start_pos, next_pos); + const auto& camera = m_Game->GetCamera(); + m_Window->DrawLine(camera.WorldToWindow(start_pos), camera.WorldToWindow(next_pos)); start_pos = next_pos; } // draw all the entities (player etc) for (auto &entity : m_Game->GetEntities()) { - m_Window->DrawSprite(entity->GetPosition(), entity->GetSprite()); + const auto& camera = m_Game->GetCamera(); + m_Window->DrawSprite(camera.WorldToWindow(entity->GetPosition()), entity->GetSprite()); } m_Window->Flush(); diff --git a/cpp/src/map.cpp b/cpp/src/map.cpp index aa48775..4ef7e51 100644 --- a/cpp/src/map.cpp +++ b/cpp/src/map.cpp @@ -17,23 +17,24 @@ Map::Map(int rows, int cols) : m_Cols(cols), m_Rows(rows) { } WorldPos Map::TileToWorld(TilePos p) const { - return WorldPos{(p.x + 0.5) * TILE_SIZE, (p.y + 0.5) * TILE_SIZE}; + return WorldPos{(p.x() + 0.5f) * TILE_SIZE, (p.y() + 0.5f) * TILE_SIZE}; } WorldPos Map::TileEdgeToWorld(TilePos p) const { - return WorldPos{p.x * TILE_SIZE, p.y * TILE_SIZE}; + return WorldPos{p.x() * TILE_SIZE, p.y() * TILE_SIZE}; } TilePos Map::WorldToTile(WorldPos p) const { - return TilePos{p.x / TILE_SIZE, p.y / TILE_SIZE}; + return TilePos{static_cast(p.x() / TILE_SIZE), static_cast(p.y() / TILE_SIZE)}; } +// TODO this should probably use something like WorldSize or WorldVec to make the distinction clear WorldPos Map::GetTileSize() const { return WorldPos{TILE_SIZE, TILE_SIZE}; } const Tile *Map::GetTileAt(TilePos p) const { assert(IsTilePosValid(p)); - size_t row = p.x; - size_t col = p.y; + size_t row = p.x(); + size_t col = p.y(); return m_Tiles[row][col]; } @@ -43,10 +44,10 @@ const Tile *Map::GetTileAt(WorldPos p) const { } bool Map::IsTilePosValid(TilePos p) const { - if (p.x < 0 || p.y < 0) + if (p.x() < 0 || p.y() < 0) return false; - size_t row = static_cast(p.x); - size_t col = static_cast(p.y); + size_t row = static_cast(p.x()); + size_t col = static_cast(p.y()); return row < m_Tiles.size() && col < m_Tiles[0].size(); } @@ -75,14 +76,14 @@ std::vector Map::GetNeighbors(TilePos center) const void Map::PaintCircle(TilePos center, unsigned radius, TileType tile_type) { // get rectangle that wraps the circle - TilePos corner1 = TilePos{center.x - radius, center.y - radius}; - TilePos corner2 = TilePos{center.x + radius, center.y + radius}; + TilePos corner1 = TilePos{center.x() - static_cast(radius), center.y() - static_cast(radius)}; + TilePos corner2 = TilePos{center.x() + static_cast(radius), center.y() + static_cast(radius)}; // iterate through all valid points, setting the type const unsigned radius_squared = radius * radius; - for (int x = corner1.x; x < corner2.x; x++) { - for (int y = corner1.y; y < corner2.y; y++) { + for (int x = corner1.x(); x < corner2.x(); x++) { + for (int y = corner1.y(); y < corner2.y(); y++) { TilePos current_tile = {x, y}; - unsigned distance_squared = center.distance_squared(current_tile); + unsigned distance_squared = static_cast(center.DistanceTo(current_tile) * center.DistanceTo(current_tile)); if (IsTilePosValid(current_tile) && distance_squared < radius_squared) { // y is row, x is col @@ -94,19 +95,20 @@ void Map::PaintCircle(TilePos center, unsigned radius, TileType tile_type) void Map::PaintLine(TilePos start_tile, TilePos stop_tile, double width, TileType tile_type) { - const Vec2D start(start_tile); - const Vec2D stop(stop_tile); - const double line_length = start.distance(stop); - const Vec2D step((stop-start)/line_length); - const Vec2D ortho = step.orthogonal(); + const vec start{static_cast(start_tile.x()), static_cast(start_tile.y())}; + const vec stop{static_cast(stop_tile.x()), static_cast(stop_tile.y())}; + const double line_length = start.DistanceTo(stop); + const vec step = (stop - start) / line_length; + const vec ortho = step.GetOrthogonal(); LOG_DEBUG("step = ", step, " ortho = ", ortho); for (double t = 0; t < line_length; t += 1.0) { for (double ortho_t = 0; ortho_t < width; ortho_t += 0.1) { auto tile_pos = start + step * t + ortho * ortho_t; - if (IsTilePosValid(tile_pos)) { - size_t row = static_cast(tile_pos.x); - size_t col = static_cast(tile_pos.y); + TilePos tile_pos_int{static_cast(tile_pos.x()), static_cast(tile_pos.y())}; + if (IsTilePosValid(tile_pos_int)) { + size_t row = static_cast(tile_pos.x()); + size_t col = static_cast(tile_pos.y()); m_Tiles[row][col] = &tile_types.at(tile_type); } } @@ -116,15 +118,15 @@ void Map::PaintLine(TilePos start_tile, TilePos stop_tile, double width, TileTyp void Map::PaintRectangle(TilePos first_corner, TilePos second_corner, TileType tile_type) { - std::initializer_list xvals = {first_corner.x, second_corner.x}; - std::initializer_list yvals = {first_corner.y, second_corner.y}; + std::initializer_list xvals = {first_corner.x(), second_corner.x()}; + std::initializer_list yvals = {first_corner.y(), second_corner.y()}; for (int x = std::min(xvals); x < std::max(xvals); x++) { for (int y = std::min(yvals); y < std::max(yvals); y++) { TilePos tile_pos{x,y}; LOG_DEBUG("tile_pos = ", tile_pos); if (IsTilePosValid(tile_pos)) { - size_t row = static_cast(tile_pos.x); - size_t col = static_cast(tile_pos.y); + size_t row = static_cast(tile_pos.x()); + size_t col = static_cast(tile_pos.y()); m_Tiles[row][col] = &tile_types.at(tile_type); } } diff --git a/cpp/src/math.hpp b/cpp/src/math.hpp index 01e900e..5d214b0 100644 --- a/cpp/src/math.hpp +++ b/cpp/src/math.hpp @@ -60,7 +60,15 @@ public: // binary operators // - friend bool operator==(const vec &a, const vec &b) { + friend bool operator==(const vec &a, const vec &b) + requires (std::is_integral_v) + { + return std::ranges::equal(a.m_Array, b.m_Array); + } + + friend bool operator==(const vec &a, const vec &b) + requires (std::is_floating_point_v) + { for (const auto &[u, v] : std::views::zip(a.m_Array, b.m_Array)) { if (!equalEpsilon(u, v)) { return false; @@ -72,21 +80,21 @@ public: friend bool operator!=(const vec &a, const vec &b) { return !(a == b); } friend vec operator+(const vec &a, const vec &b) { - vec c; + vec c; std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::plus{}); return c; } friend vec operator-(const vec &a, const vec &b) { - vec c; + vec c; std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::minus{}); return c; } friend vec operator*(const vec &a, const T &scalar) { - vec c; + vec c; std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::multiplies{}); return c; @@ -95,7 +103,7 @@ public: friend vec operator*(const T &scalar, const vec &a) { return a * scalar; } friend vec operator/(const vec &a, const T &scalar) { - vec c; + vec c; std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::divides{}); return c; @@ -124,7 +132,7 @@ public: // T LengthSquared() const { - return std::transform_reduce(m_Array.begin(), m_Array.end(), T{0.0}, + return std::transform_reduce(m_Array.begin(), m_Array.end(), T{}, std::plus{}, [](T x) { return x * x; }); } @@ -237,7 +245,7 @@ struct TileTag {}; // types for each domain using WorldPos = vec; using WindowPos = vec; -using TilePos = vec; +using TilePos = vec; // // Utils diff --git a/cpp/src/pathfinder/gbfs.cpp b/cpp/src/pathfinder/gbfs.cpp index 8b9bbfd..02684ca 100644 --- a/cpp/src/pathfinder/gbfs.cpp +++ b/cpp/src/pathfinder/gbfs.cpp @@ -11,7 +11,7 @@ namespace pathfinder { float GBFS::Heuristic(const TilePos& a, const TilePos& b) { - return static_cast(std::abs(a.x- b.x) + std::abs(a.y - b.y)); + return static_cast(std::abs(a.x() - b.x()) + std::abs(a.y() - b.y())); } Path GBFS::CalculatePath(WorldPos start_world, WorldPos end_world) diff --git a/cpp/src/pathfindingdemo.cpp b/cpp/src/pathfindingdemo.cpp index aa2b899..8fe7d8e 100644 --- a/cpp/src/pathfindingdemo.cpp +++ b/cpp/src/pathfindingdemo.cpp @@ -63,7 +63,7 @@ void PathFindingDemo::CreateMap() { } WorldPos PathFindingDemo::GetRandomPosition() const { - return WorldPos{0.0, 0.0}; // totally random! + return WorldPos{0.0f, 0.0f}; // totally random! } std::optional PathFindingDemo::GetMoveTarget() { @@ -75,7 +75,7 @@ std::optional PathFindingDemo::GetMoveTarget() { WorldPos next_player_pos = m_Path.front(); - if (current_player_pos.distance(next_player_pos) > 1.0) { + if (current_player_pos.DistanceTo(next_player_pos) > 1.0) { // target not reached yet return next_player_pos; } @@ -95,7 +95,7 @@ void PathFindingDemo::UpdatePlayerVelocity() { WorldPos velocity = WorldPos{}; if (next_pos) { velocity = next_pos.value() - current_pos; - velocity.normalize(); + velocity.Normalize(); //LOG_DEBUG("I want to move to: ", next_pos.value(), // ", velocity: ", velocity); } diff --git a/cpp/src/pathfindingdemo.hpp b/cpp/src/pathfindingdemo.hpp index 20532b3..9743c86 100644 --- a/cpp/src/pathfindingdemo.hpp +++ b/cpp/src/pathfindingdemo.hpp @@ -10,6 +10,7 @@ #include "map.hpp" #include "user_input.hpp" #include "pathfinder/base.hpp" +#include "camera.hpp" class PathFindingDemo { public: @@ -24,6 +25,7 @@ public: std::shared_ptr GetPlayer() { return m_Player; } std::vector>& GetEntities() { return m_Entities; } const Map& GetMap() const { return m_Map; } + const Camera& GetCamera() const { return m_Camera; } const pathfinder::Path& GetPath() const { return m_Path; } bool IsExitRequested() const { return m_ExitRequested; } @@ -37,6 +39,7 @@ public: private: bool m_ExitRequested = false; Map m_Map; + Camera m_Camera; std::vector> m_Entities; std::shared_ptr m_Player; pathfinder::Path m_Path; diff --git a/cpp/src/sprite.cpp b/cpp/src/sprite.cpp index 41b40ca..be5164f 100644 --- a/cpp/src/sprite.cpp +++ b/cpp/src/sprite.cpp @@ -12,13 +12,13 @@ Sprite::Sprite() : m_Texture(nullptr, SDL_DestroyTexture) {} -Sprite::Sprite(std::string path, Vec2D center) : Sprite() { +Sprite::Sprite(std::string path, WorldPos center) : Sprite() { LoadImage(path, center); } Sprite::~Sprite() { LOG_DEBUG("."); } -void Sprite::LoadImage(std::string path, Vec2D image_center) { +void Sprite::LoadImage(std::string path, WorldPos image_center) { LOG_INFO("Loading image ", path); assert(m_Renderer != nullptr); diff --git a/cpp/src/sprite.hpp b/cpp/src/sprite.hpp index fd86167..5b9b7e6 100644 --- a/cpp/src/sprite.hpp +++ b/cpp/src/sprite.hpp @@ -14,7 +14,7 @@ class Sprite { public: Sprite(); ~Sprite(); - explicit Sprite(std::string path, WorldPos center = {0, 0}); + explicit Sprite(std::string path, WorldPos center = WorldPos{}); Sprite(const Sprite &) = delete; Sprite &operator=(const Sprite &) = delete; @@ -28,7 +28,7 @@ public: WorldPos GetSize() const { return m_Size; } WorldPos GetCenter() const { return m_ImageCenter; } - void LoadImage(std::string path, WorldPos image_center = {0.0, 0.0}); + void LoadImage(std::string path, WorldPos image_center = WorldPos{}); private: static std::shared_ptr m_Renderer; diff --git a/cpp/src/user_input.hpp b/cpp/src/user_input.hpp index 2ea98b5..5c328a5 100644 --- a/cpp/src/user_input.hpp +++ b/cpp/src/user_input.hpp @@ -11,8 +11,8 @@ class UserAction { public: enum class Type { NONE, EXIT, SET_MOVE_TARGET, SELECT_PATHFINDER }; - UserAction() = default; - UserAction(Type t) : type(t) {} + UserAction() : type(Type::NONE), Argument{.number = 0} {} + UserAction(Type t) : type(t), Argument{.number = 0} {} UserAction(Type t, char key) : type(t), Argument{.key = key} {} UserAction(Type t, WorldPos v) : type(t), Argument{.position = v} {} UserAction(Type t, int arg) : type(t), Argument{.number = arg} {} @@ -25,6 +25,9 @@ public: char key; int number; } Argument; + + // TODO use std::variant + //std::variant Argument; }; class UserInput { diff --git a/cpp/src/window.cpp b/cpp/src/window.cpp index a488258..27f013e 100644 --- a/cpp/src/window.cpp +++ b/cpp/src/window.cpp @@ -76,17 +76,17 @@ Window::~Window() { LOG_DEBUG("."); } -void Window::DrawSprite(const WorldPos &position, Sprite &s) { +void Window::DrawSprite(const WindowPos &position, Sprite &s) { WorldPos size = s.GetSize(); WorldPos img_center = s.GetCenter(); - SDL_FRect rect = {position.x - img_center.x, position.y - img_center.y, - size.x, size.y}; + SDL_FRect rect = {position.x() - img_center.x(), position.y() - img_center.y(), + size.x(), size.y()}; SDL_RenderTexture(m_Renderer.get(), s.GetTexture(), nullptr, &rect); } -void Window::DrawRect(const WorldPos &position, const WorldPos size, uint8_t R, +void Window::DrawRect(const WindowPos &position, const WindowPos size, uint8_t R, uint8_t G, uint8_t B, uint8_t A) { - SDL_FRect rect = {position.x, position.y, size.x, size.y}; + SDL_FRect rect = {position.x(), position.y(), size.x(), size.y()}; SDL_SetRenderDrawColor(m_Renderer.get(), R, G, B, A); SDL_RenderFillRect(m_Renderer.get(), &rect); } @@ -98,9 +98,9 @@ void Window::ClearWindow() { void Window::Flush() { SDL_RenderPresent(m_Renderer.get()); } -void Window::DrawCircle(const WorldPos &position, float radius) { - int cx = static_cast(position.x); - int cy = static_cast(position.y); +void Window::DrawCircle(const WindowPos &position, float radius) { + int cx = static_cast(position.x()); + int cy = static_cast(position.y()); SDL_SetRenderDrawColor(m_Renderer.get(), 255, 0, 0, 255); for (int i = 0; i < 360; ++i) { double a = i * M_PI / 180.0; @@ -110,9 +110,9 @@ void Window::DrawCircle(const WorldPos &position, float radius) { } } -void Window::DrawLine(const WorldPos &A, const WorldPos &B) +void Window::DrawLine(const WindowPos &A, const WindowPos &B) { SDL_SetRenderDrawColor(m_Renderer.get(), 255, 0, 0, 255); - SDL_RenderLine(m_Renderer.get(), A.x, A.y, B.x, B.y); + SDL_RenderLine(m_Renderer.get(), A.x(), A.y(), B.x(), B.y()); } diff --git a/cpp/src/window.hpp b/cpp/src/window.hpp index 8813747..cd39983 100644 --- a/cpp/src/window.hpp +++ b/cpp/src/window.hpp @@ -22,13 +22,13 @@ public: Window &operator=(Window &&) = delete; std::expected Init(); - void DrawSprite(const WorldPos &position, Sprite &s); - void DrawRect(const WorldPos &position, const WorldPos size, uint8_t R, + void DrawSprite(const WindowPos &position, Sprite &s); + void DrawRect(const WindowPos &position, const WindowPos size, uint8_t R, uint8_t G, uint8_t B, uint8_t A); void ClearWindow(); void Flush(); - void DrawCircle(const WorldPos &position, float radius); - void DrawLine(const WorldPos &A, const WorldPos &B); + void DrawCircle(const WindowPos &position, float radius); + void DrawLine(const WindowPos &A, const WindowPos &B); private: uint32_t m_Width; diff --git a/cpp/test/test.cpp b/cpp/test/test.cpp index c7d4523..1f45431 100644 --- a/cpp/test/test.cpp +++ b/cpp/test/test.cpp @@ -37,6 +37,12 @@ TEST(vec, equalEpsilon) { ASSERT_EQ(v1, v2); } +TEST(vec, equalInt) { + ivec2 v1{1,2}; + ivec2 v2{1,2}; + ASSERT_EQ(v1, v2); +} + TEST(vec, nonEqualEpsilon) { // Test operator!= vec3 v1{1.0f, 2.0f, 3.0f};