Explorar el Código

:sparkles: added high score screen

Felix Bytow hace 1 año
padre
commit
35670bf0b4

+ 2 - 1
CMakeLists.txt

@@ -43,13 +43,14 @@ add_executable(Snake WIN32
     game/SplashState.cxx game/SplashState.hxx
     game/MenuState.cxx game/MenuState.hxx
     game/PlayingState.cxx game/PlayingState.hxx
+    game/GameOverState.cxx game/GameOverState.hxx
+    game/HighScoreState.cxx game/HighScoreState.hxx
     game/DummyState.cxx game/DummyState.hxx
     game/AssetManager.cxx game/AssetManager.hxx
     game/ui/Button.cxx game/ui/Button.hxx
     game/ui/LineInput.cxx game/ui/LineInput.hxx
     game/ui/UiColor.hxx game/ui/UiColor.cxx
     game/HighScoreManager.cxx game/HighScoreManager.hxx
-    game/GameOverState.cxx game/GameOverState.hxx
 )
 
 target_link_libraries(Snake PRIVATE

+ 6 - 5
game/GameOverState.cxx

@@ -69,8 +69,11 @@ void GameOverState::render(SDLRenderer& renderer)
   SDL_RenderClear(renderer);
 
   int base_y;
-  if (HighScoreManager::instance().has_new_score()) {
-    auto const score_text = std::format("Congratulations, you made it to the top 10!\nPlease enter your name:");
+  auto const& hsm = HighScoreManager::instance();
+  if (hsm.has_new_score()) {
+    auto const score_text = std::format(
+        "Congratulations, you made it to the top 10!\nYou reached {} points!\nPlease enter your name:",
+        hsm.get_new_score());
     SDL_Surface* text_surface = TTF_RenderText_Solid_Wrapped(font_, score_text.c_str(),
         {255, 255, 255, SDL_ALPHA_OPAQUE}, 0);
     SDL_Texture* text = SDL_CreateTextureFromSurface(renderer, text_surface);
@@ -92,9 +95,7 @@ void GameOverState::render(SDLRenderer& renderer)
     base_y += name_input_.get_bounding_box().h+10;
   }
   else {
-    auto const score_text = std::format("Game over!");
-    SDL_Surface* text_surface = TTF_RenderText_Solid_Wrapped(font_, score_text.c_str(),
-        {255, 255, 255, SDL_ALPHA_OPAQUE}, 0);
+    SDL_Surface* text_surface = TTF_RenderText_Solid(font_, "Game over!", {255, 255, 255, SDL_ALPHA_OPAQUE});
     SDL_Texture* text = SDL_CreateTextureFromSurface(renderer, text_surface);
     SDL_FreeSurface(text_surface);
     int text_width, text_height;

+ 5 - 1
game/GameState.hxx

@@ -25,7 +25,11 @@ public:
     (void) event;
   }
 
-  virtual void update(GameStateManager& gsm, std::chrono::milliseconds delta_time) = 0;
+  virtual void update(GameStateManager& gsm, std::chrono::milliseconds const delta_time)
+  {
+    (void) gsm;
+    (void) delta_time;
+  }
 
   virtual void render(SDLRenderer& renderer) = 0;
 };

+ 2 - 0
game/GameStateManager.cxx

@@ -28,6 +28,8 @@ GameState* GameStateManager::enum_to_state(GameStates const state)
     return &game_;
   case GameStates::GameOver:
     return &game_over_;
+  case GameStates::HighScores:
+    return &high_score_;
   }
 }
 

+ 2 - 0
game/GameStateManager.hxx

@@ -8,6 +8,7 @@
 #include "MenuState.hxx"
 #include "PlayingState.hxx"
 #include "GameOverState.hxx"
+#include "HighScoreState.hxx"
 #include "DummyState.hxx"
 
 #include <stack>
@@ -50,6 +51,7 @@ private:
   MenuState menu_;
   PlayingState game_;
   GameOverState game_over_;
+  HighScoreState high_score_;
   DummyState dummy_;
 };
 

+ 10 - 0
game/HighScoreManager.cxx

@@ -77,6 +77,11 @@ bool HighScoreManager::has_new_score() const
   return new_score_.has_value();
 }
 
