فهرست منبع

:sparkles: implemented main menu

Felix Bytow 1 سال پیش
والد
کامیت
01859117ce
7فایلهای تغییر یافته به همراه127 افزوده شده و 5 حذف شده
  1. 1 0
      CMakeLists.txt
  2. 25 5
      game/GameStateManager.cxx
  3. 6 0
      game/GameStateManager.hxx
  4. 48 0
      game/MenuState.cxx
  5. 24 0
      game/MenuState.hxx
  6. 17 0
      game/ui/Button.cxx
  7. 6 0
      game/ui/Button.hxx

+ 1 - 0
CMakeLists.txt

@@ -35,6 +35,7 @@ add_executable(Snake WIN32
     game/GameStateManager.cxx game/GameStateManager.hxx
     game/LoadingState.cxx game/LoadingState.hxx
     game/SplashState.cxx game/SplashState.hxx
+    game/MenuState.cxx game/MenuState.hxx
     game/DummyState.cxx game/DummyState.hxx
     game/AssetManager.cxx game/AssetManager.hxx
     game/ui/Button.cxx game/ui/Button.hxx

+ 25 - 5
game/GameStateManager.cxx

@@ -13,21 +13,41 @@ GameStateManager::~GameStateManager()
   }
 }
 
-GameState* GameStateManager::current()
+GameState* GameStateManager::enum_to_state(GameStates const state)
 {
-  if (states_.empty())
-    return nullptr;
-
-  switch (states_.top()) {
+  switch (state) {
   default:
     return &dummy_; // TODO: handle all game states
   case GameStates::Loading:
     return &loading_;
   case GameStates::Splash:
     return &splash_;
+  case GameStates::MainMenu:
+    return &menu_;
   }
 }
 
+GameState* GameStateManager::current()
+{
+  if (states_.empty())
+    return nullptr;
+
+  return enum_to_state(states_.top());
+}
+
+GameState* GameStateManager::parent()
+{
+  if (states_.size()<2)
+    return nullptr;
+
+  auto const current = states_.top();
+  states_.pop();
+  auto const parent = states_.top();
+  states_.push(current);
+
+  return enum_to_state(parent);
+}
+
 void GameStateManager::push_state(GameStates const new_state)
 {
   states_.push(new_state);

+ 6 - 0
game/GameStateManager.hxx

@@ -5,6 +5,7 @@
 
 #include "LoadingState.hxx"
 #include "SplashState.hxx"
+#include "MenuState.hxx"
 #include "DummyState.hxx"
 
 #include <stack>
@@ -29,6 +30,8 @@ public:
 
   GameState* current();
 
+  GameState* parent();
+
   void push_state(GameStates new_state);
 
   void pop_state();
@@ -38,8 +41,11 @@ public:
 private:
   std::stack<GameStates> states_;
 
+  GameState* enum_to_state(GameStates state);
+
   LoadingState loading_;
   SplashState splash_;
+  MenuState menu_;
   DummyState dummy_;
 };
 

+ 48 - 0
game/MenuState.cxx

@@ -0,0 +1,48 @@
+#include "MenuState.hxx"
+#include "GameStateManager.hxx"
+#include "../SDLRenderer.hxx"
+
+void MenuState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
+{
+  (void) delta_time;
+
+  new_game_button_.set_on_click([&gsm] {
+    gsm.replace_state(GameStates::Game);
+  });
+
+  quit_button_.set_on_click([&gsm] {
+    while (gsm.current()!=nullptr) {
+      gsm.pop_state();
+    }
+  });
+
+  new_game_button_.update();
+  quit_button_.update();
+
+  auto const key_state = SDL_GetKeyboardState(nullptr);
+  auto const escape_pressed = !!key_state[SDL_SCANCODE_ESCAPE];
+  if (!escape_pressed && escape_pressed_) {
+    gsm.pop_state();
+  }
+  escape_pressed_ = escape_pressed;
+}
+
+void MenuState::render(SDLRenderer& renderer)
+{
+  int screen_w, screen_h;
+  SDL_GetRendererOutputSize(renderer, &screen_w, &screen_h);
+
+  int const x = (screen_w-BUTTON_WIDTH)/2;
+  int const y = (screen_h-(2*BUTTON_HEIGHT+20))/2;
+
+  new_game_button_.move(x, y);
+  quit_button_.move(x, y+BUTTON_HEIGHT+20);
+
+  SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
+  SDL_RenderClear(renderer);
+
+  new_game_button_.render(renderer);
+  quit_button_.render(renderer);
+
+  SDL_RenderPresent(renderer);
+}

+ 24 - 0
game/MenuState.hxx

@@ -0,0 +1,24 @@
+#pragma once
+
+#ifndef SNAKE_MENUSTATE_HXX
+#define SNAKE_MENUSTATE_HXX
+
+#include "GameState.hxx"
+#include "ui/Button.hxx"
+
+class MenuState final : public GameState {
+public:
+  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;
+
+  Button new_game_button_{"New game", 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT};
+  Button quit_button_{"Quit", 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT};
+  bool escape_pressed_{false};
+};
+
+#endif // SNAKE_MENUSTATE_HXX

+ 17 - 0
game/ui/Button.cxx

@@ -343,3 +343,20 @@ void Button::set_on_click(std::function<void()> handler)
 {
   on_click_ = std::move(handler);
 }
+
+void Button::move(int const x, int const y)
+{
+  x_ = x;
+  y_ = y;
+}
+
+void Button::resize(int const w, int const h)
+{
+  w_ = w;
+  h_ = h;
+}
+
+SDL_Rect Button::get_bounding_box() const
+{
+  return {x_, y_, w_, h_};
+}

+ 6 - 0
game/ui/Button.hxx

@@ -28,6 +28,12 @@ public:
 
   void set_on_click(std::function<void()> handler);
 
+  void move(int x, int y);
+
+  void resize(int w, int h);
+
+  SDL_Rect get_bounding_box() const;
+
 private:
   std::string title_;
   int x_, y_, w_, h_;