Bläddra i källkod

:sparkles: finished first version of controller support

game over screen may be reworked later for controller-only systems
also haptic may be added when hitting objects
Felix Bytow 1 år sedan
förälder
incheckning
274bca7d7d
6 ändrade filer med 66 tillägg och 8 borttagningar
  1. 1 1
      CMakeLists.txt
  2. 5 0
      SDL.cxx
  3. 2 0
      SDL.hxx
  4. 15 0
      game/GameOverState.cxx
  5. 15 0
      game/HighScoreState.cxx
  6. 28 7
      game/PlayingState.cxx

+ 1 - 1
CMakeLists.txt

@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.27)
-project(Snake VERSION 1.1.0.0)
+project(Snake VERSION 1.2.0.0)
 
 set(CMAKE_CXX_STANDARD 23)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)

+ 5 - 0
SDL.cxx

@@ -100,4 +100,9 @@ void SDL::remove_controller(int which)
   }
 }
 
+std::vector<SDL_GameController*> const& SDL::get_controllers() const
+{
+  return controllers_;
+}
+
 

+ 2 - 0
SDL.hxx

@@ -50,6 +50,8 @@ public:
 
   void remove_controller(int which);
 
+  std::vector<SDL_GameController *> const& get_controllers() const;
+
 private:
   static SDL* instance_;
 

+ 15 - 0
game/GameOverState.cxx

@@ -58,6 +58,21 @@ void GameOverState::on_event(GameStateManager& gsm, SDL_Event const& evt)
       gsm.replace_state(GameStates::MainMenu);
       break;
     }
+  } else if (evt.type==SDL_CONTROLLERBUTTONUP) {
+    switch (evt.cbutton.which) {
+    default:
+      break;
+    // TODO: for full controller support, the input must provide an onscreen keyboard
+    // in that case the controller buttons etc. used to interact with this state will need adjustment
+    case SDL_CONTROLLER_BUTTON_A:
+      HighScoreManager::instance().provide_name_for_new_score(name_input_.value());
+      [[fallthrough]];
+    case SDL_CONTROLLER_BUTTON_B:
+      [[fallthrough]];
+    case SDL_CONTROLLER_BUTTON_START:
+      gsm.replace_state(GameStates::MainMenu);
+      break;
+    }
   }
 }
 

+ 15 - 0
game/HighScoreState.cxx

@@ -18,11 +18,26 @@ void HighScoreState::on_event(GameStateManager& gsm, SDL_Event const& event)
       break;
     case SDL_SCANCODE_ESCAPE:
       [[fallthrough]];
+    case SDL_SCANCODE_SPACE:
+      [[fallthrough]];
     case SDL_SCANCODE_RETURN:
       gsm.pop_state();
       break;
     }
   }
+  else if (event.type==SDL_CONTROLLERBUTTONUP) {
+    switch (event.cbutton.which) {
+    default:
+      break;
+    case SDL_CONTROLLER_BUTTON_A:
+      [[fallthrough]];
+    case SDL_CONTROLLER_BUTTON_B:
+      [[fallthrough]];
+    case SDL_CONTROLLER_BUTTON_START:
+      gsm.pop_state();
+      break;
+    }
+  }
 }
 
 void HighScoreState::render(SDLRenderer& renderer)

+ 28 - 7
game/PlayingState.cxx

@@ -96,6 +96,11 @@ void PlayingState::on_event(GameStateManager& gsm, SDL_Event const& evt)
     if (scancode==SDL_SCANCODE_ESCAPE || scancode==SDL_SCANCODE_PAUSE)
       gsm.push_state(GameStates::MainMenu);
   }
+  else if (evt.type==SDL_CONTROLLERBUTTONUP) {
+    auto const button = evt.cbutton.button;
+    if (button==SDL_CONTROLLER_BUTTON_START)
+      gsm.push_state(GameStates::MainMenu);
+  }
 }
 
 void PlayingState::update(GameStateManager& gsm, std::chrono::milliseconds const delta_time)
@@ -176,27 +181,43 @@ void PlayingState::update(GameStateManager& gsm, std::chrono::milliseconds const
 
 void PlayingState::handle_direction_change()
 {
-  // this is not done in the event handler as we don't want to wait for KEYUP to re-fire in certain situations
-  auto const keyboard = SDL_GetKeyboardState(nullptr);
-
   if (new_direction_.has_value())
     return;
 
+  // this is not done in the event handler as we don't want to wait for KEYDOWN to re-fire in certain situations
+  auto const keyboard = SDL_GetKeyboardState(nullptr);
+  auto const& controllers = SDL::instance().get_controllers();
+  bool controller_up = false, controller_down = false, controller_left = false, controller_right = false;
+  for (auto const controller: controllers) {
+    controller_up = controller_up
+        || (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)==1)
+        || (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)<-13'000);
+    controller_down = controller_down
+        || (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)==1)
+        || (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)>13'000);
+    controller_left = controller_left
+        || (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)==1)
+        || (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)<-13'000);
+    controller_right = controller_right
+        || (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)==1)
+        || (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)>13'000);
+  }
+
   if (direction_==Direction::Left || direction_==Direction::Right) {
-    if (keyboard[SDL_SCANCODE_UP] || keyboard[SDL_SCANCODE_W]) {
+    if (keyboard[SDL_SCANCODE_UP] || keyboard[SDL_SCANCODE_W] || controller_up) {
       new_direction_ = Direction::Up;
     }
 
-    else if (keyboard[SDL_SCANCODE_DOWN] || keyboard[SDL_SCANCODE_S]) {
+    else if (keyboard[SDL_SCANCODE_DOWN] || keyboard[SDL_SCANCODE_S] || controller_down) {
       new_direction_ = Direction::Down;
     }
   }
   else {
-    if (keyboard[SDL_SCANCODE_LEFT] || keyboard[SDL_SCANCODE_A]) {
+    if (keyboard[SDL_SCANCODE_LEFT] || keyboard[SDL_SCANCODE_A] || controller_left) {
       new_direction_ = Direction::Left;
     }
 
-    else if (keyboard[SDL_SCANCODE_RIGHT] || keyboard[SDL_SCANCODE_D]) {
+    else if (keyboard[SDL_SCANCODE_RIGHT] || keyboard[SDL_SCANCODE_D] || controller_right) {
       new_direction_ = Direction::Right;
     }
   }