MenuState.cxx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "MenuState.hxx"
  2. #include "PlayingState.hxx"
  3. #include "GameStateManager.hxx"
  4. #include "../SDLRenderer.hxx"
  5. #include <array>
  6. void MenuState::on_enter(GameStateManager& gsm)
  7. {
  8. active_button_ = 0;
  9. game_.reset();
  10. if (auto const parent = gsm.parent(); parent!=nullptr) {
  11. continue_button_.set_visible(true);
  12. if (auto const game = dynamic_cast<PlayingState*>(parent); game!=nullptr) {
  13. game_ = game;
  14. active_button_ = 1;
  15. }
  16. }
  17. else {
  18. continue_button_.set_visible(false);
  19. }
  20. new_game_button_.set_on_click([&gsm] {
  21. if (gsm.parent()!=nullptr)
  22. gsm.pop_state();
  23. gsm.replace_state(GameStates::Game);
  24. });
  25. continue_button_.set_on_click([&gsm] {
  26. gsm.pop_state();
  27. });
  28. high_score_button_.set_on_click([&gsm] {
  29. gsm.push_state(GameStates::HighScores);
  30. });
  31. credits_button_.set_on_click([&gsm] {
  32. gsm.push_state(GameStates::Credits);
  33. });
  34. quit_button_.set_on_click([&gsm] {
  35. while (gsm.current()!=nullptr) {
  36. gsm.pop_state();
  37. }
  38. });
  39. SDL_ShowCursor(SDL_ENABLE);
  40. }
  41. void MenuState::on_event(GameStateManager& gsm, SDL_Event const& evt)
  42. {
  43. if (evt.type==SDL_KEYUP) {
  44. switch (evt.key.keysym.scancode) {
  45. default:
  46. break;
  47. case SDL_SCANCODE_PAUSE:
  48. if (gsm.parent()==nullptr)
  49. break;
  50. [[fallthrough]];
  51. case SDL_SCANCODE_ESCAPE:
  52. gsm.pop_state();
  53. break;
  54. case SDL_SCANCODE_UP:
  55. SDL_ShowCursor(SDL_DISABLE);
  56. --active_button_;
  57. if (active_button_<0)
  58. active_button_ = 4;
  59. else if (active_button_==1 && !continue_button_.is_visible())
  60. active_button_ = 0;
  61. break;
  62. case SDL_SCANCODE_DOWN:
  63. SDL_ShowCursor(SDL_DISABLE);
  64. ++active_button_;
  65. if (active_button_>4)
  66. active_button_ = 0;
  67. else if (active_button_==1 && !continue_button_.is_visible())
  68. active_button_ = 2;
  69. break;
  70. case SDL_SCANCODE_RETURN:
  71. switch (active_button_) {
  72. case 0:
  73. new_game_button_.trigger();
  74. break;
  75. case 1:
  76. continue_button_.trigger();
  77. break;
  78. case 2:
  79. high_score_button_.trigger();
  80. break;
  81. case 3:
  82. credits_button_.trigger();
  83. break;
  84. case 4:
  85. quit_button_.trigger();
  86. break;
  87. }
  88. break;
  89. }
  90. }
  91. else if (evt.type==SDL_MOUSEMOTION) {
  92. SDL_ShowCursor(SDL_ENABLE);
  93. auto const x = evt.motion.x;
  94. auto const y = evt.motion.y;
  95. std::array<Button*, 5> buttons{&new_game_button_, nullptr, &high_score_button_, &credits_button_, &quit_button_};
  96. if (continue_button_.is_visible())
  97. buttons[1] = &continue_button_;
  98. for (std::size_t n = 0; n<buttons.size(); ++n) {
  99. if (buttons[n]==nullptr)
  100. continue;
  101. auto const box = buttons[n]->get_bounding_box();
  102. if (x>=box.x && x<=box.x+box.w && y>=box.y && y<=box.y+box.h) {
  103. active_button_ = static_cast<int>(n);
  104. break;
  105. }
  106. }
  107. }
  108. }
  109. void MenuState::update(GameStateManager& gsm, std::chrono::milliseconds const delta_time)
  110. {
  111. (void) delta_time;
  112. auto adjust_button_size = [this, idx = 0](Button& btn) mutable {
  113. if (idx++==active_button_) {
  114. btn.resize(BUTTON_WIDTH, BUTTON_HEIGHT);
  115. }
  116. else {
  117. btn.resize(BUTTON_WIDTH-ACTIVE_SIZE_DIFF, BUTTON_HEIGHT-ACTIVE_SIZE_DIFF);
  118. }
  119. };
  120. for (auto const btn: {&new_game_button_, &continue_button_, &high_score_button_, &credits_button_, &quit_button_}) {
  121. adjust_button_size(*btn);
  122. btn->update();
  123. }
  124. }
  125. void MenuState::render(SDLRenderer& renderer)
  126. {
  127. int screen_w, screen_h;
  128. SDL_GetRendererOutputSize(renderer, &screen_w, &screen_h);
  129. int const button_count = continue_button_.is_visible() ? 5 : 4;
  130. int const x = (screen_w-BUTTON_WIDTH)/2;
  131. int y = (screen_h-(button_count*BUTTON_HEIGHT+(button_count-1)*20))/2;
  132. auto const adjust_button_position = [](Button& btn, int x, int y) {
  133. auto const box = btn.get_bounding_box();
  134. auto const dw = BUTTON_WIDTH-box.w;
  135. auto const dh = BUTTON_HEIGHT-box.h;
  136. btn.move(x+dw/2, y+dh/2);
  137. };
  138. adjust_button_position(new_game_button_, x, y);
  139. if (continue_button_.is_visible()) {
  140. adjust_button_position(continue_button_, x, y += BUTTON_HEIGHT+20);
  141. }
  142. adjust_button_position(high_score_button_, x, y += BUTTON_HEIGHT+20);
  143. adjust_button_position(credits_button_, x, y += BUTTON_HEIGHT+20);
  144. adjust_button_position(quit_button_, x, y+BUTTON_HEIGHT+20);
  145. SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
  146. SDL_RenderClear(renderer);
  147. if (game_.has_value()) {
  148. game_.value()->render_game(renderer, false);
  149. }
  150. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 200);
  151. SDL_RenderFillRect(renderer, nullptr);
  152. new_game_button_.render(renderer);
  153. continue_button_.render(renderer);
  154. high_score_button_.render(renderer);
  155. credits_button_.render(renderer);
  156. quit_button_.render(renderer);
  157. SDL_RenderPresent(renderer);
  158. }
  159. void MenuState::on_leave()
  160. {
  161. SDL_ShowCursor(SDL_DISABLE);
  162. }