Quellcode durchsuchen

:sparkles: harder targets give more points now

Felix Bytow vor 1 Jahr
Ursprung
Commit
7268640566
3 geänderte Dateien mit 49 neuen und 14 gelöschten Zeilen
  1. 8 10
      game/HighScoreState.cxx
  2. 1 1
      game/HighScoreState.hxx
  3. 40 3
      game/PlayingState.cxx

+ 8 - 10
game/HighScoreState.cxx

@@ -38,12 +38,14 @@ void HighScoreState::render(SDLRenderer& renderer)
 
   SDL_Color const color = {255, 255, 255, SDL_ALPHA_OPAQUE};
 
-  int current_height = 80;
-  render_heading(renderer, width, color, current_height);
+  render_heading(renderer, width, color);
 
   auto const scores = HighScoreManager::instance().get_scores();
-  for (auto const& score: scores) {
-    std::string text = score.player_name_+": "+std::to_string(score.points_);
+  for (auto n = scores.size(); n--;) {
+    auto const current_height = 180+static_cast<int>(n)*50;
+    auto const& score = scores[n];
+
+    std::string const text = std::to_string(n+1)+" - "+score.player_name_+": "+std::to_string(score.points_);
     SDL_Surface* surface = TTF_RenderUTF8_Solid(font, text.c_str(), color);
     SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
 
@@ -57,14 +59,12 @@ void HighScoreState::render(SDLRenderer& renderer)
 
     SDL_FreeSurface(surface);
     SDL_DestroyTexture(texture);
-
-    current_height += textRect.h;
   }
 
   SDL_RenderPresent(renderer);
 }
 
-void HighScoreState::render_heading(SDLRenderer& renderer, int const width, SDL_Color const& color, int& current_height)
+void HighScoreState::render_heading(SDLRenderer& renderer, int const width, SDL_Color const& color)
 {
   SDL_Surface* headingSurface = TTF_RenderUTF8_Solid(font_,
       TranslationManager::instance().get_translation("High Scores").c_str(), color);
@@ -74,12 +74,10 @@ void HighScoreState::render_heading(SDLRenderer& renderer, int const width, SDL_
   heading_rect.w = headingSurface->w*2;
   heading_rect.h = headingSurface->h*2;
   heading_rect.x = (width-heading_rect.w)/2;
-  heading_rect.y = current_height;
+  heading_rect.y = 80;
 
   SDL_RenderCopy(renderer, headingTexture, nullptr, &heading_rect);
 
   SDL_FreeSurface(headingSurface);
   SDL_DestroyTexture(headingTexture);
-
-  current_height += heading_rect.h;
 }

+ 1 - 1
game/HighScoreState.hxx

@@ -17,7 +17,7 @@ public:
 private:
   Asset<TTF_Font*> font_;
 
-  void render_heading(SDLRenderer& renderer, int width, SDL_Color const& color, int& current_height);
+  void render_heading(SDLRenderer& renderer, int width, SDL_Color const& color);
 };
 
 #endif // SNAKE_HIGHSCORESTATE_HXX

+ 40 - 3
game/PlayingState.cxx

@@ -7,18 +7,54 @@
 #include <algorithm>
 #include <cfenv>
 #include <cmath>
+#include <iterator>
 #include <random>
 
 namespace {
   SDL_Point head_position(SDL_FPoint const& position)
   {
+#ifndef _MSC_VER
 #pragma STDC FENV_ACCESS ON
+#endif // !_MSC_VER
     std::fesetround(FE_TONEAREST);
     return {
         .x = static_cast<int>(std::nearbyint(position.x)),
         .y = static_cast<int>(std::nearbyint(position.y)),
     };
   }
+
+  unsigned points_for_target(SDL_Point const& target)
+  {
+    // normally there is just 1 point per target hit
+    SDL_Rect const inner_field{
+        .x=2,
+        .y=2,
+        .w=PlayingState::CELLS_X-4,
+        .h=PlayingState::CELLS_Y-4,
+    };
+    if (SDL_PointInRect(&target, &inner_field)) {
+      return 1;
+    }
+
+    // targets with a distance of 1 to the wall give double points
+    SDL_Rect const outer_field{
+        .x=1,
+        .y=1,
+        .w=PlayingState::CELLS_X-2,
+        .h=PlayingState::CELLS_Y-2,
+    };
+    if (SDL_PointInRect(&target, &outer_field)) {
+      return 2;
+    }
+
+    // corners give 8 points
+    if ((target.x==0 || target.x==PlayingState::CELLS_X-1) && (target.y==0 || target.y==PlayingState::CELLS_Y-1)) {
+      return 8;
+    }
+
+    // edges give 4 points
+    return 4;
+  }
 }
 
 static bool operator==(SDL_Point const& lhs, SDL_Point const& rhs)
@@ -120,8 +156,9 @@ void PlayingState::update(GameStateManager& gsm, std::chrono::milliseconds const
 
     if (target_.contains(new_pos)) {
       target_.erase(new_pos);
-      ++length_;
-      speed_ = std::min(MAX_SPEED, speed_*ACCELERATION);
+      auto const growth = std::min(points_for_target(new_pos), static_cast<unsigned>(CELLS_X*CELLS_Y)-length_);
+      length_ += growth;
+      speed_ = std::min(MAX_SPEED, speed_*std::pow(ACCELERATION, static_cast<float>(growth)));
       if (!place_target()) {
         // technically the player finished the game at this point
         HighScoreManager::instance().set_new_score(length_);
@@ -223,7 +260,7 @@ bool PlayingState::place_target()
   }
 
   auto const wanted_targets = distribution_num_targets(generator_);
-  std::ranges::sample(field, std::inserter(target_, target_.end()),
+  std::ranges::sample(field, std::insert_iterator{target_, target_.end()},
       std::max(static_cast<long long>(wanted_targets-target_.size()), 0ll), generator_);
   deadly_wall_ = distribution_deadly_wall(generator_)!=0;