11#include " chomper/runtimes/game.hpp"
2+ #include " chomper/collectible.hpp"
23#include " chomper/im_util.hpp"
34#include " chomper/runtimes/entrypoint.hpp"
4- #include < array>
5+ #include " chomper/world_size.hpp"
6+ #include " chomper/world_space.hpp"
7+ #include < le2d/random.hpp>
8+ #include < algorithm>
59
610namespace chomper ::runtime {
711namespace {
812constexpr auto countdownParams_v = le::drawable::Text::Params{
913 .height = le::TextHeight{60 },
1014};
11- }
15+ constexpr auto collectibleAmount_v = 10 ;
16+ } // namespace
1217using ActionValue = le::input::action::Value;
1318
1419Game::Game (gsl::not_null<Engine*> engine) : m_engine(engine), m_mapping(&engine->getInputRouter ()) {
1520 createPlayer ();
1621 m_world = std::make_unique<World>(m_engine);
1722
23+ createCollectibleTexture ();
24+
25+ spawnCollectibles ();
26+
1827 m_countdownText.set_string (engine->getResources ().getMainFont (), " 3" , countdownParams_v);
1928}
2029
@@ -33,6 +42,8 @@ void Game::tick(kvf::Seconds const dt) {
3342
3443 m_player->tick (dt);
3544
45+ collideCollectibles ();
46+
3647 // On death
3748 if (!m_player->getInfo ().alive ) {
3849 m_engine->setNextRuntime <runtime::Entrypoint>();
@@ -42,6 +53,9 @@ void Game::tick(kvf::Seconds const dt) {
4253void Game::render (le::IRenderer& renderer) const {
4354 m_world->draw (renderer);
4455 m_player->draw (renderer);
56+ for (auto const & collectible : m_collectibles) {
57+ collectible.draw (renderer);
58+ }
4559 if (m_countdown.count () > 0 ) {
4660 m_countdownText.draw (renderer);
4761 }
@@ -75,6 +89,69 @@ void Game::createPlayer() {
7589 m_player = std::make_unique<Player>(m_mapping, m_engine);
7690}
7791
92+ void Game::createCollectibleTexture () {
93+ 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+ }
140+ }
141+
142+ 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 );
145+ });
146+ if (it == m_collectibles.end ()) {
147+ return ;
148+ }
149+
150+ m_collectibles.erase (it);
151+ m_player->grow ();
152+ spawnCollectibles ();
153+ }
154+
78155void Game::onGoBack () {
79156 m_log.debug (" execute 'go back' action here" );
80157}
0 commit comments