Bläddra i källkod

:sparkles: added multiple target support

in 90% of cases you will only have 1 target
in 9% of cases you will have 2 targets
in 1% of cases you will have 3 targets
Felix Bytow 1 år sedan
förälder
incheckning
a8fb7716d6
2 ändrade filer med 30 tillägg och 26 borttagningar
  1. 15 25
      game/PlayingState.cxx
  2. 15 1
      game/PlayingState.hxx

+ 15 - 25
game/PlayingState.cxx

@@ -8,19 +8,6 @@
 #include <cfenv>
 #include <cmath>
 #include <random>
-#include <unordered_set>
-
-namespace std {
-  template<>
-  struct hash<SDL_Point> {
-    std::size_t operator()(SDL_Point const& p) const noexcept
-    {
-      static_assert(sizeof(std::size_t)==8u);
-      static_assert(sizeof(int)==4u);
-      return (static_cast<std::size_t>(p.x) << 32u) | static_cast<std::size_t>(p.y);
-    }
-  };
-}
 
 namespace {
   SDL_Point head_position(SDL_FPoint const& position)
@@ -131,7 +118,8 @@ void PlayingState::update(GameStateManager& gsm, std::chrono::milliseconds const
       gsm.replace_state(GameStates::GameOver);
     }
 
-    if (new_pos==target_) {
+    if (target_.contains(new_pos)) {
+      target_.erase(new_pos);
       ++length_;
       speed_ = std::min(MAX_SPEED, speed_*ACCELERATION);
       if (!place_target()) {
@@ -231,10 +219,9 @@ bool PlayingState::place_target()
     return false;
   }
 
-  std::vector<SDL_Point> result;
-  std::ranges::sample(field, std::back_inserter(result), 1, generator_);
-
-  target_ = result[0];
+  auto const wanted_targets = distribution_num_targets(generator_);
+  std::ranges::sample(field, std::inserter(target_, target_.end()),
+      std::max(static_cast<long long>(wanted_targets-target_.size()), 0ll), generator_);
   deadly_wall_ = distribution_deadly_wall(generator_)!=0;
 
   return true;
@@ -256,15 +243,18 @@ void PlayingState::place_head()
 void PlayingState::render_target(SDLRenderer& renderer, SDL_Rect const& playing_field)
 {
   auto const ratio = playing_field.w/static_cast<double>(CELLS_X);
-  SDL_Rect const target_rect{
-      .x = static_cast<int>(playing_field.x+ratio*target_.x),
-      .y = static_cast<int>(playing_field.y+ratio*target_.y),
-      .w = static_cast<int>(ratio),
-      .h = static_cast<int>(ratio),
-  };
 
   SDL_SetRenderDrawColor(renderer, 76, 208, 45, SDL_ALPHA_OPAQUE);
-  SDL_RenderFillRect(renderer, &target_rect);
+  for (auto const& target: target_) {
+    SDL_Rect const target_rect{
+        .x = static_cast<int>(playing_field.x+ratio*target.x),
+        .y = static_cast<int>(playing_field.y+ratio*target.y),
+        .w = static_cast<int>(ratio),
+        .h = static_cast<int>(ratio),
+    };
+
+    SDL_RenderFillRect(renderer, &target_rect);
+  }
 }
 
 void PlayingState::render_snake(SDLRenderer& renderer, SDL_Rect const& playing_field)

+ 15 - 1
game/PlayingState.hxx

@@ -9,6 +9,19 @@
 #include <deque>
 #include <optional>
 #include <random>
+#include <unordered_set>
+
+namespace std {
+  template<>
+  struct hash<SDL_Point> {
+    std::size_t operator()(SDL_Point const& p) const noexcept
+    {
+      static_assert(sizeof(std::size_t)==8u);
+      static_assert(sizeof(int)==4u);
+      return (static_cast<std::size_t>(p.x) << 32u) | static_cast<std::size_t>(p.y);
+    }
+  };
+}
 
 enum class Direction {
   Up,
@@ -58,8 +71,9 @@ private:
   std::uniform_int_distribution<int> distribution_position_x_{0, CELLS_X-1};
   std::uniform_int_distribution<int> distribution_position_y_{0, CELLS_Y-1};
   std::discrete_distribution<int> distribution_deadly_wall{{5, 95}};
+  std::discrete_distribution<std::size_t> distribution_num_targets{{0, 90, 9, 1}};
 
-  SDL_Point target_{};
+  std::unordered_set<SDL_Point> target_{};
   unsigned length_{0u};
   Direction direction_{Direction::Left};
   std::optional<Direction> new_direction_{};