diff --git a/cpp/src/array.hpp b/cpp/src/array.hpp index 3100794..6631018 100644 --- a/cpp/src/array.hpp +++ b/cpp/src/array.hpp @@ -4,7 +4,7 @@ #include #include -namespace array { // TODO rename to container or something +namespace array { template concept Deletable = requires(U u) { @@ -148,7 +148,6 @@ public: private: pair_t *m_Pool = nullptr; - // TODO use unique_ptr std::stack m_FreeIdx; size_t m_Capacity = 0; diff --git a/cpp/src/camera.hpp b/cpp/src/camera.hpp index 37b2527..843d710 100644 --- a/cpp/src/camera.hpp +++ b/cpp/src/camera.hpp @@ -28,7 +28,6 @@ public: } private: - // TODO this should be replaced with a matrix float m_Zoom = 1.0f; WorldPos m_Pan; }; diff --git a/cpp/src/gameloop.cpp b/cpp/src/gameloop.cpp index 8d7b9b0..6735228 100644 --- a/cpp/src/gameloop.cpp +++ b/cpp/src/gameloop.cpp @@ -63,16 +63,12 @@ void GameLoop::Draw() { } } -// TODO rethink coupling and dependencies in the game loop class - void GameLoop::Run() { LOG_INFO("Running the game"); while (!m_Game->IsExitRequested()) { m_Game->HandleActions(m_UserInput->GetActions()); m_Game->UpdateWorld(); - // TODO measure fps, draw only if delay for target fps was reached - // or create a separate thread for drawing m_Window->ClearWindow(); Draw(); m_Window->Flush(); diff --git a/cpp/src/math.hpp b/cpp/src/math.hpp index d496a5d..74c749c 100644 --- a/cpp/src/math.hpp +++ b/cpp/src/math.hpp @@ -7,16 +7,11 @@ #include #include #include +#include #include #include #include -#ifdef _WIN32 -#include -#define M_PI std::numbers::pi -// TODO use std::numbers::pi instead of M_PI -#endif - template requires std::floating_point static inline bool equalEpsilon(const T &a, const T &b) { @@ -174,8 +169,6 @@ public: vec &a = *this; auto b = std::views::repeat(scalar); std::ranges::transform(a.m_Array, b, a.m_Array.begin(), std::divides{}); - // TODO check all of this, could be done better with views instead of - // ranges? return a; } diff --git a/cpp/src/pathfindingdemo.cpp b/cpp/src/pathfindingdemo.cpp index a75cea2..3897639 100644 --- a/cpp/src/pathfindingdemo.cpp +++ b/cpp/src/pathfindingdemo.cpp @@ -23,7 +23,6 @@ PathFindingDemo::PathFindingDemo(int width, int height) : m_Map(width, height) { PathFindingDemo::~PathFindingDemo() { LOG_DEBUG("."); } void PathFindingDemo::AddEntity(std::shared_ptr e) { - // TODO emplace_back m_Entities.push_back(e); } @@ -71,11 +70,6 @@ void PathFindingDemo::CreateMap() { AddEntity(p); } } - - // select everything - TODO this is just temporary for testing - for (const auto &entity : m_Entities) { - m_SelectedEntities.push_back(entity); - } } WorldPos PathFindingDemo::GetRandomPosition() const { @@ -121,8 +115,6 @@ void PathFindingDemo::UpdateWorld() { entity->SetActualVelocity(velocity * tile_velocity_coeff); for (const auto &collision : GetEntityCollisions()) { - // TODO this loop is quite "hot", is it good idea to use weak_ptr and - // promote it? auto weak_A = std::get<0>(collision); auto weak_B = std::get<1>(collision); auto A = weak_A.lock(); @@ -136,8 +128,6 @@ void PathFindingDemo::UpdateWorld() { // LOG_DEBUG("Collision: A is ", A, ", B is ", B); auto AB = B->GetPosition() - A->GetPosition(); A->ZeroActualVelocityInDirection(AB); - // handle logic - // TODO } // update the position @@ -211,7 +201,6 @@ void PathFindingDemo::DeselectEntities() { void PathFindingDemo::SelectEntitiesInRectangle(WorldPos A, WorldPos B) { DeselectEntities(); - // TODO use colliders for this auto [x_min, x_max] = std::minmax(A.x(), B.x()); auto [y_min, y_max] = std::minmax(A.y(), B.y()); for (const auto &entity : m_Entities) { diff --git a/cpp/src/positional_container.hpp b/cpp/src/positional_container.hpp index 51419b1..f306891 100644 --- a/cpp/src/positional_container.hpp +++ b/cpp/src/positional_container.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include #include +#include +#include #include +#include +#include -#include "math.hpp" #include "log.hpp" +#include "math.hpp" template concept HasPosition = requires(T t, WorldPos pos) { @@ -17,54 +17,42 @@ concept HasPosition = requires(T t, WorldPos pos) { }; template -concept HasCollisions = requires(T t) { - t.Dummy(); // TODO -}; + requires HasPosition -template -requires HasPosition - -class IPositionalContainer -{ +class IPositionalContainer { public: virtual ~IPositionalContainer() = default; virtual bool Add(std::shared_ptr t) = 0; - virtual std::vector> Get(const WorldPos& p, float radius) = 0; + virtual std::vector> Get(const WorldPos &p, + float radius) = 0; virtual void UpdateAll() = 0; virtual void Update(std::shared_ptr item) = 0; }; - template -class IColliderContainer : public IPositionalContainer -{ +class IColliderContainer : public IPositionalContainer { public: virtual std::vector> GetCollisions() = 0; }; -template -class SimpleContainer : IPositionalContainer -{ +template class SimpleContainer : IPositionalContainer { public: - bool Add(std::shared_ptr t) override - { + bool Add(std::shared_ptr t) override { m_Items.push_back(t); return true; } - - std::vector> Get(const WorldPos& center, float radius) override - { + + std::vector> Get(const WorldPos ¢er, + float radius) override { std::vector> matched_items; - for (const auto& item : m_Items) - { - if (center.DistanceTo(item->GetPosition()) < radius) - { + for (const auto &item : m_Items) { + if (center.DistanceTo(item->GetPosition()) < radius) { matched_items.push_back(item); } } return matched_items; } - + // no update needed here, as we have no smart lookup scheme void UpdateAll() override {} void Update(std::shared_ptr) override {} @@ -73,70 +61,55 @@ private: std::vector> m_Items; }; - -template -class PositionalContainer : IPositionalContainer -{ +template class PositionalContainer : IPositionalContainer { public: - - PositionalContainer(const WorldSize& size, size_t chunks) : - m_GridSize{size}, - m_GridStep{size / chunks}, - m_ChunksPerAxis{chunks} - { + PositionalContainer(const WorldSize &size, size_t chunks) + : m_GridSize{size}, m_GridStep{size / chunks}, m_ChunksPerAxis{chunks} { LOG_INFO("Size: ", m_GridSize, " step: ", m_GridStep); m_Grid.reserve(chunks); - for (size_t i = 0; i < chunks; i++) - { + for (size_t i = 0; i < chunks; i++) { m_Grid.emplace_back(chunks); - for (size_t j = 0; j < chunks; j++) - { + for (size_t j = 0; j < chunks; j++) { m_Grid[i][j].reserve(16); } } } // calling Add on object that is already in the container is UB - bool Add(std::shared_ptr item) override - { - const auto& world_pos = item->GetPosition(); - if (!CheckBounds(world_pos)) - { + bool Add(std::shared_ptr item) override { + const auto &world_pos = item->GetPosition(); + if (!CheckBounds(world_pos)) { return false; } m_Items.push_back(item); auto coords = GetCoords(world_pos); m_Grid[coords.x()][coords.y()].push_back(item); m_ReverseGridLookup[item] = coords; - // TODO should we call Update instead? - //Update(item); return true; } - - std::vector> Get(const WorldPos& center, float radius) override - { + + std::vector> Get(const WorldPos ¢er, + float radius) override { vector_wptr output_vec{}; Get(output_vec, center, radius); - + return output_vec; } - void Get(std::vector>& output_vec, const WorldPos& corner, const WorldSize& size) - { + void Get(std::vector> &output_vec, const WorldPos &corner, + const WorldSize &size) { const WorldSize half_size = size / 2.0f; - const WorldPos center = corner + half_size.ChangeTag(); + const WorldPos center = corner + half_size.ChangeTag(); float radius = half_size.x(); Get(output_vec, center, radius); } - // TODO add those Get methods to the interface - - void Get(std::vector>& output_vec, const WorldPos& center, float radius) - { + void Get(std::vector> &output_vec, const WorldPos ¢er, + float radius) { output_vec.clear(); - const WorldPos corner_1 = center + radius; - const WorldPos corner_2 = center - radius; + const WorldPos corner_1 = center + radius; + const WorldPos corner_2 = center - radius; const auto A = GetCoords(corner_1); const auto B = GetCoords(corner_2); @@ -149,108 +122,82 @@ public: size_t y_min = static_cast(std::floor(y_min_f)); size_t y_max = static_cast(std::ceil(y_max_f)); - for (size_t x = x_min; x <= x_max; x++) - { - for (size_t y = y_min; y <= y_max; y++) - { - if (!CheckBounds(x, y)) - { + for (size_t x = x_min; x <= x_max; x++) { + for (size_t y = y_min; y <= y_max; y++) { + if (!CheckBounds(x, y)) { continue; } -#if 0 - // TODO this is approx 2x faster, but inserts items outside of radius; - // We can use this is a Get(rectangle) function - std::ranges::copy(m_Grid[x][y], std::back_inserter(output_vec)); -#else - for (auto item_wptr : m_Grid[x][y]) - { - if (auto shared = item_wptr.lock()) - { - if (center.DistanceTo(shared->GetPosition()) < radius) - { + for (auto item_wptr : m_Grid[x][y]) { + if (auto shared = item_wptr.lock()) { + if (center.DistanceTo(shared->GetPosition()) < radius) { output_vec.push_back(item_wptr); } } } -#endif } } } - void UpdateAll() override - { - for (auto ptr : m_Items) - { - // TODO is this efficient? Maybe use const ref? - - + void UpdateAll() override { + for (auto ptr : m_Items) { Update(ptr); } } - void Update(std::shared_ptr item) override - { + void Update(std::shared_ptr item) override { coord_type current_coords = GetCoords(item->GetPosition()); - coord_type last_known_coords = m_ReverseGridLookup[item]; - if (current_coords == last_known_coords) - { + coord_type last_known_coords = m_ReverseGridLookup[item]; + if (current_coords == last_known_coords) { return; } - vector_wptr& vec = m_Grid[last_known_coords.x()][last_known_coords.y()]; + vector_wptr &vec = m_Grid[last_known_coords.x()][last_known_coords.y()]; // remove the old weak ptr from the map vec.erase(std::remove_if(vec.begin(), vec.end(), - [&](const std::weak_ptr& w) - { - return !w.owner_before(item) && !item.owner_before(w); - }), - vec.end()); + [&](const std::weak_ptr &w) { + return !w.owner_before(item) && + !item.owner_before(w); + }), + vec.end()); // add new weak ptr to the map m_Grid[current_coords.x()][current_coords.y()].push_back(item); } private: - using coord_type = vec; using vector_wptr = std::vector>; using grid_type = std::vector>; - coord_type GetCoords(const WorldPos &wp) - { + coord_type GetCoords(const WorldPos &wp) { auto coord_float = wp / m_GridStep.ChangeTag(); - return coord_type{ - static_cast(coord_float.x()), - static_cast(coord_float.y()) - }; + return coord_type{static_cast(coord_float.x()), + static_cast(coord_float.y())}; } - bool CheckBounds(size_t x, size_t y) const - { + bool CheckBounds(size_t x, size_t y) const { bool x_in_bounds = x < m_Grid.size(); bool y_in_bounds = y < m_Grid.size(); return x_in_bounds && y_in_bounds; } - bool CheckBounds(const WorldPos& pos) const - { - auto [x,y] = pos; - bool x_in_bounds = 0.0f < x && x < m_GridSize.x(); - bool y_in_bounds = 0.0f < y && y < m_GridSize.y(); + bool CheckBounds(const WorldPos &pos) const { + auto [x, y] = pos; + bool x_in_bounds = 0.0f < x && x < m_GridSize.x(); + bool y_in_bounds = 0.0f < y && y < m_GridSize.y(); return x_in_bounds && y_in_bounds; } WorldSize m_GridSize; WorldSize m_GridStep; size_t m_ChunksPerAxis; - // TODO it would be better to have vector - contiguous memory, more cache-friendly? std::vector> m_Items; grid_type m_Grid; // normal lookup: WorldPos -> coord_type -> vector_wptr -> std::shared_ptr // reverse lookup: std::shared_ptr -> vector_wptr -> coord_type - // we need the reverse lookup because T.GetPosition() may change and we need to delete - // the old weak_ptr from vector_wptr (without iterating through all of them). - // Also it might be useful to have T -> location lookup - // Note: hash of std::shared_ptr may give us trouble if we free the memory and new one points - // to the same location, maybe it would be better to hash the object itself? - // TODO how about using counting bloom filter for this? + // we need the reverse lookup because T.GetPosition() may change and we need + // to delete the old weak_ptr from vector_wptr (without iterating through all + // of them). Also it might be useful to have T -> location lookup Note: hash + // of std::shared_ptr may give us trouble if we free the memory and new one + // points to the same location, maybe it would be better to hash the object + // itself? NOTE how about using counting bloom filter for this? std::unordered_map, coord_type> m_ReverseGridLookup; }; diff --git a/cpp/src/user_input.cpp b/cpp/src/user_input.cpp index a46139b..78e3838 100644 --- a/cpp/src/user_input.cpp +++ b/cpp/src/user_input.cpp @@ -117,8 +117,7 @@ const std::vector &UserInput::GetActions() { } else if (mouse_events.contains(event.type)) { GetActions_mouse(event); } else { - // TODO uncomment, for now too much noise - // LOG_WARNING("Action not processed"); + LOG_WARNING("Action not processed"); } } return m_Actions; diff --git a/cpp/src/window.cpp b/cpp/src/window.cpp index 2795b0d..a31b0ff 100644 --- a/cpp/src/window.cpp +++ b/cpp/src/window.cpp @@ -110,7 +110,7 @@ void Window::DrawCircle(const WindowPos &position, float radius, uint8_t R, int cy = static_cast(position.y()); SDL_SetRenderDrawColor(m_Renderer.get(), R, G, B, 255); for (int i = 0; i < 360; ++i) { - double a = i * M_PI / 180.0; + double a = i * std::numbers::pi / 180.0; SDL_RenderPoint(m_Renderer.get(), cx + static_cast(std::round(radius * std::cos(a))), cy + static_cast(std::round(radius * std::sin(a))));