From 6dfe66a83a2501bc33bb96d19cdc21af89f85749 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 19 Jan 2026 20:47:23 +0100 Subject: [PATCH 1/3] Refactor `Collectibles` --- lib/include/chomper/collectible.hpp | 22 --------- lib/include/chomper/collectibles.hpp | 35 ++++++++++++++ lib/include/chomper/runtimes/game.hpp | 13 ++--- lib/src/collectible.cpp | 15 ------ lib/src/collectibles.cpp | 66 +++++++++++++++++++++++++ lib/src/runtimes/game.cpp | 70 ++++----------------------- 6 files changed, 114 insertions(+), 107 deletions(-) delete mode 100644 lib/include/chomper/collectible.hpp create mode 100644 lib/include/chomper/collectibles.hpp delete mode 100644 lib/src/collectible.cpp create mode 100644 lib/src/collectibles.cpp diff --git a/lib/include/chomper/collectible.hpp b/lib/include/chomper/collectible.hpp deleted file mode 100644 index a7cedb4..0000000 --- a/lib/include/chomper/collectible.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "chomper/world_space.hpp" -#include "glm/ext/vector_float2.hpp" -#include "le2d/drawable/sprite.hpp" -#include "le2d/renderer.hpp" -#include "le2d/resource/texture.hpp" - -namespace chomper { -class Collectible { - public: - explicit Collectible(le::ITexture const& texture, glm::vec2 position); - - void draw(le::IRenderer& renderer) const; - - [[nodiscard]] glm::vec2 getGridPosition() const { - return worldSpace::worldToGrid(m_sprite.transform.position); - } - - private: - le::drawable::Sprite m_sprite{}; -}; -} // namespace chomper \ No newline at end of file diff --git a/lib/include/chomper/collectibles.hpp b/lib/include/chomper/collectibles.hpp new file mode 100644 index 0000000..f1467b3 --- /dev/null +++ b/lib/include/chomper/collectibles.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "chomper/player.hpp" +#include +#include +#include + +namespace chomper { +class Collectibles { + public: + explicit Collectibles(le::ITexture const& texture); + + void spawn(Player const& player); + + void draw(le::IRenderer& renderer) const; + + void eraseInstance(std::size_t index) { + if (index > m_sprites.instances.size()) { + return; + } + m_sprites.instances.erase(m_sprites.instances.begin() + static_cast::difference_type>(index)); + } + + [[nodiscard]] std::span getInstances() const { + return m_sprites.instances; + } + + private: + void findEmptyTiles(Player const& player); + + std::vector m_emptyTiles{}; + le::Random m_random{}; + + le::drawable::InstancedSprite m_sprites{}; +}; +} // namespace chomper \ No newline at end of file diff --git a/lib/include/chomper/runtimes/game.hpp b/lib/include/chomper/runtimes/game.hpp index 7e12e03..58a4aa0 100644 --- a/lib/include/chomper/runtimes/game.hpp +++ b/lib/include/chomper/runtimes/game.hpp @@ -1,16 +1,14 @@ #pragma once -#include "chomper/collectible.hpp" +#include "chomper/collectibles.hpp" #include "chomper/engine.hpp" #include "chomper/player.hpp" #include "chomper/runtime.hpp" #include "chomper/world.hpp" -#include "le2d/random.hpp" #include "le2d/resource/texture.hpp" #include #include #include #include -#include namespace chomper::runtime { // driven by Engine, owner (whether indirectly) of all game things. @@ -32,10 +30,8 @@ class Game : public IRuntime, public klib::Pinned { void bindActions(); void createPlayer(); - void createCollectibleTexture(); + void createCollectibles(); - void findEmptyTiles(); - void spawnCollectibles(); void collideCollectibles(); void onGoBack(); @@ -47,12 +43,9 @@ class Game : public IRuntime, public klib::Pinned { le::input::ScopedActionMapping m_mapping; Actions m_actions{}; - le::Random m_random{}; - std::unordered_set m_occupied; - std::unique_ptr m_player{}; std::unique_ptr m_world{}; - std::vector m_collectibles{}; + std::unique_ptr m_collectibles{}; klib::Ptr m_collectibleTexture{}; std::vector m_emptyTiles{}; diff --git a/lib/src/collectible.cpp b/lib/src/collectible.cpp deleted file mode 100644 index 3573d9c..0000000 --- a/lib/src/collectible.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "chomper/collectible.hpp" -#include "chomper/world_size.hpp" -#include "le2d/renderer.hpp" - -namespace chomper { -Collectible::Collectible(le::ITexture const& texture, glm::vec2 position) { - m_sprite.set_base_size(tileSize_v); - m_sprite.set_texture(&texture); - m_sprite.transform.position = position; -} - -void Collectible::draw(le::IRenderer& renderer) const { - m_sprite.draw(renderer); -} -} // namespace chomper \ No newline at end of file diff --git a/lib/src/collectibles.cpp b/lib/src/collectibles.cpp new file mode 100644 index 0000000..391b1dd --- /dev/null +++ b/lib/src/collectibles.cpp @@ -0,0 +1,66 @@ +#include "chomper/collectibles.hpp" +#include "chomper/world_size.hpp" +#include "chomper/world_space.hpp" +#include "le2d/renderer.hpp" + +namespace chomper { +namespace { +constexpr auto collectibleAmount_v = 10; +} + +Collectibles::Collectibles(le::ITexture const& texture) { + m_sprites.set_base_size(tileSize_v); + m_sprites.set_texture(&texture); +} + +void Collectibles::spawn(Player const& player) { + findEmptyTiles(player); + + for (auto i = m_sprites.instances.size(); i < collectibleAmount_v; i++) { + if (m_emptyTiles.empty()) { + return; + } + // find a random tile + auto random = m_random.next_index(m_emptyTiles.size()); + auto tile = m_emptyTiles[random]; + // remove said tile from the vector + std::erase_if(m_emptyTiles, [&](auto const& v) { + return v == m_emptyTiles[random]; + }); + // place the collectible on the tile + auto width = static_cast(worldSize_v.x); + m_sprites.instances.emplace_back(); + m_sprites.instances.back().transform.position = worldSpace::gridToWorld({tile % width, tile / width}); + } +} + +void Collectibles::findEmptyTiles(Player const& player) { + m_emptyTiles.clear(); + m_emptyTiles.reserve(static_cast(worldSize_v.x * worldSize_v.y)); + for (auto i = 0; i < static_cast(worldSize_v.x * worldSize_v.y); i++) { + m_emptyTiles.push_back(i); + } + + auto const removeTile = [this](int tile) { + auto it = std::ranges::find(m_emptyTiles, tile); + if (it != m_emptyTiles.end()) { + *it = m_emptyTiles.back(); + m_emptyTiles.pop_back(); + } + }; + + for (auto const& seg : player.getSegments()) { + auto p = worldSpace::worldToGrid(seg.transform.position); + removeTile(static_cast((p.y * worldSize_v.x) + p.x)); + } + + for (auto const& c : m_sprites.instances) { + auto p = worldSpace::worldToGrid(c.transform.position); + removeTile(static_cast((p.y * worldSize_v.x) + p.x)); + } +} + +void Collectibles::draw(le::IRenderer& renderer) const { + m_sprites.draw(renderer); +} +} // namespace chomper \ No newline at end of file diff --git a/lib/src/runtimes/game.cpp b/lib/src/runtimes/game.cpp index 16666f8..dfa642c 100644 --- a/lib/src/runtimes/game.cpp +++ b/lib/src/runtimes/game.cpp @@ -1,8 +1,6 @@ #include "chomper/runtimes/game.hpp" -#include "chomper/collectible.hpp" #include "chomper/im_util.hpp" #include "chomper/runtimes/entrypoint.hpp" -#include "chomper/world_size.hpp" #include "chomper/world_space.hpp" #include #include @@ -12,7 +10,6 @@ namespace { constexpr auto countdownParams_v = le::drawable::Text::Params{ .height = le::TextHeight{60}, }; -constexpr auto collectibleAmount_v = 10; } // namespace using ActionValue = le::input::action::Value; @@ -20,9 +17,9 @@ Game::Game(gsl::not_null engine) : m_engine(engine), m_mapping(&engine- createPlayer(); m_world = std::make_unique(m_engine); - createCollectibleTexture(); + createCollectibles(); - spawnCollectibles(); + m_collectibles->spawn(*m_player); m_countdownText.set_string(engine->getResources().getMainFont(), "3", countdownParams_v); } @@ -53,9 +50,7 @@ void Game::tick(kvf::Seconds const dt) { void Game::render(le::IRenderer& renderer) const { m_world->draw(renderer); m_player->draw(renderer); - for (auto const& collectible : m_collectibles) { - collectible.draw(renderer); - } + m_collectibles->draw(renderer); if (m_countdown.count() > 0) { m_countdownText.draw(renderer); } @@ -89,67 +84,22 @@ void Game::createPlayer() { m_player = std::make_unique(m_mapping, m_engine); } -void Game::createCollectibleTexture() { +void Game::createCollectibles() { m_collectibleTexture = m_engine->getResources().load("images/apple.png"); -} - -void Game::findEmptyTiles() { - m_emptyTiles.clear(); - m_emptyTiles.reserve(static_cast(worldSize_v.x * worldSize_v.y)); - for (auto i = 0; i < static_cast(worldSize_v.x * worldSize_v.y); i++) { - m_emptyTiles.push_back(i); - } - - auto const removeTile = [this](int tile) { - auto it = std::ranges::find(m_emptyTiles, tile); - if (it != m_emptyTiles.end()) { - *it = m_emptyTiles.back(); - m_emptyTiles.pop_back(); - } - }; - - for (auto const& seg : m_player->getSegments()) { - auto p = worldSpace::worldToGrid(seg.transform.position); - removeTile(static_cast((p.y * worldSize_v.x) + p.x)); - } - - for (auto const& c : m_collectibles) { - auto p = c.getGridPosition(); - removeTile(static_cast((p.y * worldSize_v.x) + p.x)); - } -} - -void Game::spawnCollectibles() { - findEmptyTiles(); - - for (auto i = m_collectibles.size(); i < collectibleAmount_v; i++) { - if (m_emptyTiles.empty()) { - return; - } - // find a random tile - auto random = m_random.next_index(m_emptyTiles.size()); - auto tile = m_emptyTiles[random]; - // remove said tile from the vector - std::erase_if(m_emptyTiles, [&](auto const& v) { - return v == m_emptyTiles[random]; - }); - // place the collectible on the tile - auto width = static_cast(worldSize_v.x); - m_collectibles.emplace_back(*m_collectibleTexture, worldSpace::gridToWorld({tile % width, tile / width})); - } + m_collectibles = std::make_unique(*m_collectibleTexture); } void Game::collideCollectibles() { - auto it = std::ranges::find_if(m_collectibles, [&](auto const& collectible) { - return collectible.getGridPosition() == worldSpace::worldToGrid(m_player->getSegments().back().transform.position); + auto it = std::ranges::find_if(m_collectibles->getInstances(), [&](auto const& collectible) { + return worldSpace::worldToGrid(collectible.transform.position) == worldSpace::worldToGrid(m_player->getSegments().back().transform.position); }); - if (it == m_collectibles.end()) { + if (it == m_collectibles->getInstances().end()) { return; } - m_collectibles.erase(it); m_player->grow(); - spawnCollectibles(); + m_collectibles->eraseInstance(static_cast(std::distance(m_collectibles->getInstances().begin(), it))); + m_collectibles->spawn(*m_player); } void Game::onGoBack() { From 4d57c16935e0afbfb113305b9f049d6bce6d8ac0 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 19 Jan 2026 21:58:30 +0100 Subject: [PATCH 2/3] Add requested changes --- lib/include/chomper/collectibles.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/chomper/collectibles.hpp b/lib/include/chomper/collectibles.hpp index f1467b3..a73ad87 100644 --- a/lib/include/chomper/collectibles.hpp +++ b/lib/include/chomper/collectibles.hpp @@ -14,7 +14,7 @@ class Collectibles { void draw(le::IRenderer& renderer) const; void eraseInstance(std::size_t index) { - if (index > m_sprites.instances.size()) { + if (index > +m_sprites.instances.size()) { return; } m_sprites.instances.erase(m_sprites.instances.begin() + static_cast::difference_type>(index)); From 5c2da89f9916aabafb6ba59cab5b762960591af6 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 20 Jan 2026 12:45:06 +0100 Subject: [PATCH 3/3] fix typo --- lib/include/chomper/collectibles.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/chomper/collectibles.hpp b/lib/include/chomper/collectibles.hpp index a73ad87..c23fd4a 100644 --- a/lib/include/chomper/collectibles.hpp +++ b/lib/include/chomper/collectibles.hpp @@ -14,7 +14,7 @@ class Collectibles { void draw(le::IRenderer& renderer) const; void eraseInstance(std::size_t index) { - if (index > +m_sprites.instances.size()) { + if (index >= m_sprites.instances.size()) { return; } m_sprites.instances.erase(m_sprites.instances.begin() + static_cast::difference_type>(index));