+unsigned HighScoreManager::get_new_score() const
+{
+  return new_score_.value_or(0u);
+}
+
 void HighScoreManager::provide_name_for_new_score(std::string const& name)
 {
   if (new_score_.has_value()) {
@@ -95,3 +100,8 @@ HighScoreManager& HighScoreManager::instance()
   static HighScoreManager manager;
   return manager;
 }
+
+std::vector<Score> const& HighScoreManager::get_scores() const
+{
+  return high_score_.scores_;
+}

+ 4 - 0
game/HighScoreManager.hxx

@@ -47,10 +47,14 @@ public:
 
   [[nodiscard]] bool has_new_score() const;
 
+  [[nodiscard]] unsigned get_new_score() const;
+
   void provide_name_for_new_score(std::string const& name);
 
   static HighScoreManager& instance();
 
+  [[nodiscard]] std::vector<Score> const& get_scores() const;
+
 private:
   HighScoreManager();
 

+ 84 - 0
game/HighScoreState.cxx

@@ -0,0 +1,84 @@
+#include "HighScoreState.hxx"
+
+#include "HighScoreManager.hxx"
+#include "GameStateManager.hxx"
+#include "../SDLRenderer.hxx"
+
+HighScoreState::HighScoreState()
+    :font_{"kenney_pixel.ttf"}
+{
+}
+
+void HighScoreState::on_event(GameStateManager& gsm, SDL_Event const& event)
+{
+  if (event.type==SDL_KEYUP) {
+    switch (event.key.keysym.scancode) {
+    default:
+      break;
+    case SDL_SCANCODE_ESCAPE:
+      [[fallthrough]];
+    case SDL_SCANCODE_RETURN:
+      gsm.pop_state();
+      break;
+    }
+  }
+}
+
+void HighScoreState::render(SDLRenderer& renderer)
+{
+  TTF_Font* const font = font_;
+
+  SDL_Rect viewport;
+  SDL_RenderGetViewport(renderer, &viewport);
+  int width = viewport.w;
+
+  SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
+  SDL_RenderClear(renderer);
+
+  SDL_Color const color = {255, 255, 255, SDL_ALPHA_OPAQUE};
+
+  int current_height = 80;
+  render_heading(renderer, width, color, current_height);
+
+  auto const scores = HighScoreManager::instance().get_scores();
+  for (auto const& score: scores) {
+    std::string text = score.player_name_+": "+std::to_string(score.points_);
+    SDL_Surface* surface = TTF_RenderText_Solid(font, text.c_str(), color);
+    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
+
+    SDL_Rect textRect;
+    textRect.w = surface->w;
+    textRect.h = surface->h;
+    textRect.x = (width-textRect.w)/2;
+    textRect.y = current_height;
+
+    SDL_RenderCopy(renderer, texture, nullptr, &textRect);
+
+    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)
+{
+  std::string heading = "High Scores";
+  SDL_Surface* headingSurface = TTF_RenderText_Solid(font_, "High Scores", color);
+  SDL_Texture* headingTexture = SDL_CreateTextureFromSurface(renderer, headingSurface);
+
+  SDL_Rect heading_rect;
+  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;
+
+  SDL_RenderCopy(renderer, headingTexture, nullptr, &heading_rect);
+
+  SDL_FreeSurface(headingSurface);
+  SDL_DestroyTexture(headingTexture);
+
+  current_height += heading_rect.h;
+}

+ 23 - 0
game/HighScoreState.hxx

@@ -0,0 +1,23 @@
+#pragma once
+
+#ifndef SNAKE_HIGHSCORESTATE_HXX
+#define SNAKE_HIGHSCORESTATE_HXX
+
+#include "GameState.hxx"
+#include "AssetManager.hxx"
+
+class HighScoreState final : public GameState {
+public:
+  HighScoreState();
+
+  void on_event(GameStateManager& gsm, SDL_Event const& event) override;
+
+  void render(SDLRenderer& renderer) override;
+
+private:
+  Asset<TTF_Font*> font_;
+
+  void render_heading(SDLRenderer& renderer, int width, SDL_Color const& color, int& current_height);
+};
+
+#endif // SNAKE_HIGHSCORESTATE_HXX

+ 1 - 3
game/PlayingState.cxx

@@ -170,10 +170,8 @@ void PlayingState::render(SDLRenderer& renderer)
 
 void PlayingState::render_ui(SDLRenderer& renderer, SDL_Rect const& playing_field)
 {
-  TTF_Font* const font = font_;
-
   auto const score_text = std::format("Score: {}", length_);
-  SDL_Surface* text_surface = TTF_RenderText_Solid(font, score_text.c_str(), {255, 255, 255, SDL_ALPHA_OPAQUE});
+  SDL_Surface* text_surface = TTF_RenderText_Solid(font_, score_text.c_str(), {255, 255, 255, SDL_ALPHA_OPAQUE});
   SDL_Texture* text = SDL_CreateTextureFromSurface(renderer, text_surface);
   SDL_FreeSurface(text_surface);
   int text_width, text_height;