Skip to content

Commit e094057

Browse files
authored
Refactor Collectibles (#28)
1 parent 04fbaca commit e094057

4 files changed

Lines changed: 114 additions & 71 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
#include "chomper/player.hpp"
3+
#include <le2d/drawable/sprite.hpp>
4+
#include <le2d/random.hpp>
5+
#include <le2d/renderer.hpp>
6+
7+
namespace chomper {
8+
class Collectibles {
9+
public:
10+
explicit Collectibles(le::ITexture const& texture);
11+
12+
void spawn(Player const& player);
13+
14+
void draw(le::IRenderer& renderer) const;
15+
16+
void eraseInstance(std::size_t index) {
17+
if (index >= m_sprites.instances.size()) {
18+
return;
19+
}
20+
m_sprites.instances.erase(m_sprites.instances.begin() + static_cast<std::vector<le::RenderInstance>::difference_type>(index));
21+
}
22+
23+
[[nodiscard]] std::span<le::RenderInstance const> getInstances() const {
24+
return m_sprites.instances;
25+
}
26+
27+
private:
28+
void findEmptyTiles(Player const& player);
29+
30+
std::vector<int> m_emptyTiles{};
31+
le::Random m_random{};
32+
33+
le::drawable::InstancedSprite m_sprites{};
34+
};
35+
} // namespace chomper

lib/include/chomper/runtimes/game.hpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#pragma once
2-
#include "chomper/collectible.hpp"
2+
#include "chomper/collectibles.hpp"
33
#include "chomper/engine.hpp"
44
#include "chomper/player.hpp"
55
#include "chomper/runtime.hpp"
@@ -8,9 +8,6 @@
88
#include <le2d/drawable/text.hpp>
99
#include <le2d/input/action.hpp>
1010
#include <le2d/input/scoped_mapping.hpp>
11-
#include <le2d/random.hpp>
12-
#include <le2d/resource/texture.hpp>
13-
#include <unordered_set>
1411

1512
namespace chomper::runtime {
1613
// driven by Engine, owner (whether indirectly) of all game things.
@@ -32,10 +29,8 @@ class Game : public IRuntime, public klib::Pinned {
3229

3330
void bindActions();
3431
void createPlayer();
35-
void createCollectibleTexture();
32+
void createCollectibles();
3633

37-
void findEmptyTiles();
38-
void spawnCollectibles();
3934
void collideCollectibles();
4035

4136
void onGoBack();
@@ -47,12 +42,9 @@ class Game : public IRuntime, public klib::Pinned {
4742
le::input::ScopedActionMapping m_mapping;
4843
Actions m_actions{};
4944

50-
le::Random m_random{};
51-
std::unordered_set<int> m_occupied;
52-
5345
std::unique_ptr<Player> m_player{};
5446
std::unique_ptr<World> m_world{};
55-
std::vector<Collectible> m_collectibles{};
47+
std::unique_ptr<Collectibles> m_collectibles{};
5648
klib::Ptr<le::ITexture const> m_collectibleTexture{};
5749

5850
std::vector<int> m_emptyTiles{};

lib/src/collectibles.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "chomper/collectibles.hpp"
2+
#include "chomper/world_size.hpp"
3+
#include "chomper/world_space.hpp"
4+
#include "le2d/renderer.hpp"
5+
6+
namespace chomper {
7+
namespace {
8+
constexpr auto collectibleAmount_v = 10;
9+
}
10+
11+
Collectibles::Collectibles(le::ITexture const& texture) {
12+
m_sprites.set_base_size(tileSize_v);
13+
m_sprites.set_texture(&texture);
14+
}
15+
16+
void Collectibles::spawn(Player const& player) {
17+
findEmptyTiles(player);
18+
19+
for (auto i = m_sprites.instances.size(); i < collectibleAmount_v; i++) {
20+
if (m_emptyTiles.empty()) {
21+
return;
22+
}
23+
// find a random tile
24+
auto random = m_random.next_index(m_emptyTiles.size());
25+
auto tile = m_emptyTiles[random];
26+
// remove said tile from the vector
27+
std::erase_if(m_emptyTiles, [&](auto const& v) {
28+
return v == m_emptyTiles[random];
29+
});
30+
// place the collectible on the tile
31+
auto width = static_cast<int>(worldSize_v.x);
32+
m_sprites.instances.emplace_back();
33+
m_sprites.instances.back().transform.position = worldSpace::gridToWorld({tile % width, tile / width});
34+
}
35+
}
36+
37+
void Collectibles::findEmptyTiles(Player const& player) {
38+
m_emptyTiles.clear();
39+
m_emptyTiles.reserve(static_cast<int>(worldSize_v.x * worldSize_v.y));
40+
for (auto i = 0; i < static_cast<int>(worldSize_v.x * worldSize_v.y); i++) {
41+
m_emptyTiles.push_back(i);
42+
}
43+
44+
auto const removeTile = [this](int tile) {
45+
auto it = std::ranges::find(m_emptyTiles, tile);
46+
if (it != m_emptyTiles.end()) {
47+
*it = m_emptyTiles.back();
48+
m_emptyTiles.pop_back();
49+
}
50+
};
51+
52+
for (auto const& seg : player.getSegments()) {
53+
auto p = worldSpace::worldToGrid(seg.transform.position);
54+
removeTile(static_cast<int>((p.y * worldSize_v.x) + p.x));
55+
}
56+
57+
for (auto const& c : m_sprites.instances) {
58+
auto p = worldSpace::worldToGrid(c.transform.position);
59+
removeTile(static_cast<int>((p.y * worldSize_v.x) + p.x));
60+
}
61+
}
62+
63+
void Collectibles::draw(le::IRenderer& renderer) const {
64+
m_sprites.draw(renderer);
65+
}
66+
} // namespace chomper

lib/src/runtimes/game.cpp

Lines changed: 10 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include "chomper/runtimes/game.hpp"
2-
#include "chomper/collectible.hpp"
32
#include "chomper/im_util.hpp"
43
#include "chomper/runtimes/entrypoint.hpp"
5-
#include "chomper/world_size.hpp"
64
#include "chomper/world_space.hpp"
75
#include <le2d/random.hpp>
86
#include <algorithm>
@@ -12,17 +10,16 @@ namespace {
1210
constexpr auto countdownParams_v = le::drawable::Text::Params{
1311
.height = le::TextHeight{60},
1412
};
15-
constexpr auto collectibleAmount_v = 10;
1613
} // namespace
1714
using ActionValue = le::input::action::Value;
1815

1916
Game::Game(gsl::not_null<Engine*> engine) : m_engine(engine), m_mapping(&engine->getInputRouter()) {
2017
createPlayer();
2118
m_world = std::make_unique<World>(m_engine);
2219

23-
createCollectibleTexture();
20+
createCollectibles();
2421

25-
spawnCollectibles();
22+
m_collectibles->spawn(*m_player);
2623

2724
m_countdownText.set_string(engine->getResources().getMainFont(), "3", countdownParams_v);
2825
}
@@ -52,9 +49,7 @@ void Game::tick(kvf::Seconds const dt) {
5249

5350
void Game::render(le::IRenderer& renderer) const {
5451
m_world->draw(renderer);
55-
for (auto const& collectible : m_collectibles) {
56-
collectible.draw(renderer);
57-
}
52+
m_collectibles->draw(renderer);
5853
m_player->draw(renderer);
5954
if (m_countdown.count() > 0) {
6055
m_countdownText.draw(renderer);
@@ -89,67 +84,22 @@ void Game::createPlayer() {
8984
m_player = std::make_unique<Player>(m_mapping, m_engine);
9085
}
9186

92-
void Game::createCollectibleTexture() {
87+
void Game::createCollectibles() {
9388
m_collectibleTexture = m_engine->getResources().load<le::ITexture>("images/apple.png");
94-
}
95-
96-
void Game::findEmptyTiles() {
97-
m_emptyTiles.clear();
98-
m_emptyTiles.reserve(static_cast<int>(worldSize_v.x * worldSize_v.y));
99-
for (auto i = 0; i < static_cast<int>(worldSize_v.x * worldSize_v.y); i++) {
100-
m_emptyTiles.push_back(i);
101-
}
102-
103-
auto const removeTile = [this](int tile) {
104-
auto it = std::ranges::find(m_emptyTiles, tile);
105-
if (it != m_emptyTiles.end()) {
106-
*it = m_emptyTiles.back();
107-
m_emptyTiles.pop_back();
108-
}
109-
};
110-
111-
for (auto const& seg : m_player->getSegments()) {
112-
auto p = worldSpace::worldToGrid(seg.transform.position);
113-
removeTile(static_cast<int>((p.y * worldSize_v.x) + p.x));
114-
}
115-
116-
for (auto const& c : m_collectibles) {
117-
auto p = c.getGridPosition();
118-
removeTile(static_cast<int>((p.y * worldSize_v.x) + p.x));
119-
}
120-
}
121-
122-
void Game::spawnCollectibles() {
123-
findEmptyTiles();
124-
125-
for (auto i = m_collectibles.size(); i < collectibleAmount_v; i++) {
126-
if (m_emptyTiles.empty()) {
127-
return;
128-
}
129-
// find a random tile
130-
auto random = m_random.next_index(m_emptyTiles.size());
131-
auto tile = m_emptyTiles[random];
132-
// remove said tile from the vector
133-
std::erase_if(m_emptyTiles, [&](auto const& v) {
134-
return v == m_emptyTiles[random];
135-
});
136-
// place the collectible on the tile
137-
auto width = static_cast<int>(worldSize_v.x);
138-
m_collectibles.emplace_back(*m_collectibleTexture, worldSpace::gridToWorld({tile % width, tile / width}));
139-
}
89+
m_collectibles = std::make_unique<Collectibles>(*m_collectibleTexture);
14090
}
14191

14292
void Game::collideCollectibles() {
143-
auto it = std::ranges::find_if(m_collectibles, [&](auto const& collectible) {
144-
return collectible.getGridPosition() == worldSpace::worldToGrid(m_player->getSegments().back().transform.position);
93+
auto it = std::ranges::find_if(m_collectibles->getInstances(), [&](auto const& collectible) {
94+
return worldSpace::worldToGrid(collectible.transform.position) == worldSpace::worldToGrid(m_player->getSegments().back().transform.position);
14595
});
146-
if (it == m_collectibles.end()) {
96+
if (it == m_collectibles->getInstances().end()) {
14797
return;
14898
}
14999

150-
m_collectibles.erase(it);
151100
m_player->grow();
152-
spawnCollectibles();
101+
m_collectibles->eraseInstance(static_cast<std::size_t>(std::distance(m_collectibles->getInstances().begin(), it)));
102+
m_collectibles->spawn(*m_player);
153103
}
154104

155105
void Game::onGoBack() {

0 commit comments

Comments
 (0)