Explorar o código

:recycle: providing the GameStateManager in on_enter now so things event handlers need only be set once

Felix Bytow hai 1 ano
pai
achega
6a598b3acd

+ 9 - 6
game/DummyState.cxx

@@ -3,13 +3,16 @@
 
 #include "../SDLRenderer.hxx"
 
-void DummyState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
+void DummyState::on_enter(GameStateManager& gsm)
 {
-  time_in_state_ += delta_time;
-  quit_button_.set_on_click([&gsm] {
-    gsm.pop_state();
+  pause_button_.set_on_click([&gsm] {
+    gsm.push_state(GameStates::MainMenu);
   });
-  quit_button_.update();
+}
+
+void DummyState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
+{
+  pause_button_.update();
 }
 
 void DummyState::render(SDLRenderer& renderer)
@@ -17,7 +20,7 @@ void DummyState::render(SDLRenderer& renderer)
   SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
   SDL_RenderClear(renderer);
 
-  quit_button_.render(renderer);
+  pause_button_.render(renderer);
 
   SDL_RenderPresent(renderer);
 }

+ 3 - 2
game/DummyState.hxx

@@ -8,13 +8,14 @@
 
 class DummyState final : public GameState {
 public:
+  void on_enter(GameStateManager& gsm) override;
+
   void update(GameStateManager& gsm, std::chrono::milliseconds delta_time) override;
 
   void render(SDLRenderer& renderer) override;
 
 private:
-  std::chrono::milliseconds time_in_state_{0};
-  Button quit_button_{"Quit", 15, 15, 800, 80};
+  Button pause_button_{"Pause", 15, 15, 800, 80};
 };
 
 #endif // SNAKE_DUMMYSTATE_HXX

+ 1 - 1
game/GameState.hxx

@@ -13,7 +13,7 @@ class GameState {
 public:
   virtual ~GameState() noexcept = default;
 
-  virtual void on_enter() { }
+  virtual void on_enter(GameStateManager& gsm) { (void) gsm; }
 
   virtual void on_leave() { }
 

+ 2 - 2
game/GameStateManager.cxx

@@ -3,7 +3,7 @@
 GameStateManager::GameStateManager()
     :states_{{GameStates::Loading}}
 {
-  loading_.on_enter();
+  loading_.on_enter(*this);
 }
 
 GameStateManager::~GameStateManager()
@@ -51,7 +51,7 @@ GameState* GameStateManager::parent()
 void GameStateManager::push_state(GameStates const new_state)
 {
   states_.push(new_state);
-  current()->on_enter();
+  current()->on_enter(*this);
 }
 
 void GameStateManager::pop_state()

+ 21 - 5
game/MenuState.cxx

@@ -2,21 +2,33 @@
 #include "GameStateManager.hxx"
 #include "../SDLRenderer.hxx"
 
-void MenuState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
+void MenuState::on_enter(GameStateManager& gsm)
 {
-  (void) delta_time;
-
   new_game_button_.set_on_click([&gsm] {
+    if (gsm.parent()!=nullptr)
+      gsm.pop_state();
     gsm.replace_state(GameStates::Game);
   });
 
+  continue_button_.set_on_click([&gsm] {
+    gsm.pop_state();
+  });
+
   quit_button_.set_on_click([&gsm] {
     while (gsm.current()!=nullptr) {
       gsm.pop_state();
     }
   });
+}
+
+void MenuState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
+{
+  (void) delta_time;
+
+  continue_button_.set_visible(gsm.parent()!=nullptr);
 
   new_game_button_.update();
+  continue_button_.update();
   quit_button_.update();
 
   auto const key_state = SDL_GetKeyboardState(nullptr);
@@ -32,16 +44,20 @@ void MenuState::render(SDLRenderer& renderer)
   int screen_w, screen_h;
   SDL_GetRendererOutputSize(renderer, &screen_w, &screen_h);
 
+  int const button_count = continue_button_.is_visible() ? 3 : 2;
+
   int const x = (screen_w-BUTTON_WIDTH)/2;
-  int const y = (screen_h-(2*BUTTON_HEIGHT+20))/2;
+  int const y = (screen_h-(button_count*BUTTON_HEIGHT+(button_count-1)*20))/2;
 
   new_game_button_.move(x, y);
-  quit_button_.move(x, y+BUTTON_HEIGHT+20);
+  continue_button_.move(x, y+BUTTON_HEIGHT+20);
+  quit_button_.move(x, y+(button_count-1)*(BUTTON_HEIGHT+20));
 
   SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
   SDL_RenderClear(renderer);
 
   new_game_button_.render(renderer);
+  continue_button_.render(renderer);
   quit_button_.render(renderer);
 
   SDL_RenderPresent(renderer);

+ 5 - 2
game/MenuState.hxx

@@ -8,15 +8,18 @@
 
 class MenuState final : public GameState {
 public:
+  void on_enter(GameStateManager& gsm) override;
+
   void update(GameStateManager& gsm, std::chrono::milliseconds delta_time) override;
 
   void render(SDLRenderer& renderer) override;
 
 private:
-  static int const BUTTON_HEIGHT = 80;
-  static int const BUTTON_WIDTH = 300;
+  static int constexpr BUTTON_HEIGHT = 80;
+  static int constexpr BUTTON_WIDTH = 300;
 
   Button new_game_button_{"New game", 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT};
+  Button continue_button_{"Continue", 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT};
   Button quit_button_{"Quit", 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT};
   bool escape_pressed_{false};
 };

+ 2 - 1
game/SplashState.cxx

@@ -62,8 +62,9 @@ void SplashState::render(SDLRenderer& renderer)
   SDL_RenderPresent(renderer);
 }
 
-void SplashState::on_enter()
+void SplashState::on_enter(GameStateManager& gsm)
 {
+  (void) gsm;
   time_in_state_ = 0ms;
   logo_ = AssetManager::instance().get_texture_asset("logo.jpg");
   SDL_SetTextureBlendMode(logo_, SDL_BLENDMODE_BLEND);

+ 1 - 1
game/SplashState.hxx

@@ -9,7 +9,7 @@
 
 class SplashState final : public GameState {
 public:
-  void on_enter() override;
+  void on_enter(GameStateManager& gsm) override;
 
   void update(GameStateManager& gsm, std::chrono::milliseconds delta_time) override;
 

+ 17 - 0
game/ui/Button.cxx

@@ -58,6 +58,7 @@ namespace {
 
 Button::Button(std::string title, int x, int y, int w, int h)
     :title_{std::move(title)}, x_{x}, y_{y}, w_{w}, h_{h}, pressed_{false},
+     visible_{true},
      up_{"blue_button_up.png"},
      down_{"blue_button_down.png"},
      font_{"kenney_pixel.ttf"}
@@ -80,6 +81,9 @@ bool Button::is_pressed() const
 
 void Button::render(SDLRenderer& renderer)
 {
+  if (!visible_)
+    return;
+
   auto const text = TTF_RenderUTF8_Solid(font_, title_.c_str(), {0, 0, 0, SDL_ALPHA_OPAQUE});
   auto const text_ure = SDL_CreateTextureFromSurface(renderer, text);
   SDL_FreeSurface(text);
@@ -127,6 +131,9 @@ void Button::render(SDLRenderer& renderer)
 
 void Button::update()
 {
+  if (!visible_)
+    return;
+
   int mouse_x, mouse_y;
   auto const mouse_button = SDL_GetMouseState(&mouse_x, &mouse_y);
 
@@ -172,3 +179,13 @@ SDL_Rect Button::get_bounding_box() const
 {
   return {x_, y_, w_, h_};
 }
+
+void Button::set_visible(bool const visible)
+{
+  visible_ = visible;
+}
+
+bool Button::is_visible() const
+{
+  return visible_;
+}

+ 5 - 0
game/ui/Button.hxx

@@ -21,6 +21,10 @@ public:
 
   [[nodiscard]] bool is_pressed() const;
 
+  void set_visible(bool visible);
+
+  [[nodiscard]] bool is_visible() const;
+
   void update();
 
   void render(SDLRenderer& renderer);
@@ -39,6 +43,7 @@ private:
   std::string title_;
   int x_, y_, w_, h_;
   bool pressed_;
+  bool visible_;
   std::function<void()> on_click_;
 
   Asset<SDL_Texture*> up_;