From d11821866238b2dd0f35f781dc2eb040d3b437ac Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 20 May 2026 19:30:55 +0200 Subject: [PATCH] =?UTF-8?q?refactor(#28):=20Input=20rep=20Config::PlayerBi?= =?UTF-8?q?ndings=20per=20par=C3=A0metre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pas 3/N del hallazgo #28. Input deixa d'incloure game/options.hpp. Els antics applyPlayerXFromOptions es renombren a applyPlayerXBindings(const Config::PlayerBindings&) i reben els bindings per paràmetre en lloc de llegir-los del global Options::*. El Director hi passa Options::player1/2 als call-sites. Esborrats applyKeyboardBindingsFromOptions i applyGamepadBindingsFromOptions que no eren cridats per ningú (dead code aprofitat). Co-Authored-By: Claude Opus 4.7 (1M context) --- source/core/input/input.cpp | 78 ++++------- source/core/input/input.hpp | 237 ++++++++++++++++---------------- source/core/system/director.cpp | 4 +- 3 files changed, 144 insertions(+), 175 deletions(-) diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 5a718d3..5009840 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -8,8 +8,6 @@ #include // Para unordered_map, _Node_iterator, operator==, _Node_iterator_base, _Node_const_iterator #include // Para move -#include "game/options.hpp" // Para Options::controls - // Singleton Input* Input::instance = nullptr; @@ -51,34 +49,6 @@ void Input::bindKey(Action action, SDL_Scancode code) { keyboard_.bindings[action].scancode = code; } -// Aplica las teclas configuradas desde Options -void Input::applyKeyboardBindingsFromOptions() { - bindKey(Action::LEFT, Options::keyboard_controls.key_left); - bindKey(Action::RIGHT, Options::keyboard_controls.key_right); - bindKey(Action::THRUST, Options::keyboard_controls.key_thrust); -} - -// Aplica configuración de botones del gamepad desde Options al primer gamepad conectado -void Input::applyGamepadBindingsFromOptions() { - // Si no hay gamepads conectados, no hay nada que hacer - if (gamepads_.empty()) { - return; - } - - // Obtener el primer gamepad conectado - const auto& gamepad = gamepads_[0]; - - // Aplicar bindings desde Options - // Los valores pueden ser: - // - 0-20+: Botones SDL_GamepadButton (DPAD, face buttons, shoulders) - // - 100: L2 trigger - // - 101: R2 trigger - // - 200+: Ejes del stick analógico - gamepad->bindings[Action::LEFT].button = Options::gamepad_controls.button_left; - gamepad->bindings[Action::RIGHT].button = Options::gamepad_controls.button_right; - gamepad->bindings[Action::THRUST].button = Options::gamepad_controls.button_thrust; -} - // Asigna inputs a botones del mando void Input::bindGameControllerButton(const std::shared_ptr& gamepad, Action action, SDL_GamepadButton button) { if (gamepad != nullptr) { @@ -494,22 +464,22 @@ auto Input::findAvailableGamepadByName(const std::string& gamepad_name) -> std:: // ========== MÉTODOS ESPECÍFICOS POR JUGADOR (ORNI) ========== // Aplica configuración de controles del player 1 -void Input::applyPlayer1BindingsFromOptions() { +void Input::applyPlayer1Bindings(const Config::PlayerBindings& bindings) { // 1. Aplicar bindings de teclado (NO usar bindKey, llenar mapa específico) - player1_keyboard_bindings_[Action::LEFT].scancode = Options::player1.keyboard.key_left; - player1_keyboard_bindings_[Action::RIGHT].scancode = Options::player1.keyboard.key_right; - player1_keyboard_bindings_[Action::THRUST].scancode = Options::player1.keyboard.key_thrust; - player1_keyboard_bindings_[Action::SHOOT].scancode = Options::player1.keyboard.key_shoot; - player1_keyboard_bindings_[Action::START].scancode = Options::player1.keyboard.key_start; + player1_keyboard_bindings_[Action::LEFT].scancode = bindings.keyboard.key_left; + player1_keyboard_bindings_[Action::RIGHT].scancode = bindings.keyboard.key_right; + player1_keyboard_bindings_[Action::THRUST].scancode = bindings.keyboard.key_thrust; + player1_keyboard_bindings_[Action::SHOOT].scancode = bindings.keyboard.key_shoot; + player1_keyboard_bindings_[Action::START].scancode = bindings.keyboard.key_start; // 2. Encontrar gamepad por nombre (o usar primer gamepad como fallback) std::shared_ptr gamepad = nullptr; - if (Options::player1.gamepad_name.empty()) { + if (bindings.gamepad_name.empty()) { // Fallback: usar primer gamepad disponible gamepad = (!gamepads_.empty()) ? gamepads_[0] : nullptr; } else { // Buscar por nombre - gamepad = findAvailableGamepadByName(Options::player1.gamepad_name); + gamepad = findAvailableGamepadByName(bindings.gamepad_name); } if (!gamepad) { @@ -518,32 +488,32 @@ void Input::applyPlayer1BindingsFromOptions() { } // 3. Aplicar bindings de gamepad - gamepad->bindings[Action::LEFT].button = Options::player1.gamepad.button_left; - gamepad->bindings[Action::RIGHT].button = Options::player1.gamepad.button_right; - gamepad->bindings[Action::THRUST].button = Options::player1.gamepad.button_thrust; - gamepad->bindings[Action::SHOOT].button = Options::player1.gamepad.button_shoot; + gamepad->bindings[Action::LEFT].button = bindings.gamepad.button_left; + gamepad->bindings[Action::RIGHT].button = bindings.gamepad.button_right; + gamepad->bindings[Action::THRUST].button = bindings.gamepad.button_thrust; + gamepad->bindings[Action::SHOOT].button = bindings.gamepad.button_shoot; // 4. Cachear referencia player1_gamepad_ = gamepad; } // Aplica configuración de controles del player 2 -void Input::applyPlayer2BindingsFromOptions() { +void Input::applyPlayer2Bindings(const Config::PlayerBindings& bindings) { // 1. Aplicar bindings de teclado (mapa específico de P2, no sobrescribe P1) - player2_keyboard_bindings_[Action::LEFT].scancode = Options::player2.keyboard.key_left; - player2_keyboard_bindings_[Action::RIGHT].scancode = Options::player2.keyboard.key_right; - player2_keyboard_bindings_[Action::THRUST].scancode = Options::player2.keyboard.key_thrust; - player2_keyboard_bindings_[Action::SHOOT].scancode = Options::player2.keyboard.key_shoot; - player2_keyboard_bindings_[Action::START].scancode = Options::player2.keyboard.key_start; + player2_keyboard_bindings_[Action::LEFT].scancode = bindings.keyboard.key_left; + player2_keyboard_bindings_[Action::RIGHT].scancode = bindings.keyboard.key_right; + player2_keyboard_bindings_[Action::THRUST].scancode = bindings.keyboard.key_thrust; + player2_keyboard_bindings_[Action::SHOOT].scancode = bindings.keyboard.key_shoot; + player2_keyboard_bindings_[Action::START].scancode = bindings.keyboard.key_start; // 2. Encontrar gamepad por nombre (o usar segundo gamepad como fallback) std::shared_ptr gamepad = nullptr; - if (Options::player2.gamepad_name.empty()) { + if (bindings.gamepad_name.empty()) { // Fallback: usar segundo gamepad disponible gamepad = (gamepads_.size() > 1) ? gamepads_[1] : nullptr; } else { // Buscar por nombre - gamepad = findAvailableGamepadByName(Options::player2.gamepad_name); + gamepad = findAvailableGamepadByName(bindings.gamepad_name); } if (!gamepad) { @@ -552,10 +522,10 @@ void Input::applyPlayer2BindingsFromOptions() { } // 3. Aplicar bindings de gamepad - gamepad->bindings[Action::LEFT].button = Options::player2.gamepad.button_left; - gamepad->bindings[Action::RIGHT].button = Options::player2.gamepad.button_right; - gamepad->bindings[Action::THRUST].button = Options::player2.gamepad.button_thrust; - gamepad->bindings[Action::SHOOT].button = Options::player2.gamepad.button_shoot; + gamepad->bindings[Action::LEFT].button = bindings.gamepad.button_left; + gamepad->bindings[Action::RIGHT].button = bindings.gamepad.button_right; + gamepad->bindings[Action::THRUST].button = bindings.gamepad.button_thrust; + gamepad->bindings[Action::SHOOT].button = bindings.gamepad.button_shoot; // 4. Cachear referencia player2_gamepad_ = gamepad; diff --git a/source/core/input/input.hpp b/source/core/input/input.hpp index 30eff20..541c3b4 100644 --- a/source/core/input/input.hpp +++ b/source/core/input/input.hpp @@ -9,153 +9,152 @@ #include // Para unordered_map #include // Para vector +#include "core/config/engine_config.hpp" #include "core/input/input_types.hpp" // for InputAction // --- Clase Input: gestiona la entrada de teclado y mandos (singleton) --- class Input { - public: - // --- Constantes --- - static constexpr bool ALLOW_REPEAT = true; // Permite repetición - static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición - static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado - static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado - static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón - static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón + public: + // --- Constantes --- + static constexpr bool ALLOW_REPEAT = true; // Permite repetición + static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición + static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado + static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado + static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón + static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón - // --- Tipos --- - using Action = InputAction; // Alias para mantener compatibilidad + // --- Tipos --- + using Action = InputAction; // Alias para mantener compatibilidad - // --- Estructuras --- - struct KeyState { - Uint8 scancode{0}; // Scancode asociado - bool is_held{false}; // Está pulsada ahora mismo - bool just_pressed{false}; // Se acaba de pulsar en este fotograma - }; + // --- Estructuras --- + struct KeyState { + Uint8 scancode{0}; // Scancode asociado + bool is_held{false}; // Está pulsada ahora mismo + bool just_pressed{false}; // Se acaba de pulsar en este fotograma + }; - struct ButtonState { - int button{static_cast(SDL_GAMEPAD_BUTTON_INVALID)}; // GameControllerButton asociado - bool is_held{false}; // Está pulsada ahora mismo - bool just_pressed{false}; // Se acaba de pulsar en este fotograma - bool axis_active{false}; // Estado del eje - bool trigger_active{false}; // Estado del trigger como botón digital - }; + struct ButtonState { + int button{static_cast(SDL_GAMEPAD_BUTTON_INVALID)}; // GameControllerButton asociado + bool is_held{false}; // Está pulsada ahora mismo + bool just_pressed{false}; // Se acaba de pulsar en este fotograma + bool axis_active{false}; // Estado del eje + bool trigger_active{false}; // Estado del trigger como botón digital + }; - struct Keyboard { - std::unordered_map bindings; // Mapa de acciones a estados de tecla - }; + struct Keyboard { + std::unordered_map bindings; // Mapa de acciones a estados de tecla + }; - struct Gamepad { - SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL - SDL_JoystickID instance_id{0}; // ID de instancia del joystick - std::string name; // Nombre del gamepad - std::string path; // Ruta del dispositivo - std::unordered_map bindings; // Mapa de acciones a estados de botón + struct Gamepad { + SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL + SDL_JoystickID instance_id{0}; // ID de instancia del joystick + std::string name; // Nombre del gamepad + std::string path; // Ruta del dispositivo + std::unordered_map bindings; // Mapa de acciones a estados de botón - explicit Gamepad(SDL_Gamepad* gamepad) - : pad(gamepad), - instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))), - name(std::string(SDL_GetGamepadName(gamepad))), - path(std::string(SDL_GetGamepadPath(pad))), - bindings{ - // Movimiento y acciones del player - {Action::LEFT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}}, - {Action::RIGHT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}}, - {Action::THRUST, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_WEST)}}, - {Action::SHOOT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_SOUTH)}}} {} + explicit Gamepad(SDL_Gamepad* gamepad) + : pad(gamepad), + instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))), + name(std::string(SDL_GetGamepadName(gamepad))), + path(std::string(SDL_GetGamepadPath(pad))), + bindings{ + // Movimiento y acciones del player + {Action::LEFT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}}, + {Action::RIGHT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}}, + {Action::THRUST, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_WEST)}}, + {Action::SHOOT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_SOUTH)}}} {} - ~Gamepad() { - if (pad != nullptr) { - SDL_CloseGamepad(pad); - } - } + ~Gamepad() { + if (pad != nullptr) { + SDL_CloseGamepad(pad); + } + } - // Reasigna un botón a una acción - void rebindAction(Action action, SDL_GamepadButton new_button) { - bindings[action].button = static_cast(new_button); - } - }; + // Reasigna un botón a una acción + void rebindAction(Action action, SDL_GamepadButton new_button) { + bindings[action].button = static_cast(new_button); + } + }; - // --- Tipos --- - using Gamepads = std::vector>; // Vector de gamepads + // --- Tipos --- + using Gamepads = std::vector>; // Vector de gamepads - // --- Singleton --- - static void init(const std::string& game_controller_db_path); - static void destroy(); - static auto get() -> Input*; + // --- Singleton --- + static void init(const std::string& game_controller_db_path); + static void destroy(); + static auto get() -> Input*; - // --- Actualización del sistema --- - void update(); // Actualiza estados de entrada + // --- Actualización del sistema --- + void update(); // Actualiza estados de entrada - // --- Configuración de controles --- - void bindKey(Action action, SDL_Scancode code); - void applyKeyboardBindingsFromOptions(); - void applyGamepadBindingsFromOptions(); + // --- Configuración de controles --- + void bindKey(Action action, SDL_Scancode code); - // Configuración por player (Orni - dos jugadores) - void applyPlayer1BindingsFromOptions(); - void applyPlayer2BindingsFromOptions(); + // Configuración por player (Orni - dos jugadores) + void applyPlayer1Bindings(const Config::PlayerBindings& bindings); + void applyPlayer2Bindings(const Config::PlayerBindings& bindings); - static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action, SDL_GamepadButton button); - static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action_target, Action action_source); + static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action, SDL_GamepadButton button); + static void bindGameControllerButton(const std::shared_ptr& gamepad, Action action_target, Action action_source); - // --- Consulta de entrada --- - auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; - auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; - auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool; - void resetInputStates(); + // --- Consulta de entrada --- + auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; + auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr& gamepad = nullptr) -> bool; + auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool; + void resetInputStates(); - // Consulta por player (Orni - dos jugadores) - auto checkActionPlayer1(Action action, bool repeat = true) -> bool; - auto checkActionPlayer2(Action action, bool repeat = true) -> bool; + // Consulta por player (Orni - dos jugadores) + auto checkActionPlayer1(Action action, bool repeat = true) -> bool; + auto checkActionPlayer2(Action action, bool repeat = true) -> bool; - // Check if any player pressed any action from a list - auto checkAnyPlayerAction(const std::span& actions, bool repeat = DO_NOT_ALLOW_REPEAT) -> bool; + // Check if any player pressed any action from a list + auto checkAnyPlayerAction(const std::span& actions, bool repeat = DO_NOT_ALLOW_REPEAT) -> bool; - // --- Gestión de gamepads --- - [[nodiscard]] auto gameControllerFound() const -> bool; - [[nodiscard]] auto getNumGamepads() const -> int; - [[nodiscard]] auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr; - [[nodiscard]] auto getGamepadByName(const std::string& name) const -> std::shared_ptr; - [[nodiscard]] auto getGamepads() const -> const Gamepads& { return gamepads_; } - auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr; - static auto getControllerName(const std::shared_ptr& gamepad) -> std::string; - [[nodiscard]] auto getControllerNames() const -> std::vector; - [[nodiscard]] static auto getControllerBinding(const std::shared_ptr& gamepad, Action action) -> SDL_GamepadButton; - void printConnectedGamepads() const; + // --- Gestión de gamepads --- + [[nodiscard]] auto gameControllerFound() const -> bool; + [[nodiscard]] auto getNumGamepads() const -> int; + [[nodiscard]] auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr; + [[nodiscard]] auto getGamepadByName(const std::string& name) const -> std::shared_ptr; + [[nodiscard]] auto getGamepads() const -> const Gamepads& { return gamepads_; } + auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr; + static auto getControllerName(const std::shared_ptr& gamepad) -> std::string; + [[nodiscard]] auto getControllerNames() const -> std::vector; + [[nodiscard]] static auto getControllerBinding(const std::shared_ptr& gamepad, Action action) -> SDL_GamepadButton; + void printConnectedGamepads() const; - // --- Eventos --- - auto handleEvent(const SDL_Event& event) -> std::string; + // --- Eventos --- + auto handleEvent(const SDL_Event& event) -> std::string; - private: - // --- Constantes --- - static constexpr Sint16 AXIS_THRESHOLD = 30000; // Umbral para ejes analógicos - static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (50% del rango) - static constexpr std::array BUTTON_INPUTS = {Action::SHOOT}; // Inputs que usan botones + private: + // --- Constantes --- + static constexpr Sint16 AXIS_THRESHOLD = 30000; // Umbral para ejes analógicos + static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (50% del rango) + static constexpr std::array BUTTON_INPUTS = {Action::SHOOT}; // Inputs que usan botones - // --- Métodos --- - explicit Input(std::string game_controller_db_path); - ~Input() = default; + // --- Métodos --- + explicit Input(std::string game_controller_db_path); + ~Input() = default; - void initSDLGamePad(); - static auto checkAxisInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; - static auto checkTriggerInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; - auto addGamepad(int device_index) -> std::string; - auto removeGamepad(SDL_JoystickID id) -> std::string; - void addGamepadMappingsFromFile(); - void discoverGamepads(); + void initSDLGamePad(); + static auto checkAxisInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; + static auto checkTriggerInput(Action action, const std::shared_ptr& gamepad, bool repeat) -> bool; + auto addGamepad(int device_index) -> std::string; + auto removeGamepad(SDL_JoystickID id) -> std::string; + void addGamepadMappingsFromFile(); + void discoverGamepads(); - // --- Variables miembro --- - static Input* instance; // Instancia única del singleton + // --- Variables miembro --- + static Input* instance; // Instancia única del singleton - Gamepads gamepads_; // Lista de gamepads conectados - Keyboard keyboard_{}; // Estado del teclado (solo acciones globales) - std::string gamepad_mappings_file_; // Ruta al archivo de mappings + Gamepads gamepads_; // Lista de gamepads conectados + Keyboard keyboard_{}; // Estado del teclado (solo acciones globales) + std::string gamepad_mappings_file_; // Ruta al archivo de mappings - // Referencias cacheadas a gamepads por player (Orni) - std::shared_ptr player1_gamepad_; - std::shared_ptr player2_gamepad_; + // Referencias cacheadas a gamepads por player (Orni) + std::shared_ptr player1_gamepad_; + std::shared_ptr player2_gamepad_; - // Mapas de bindings separados por player (Orni - dos jugadores) - std::unordered_map player1_keyboard_bindings_; - std::unordered_map player2_keyboard_bindings_; + // Mapas de bindings separados por player (Orni - dos jugadores) + std::unordered_map player1_keyboard_bindings_; + std::unordered_map player2_keyboard_bindings_; }; \ No newline at end of file diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index b55627e..2296db9 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -99,8 +99,8 @@ Director::Director(std::vector const& args) { Input::init("data/gamecontrollerdb.txt"); // Aplicar configuración de controls dels jugadors - Input::get()->applyPlayer1BindingsFromOptions(); - Input::get()->applyPlayer2BindingsFromOptions(); + Input::get()->applyPlayer1Bindings(Options::player1); + Input::get()->applyPlayer2Bindings(Options::player2); if (Options::console) { std::cout << "Configuración carregada\n";