diff --git a/source/credits.cpp b/source/credits.cpp index 743b3c8..d2d13d7 100644 --- a/source/credits.cpp +++ b/source/credits.cpp @@ -144,7 +144,7 @@ void Credits::checkInput() if (!ServiceMenu::get()->isEnabled()) { // Comprueba si se ha pulsado cualquier botón (de los usados para jugar) - if (Input::get()->checkAnyButtonPressed(INPUT_ALLOW_REPEAT)) + if (Input::get()->checkAnyButton(INPUT_ALLOW_REPEAT)) { want_to_pass_ = true; fading_ = mini_logo_on_position_; diff --git a/source/define_buttons.cpp b/source/define_buttons.cpp index 9f87f63..1d7243d 100644 --- a/source/define_buttons.cpp +++ b/source/define_buttons.cpp @@ -58,6 +58,10 @@ void DefineButtons::bindButtons() { input_->bindGameControllerButton(index_controller_, button.input, button.button); } + + // Remapea los inputs a inputs + input_->bindGameControllerButton(index_controller_, InputAction::SM_SELECT, InputAction::FIRE_LEFT); + input_->bindGameControllerButton(index_controller_, InputAction::SM_BACK, InputAction::FIRE_CENTER); } // Comprueba los eventos diff --git a/source/game.cpp b/source/game.cpp index 02d8789..9846a15 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -1353,8 +1353,7 @@ void Game::checkPauseInput() // Comprueba los mandos for (int i = 0; i < input_->getNumControllers(); ++i) { - if (input_->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) && - input_->checkInput(InputAction::PAUSE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) + if (input_->checkInput(InputAction::PAUSE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { pause(!paused_); return; @@ -1372,7 +1371,7 @@ void Game::checkPauseInput() // Gestiona las entradas de los jugadores en el modo demo para saltarse la demo. void Game::DEMO_handlePassInput() { - if (input_->checkAnyButtonPressed()) + if (input_->checkAnyButton()) { Section::name = Section::Name::TITLE; // Salir del modo demo y regresar al menú principal. Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO; // El juego volverá a mostrar la demo diff --git a/source/global_inputs.cpp b/source/global_inputs.cpp index 2af8ac3..9cecaf4 100644 --- a/source/global_inputs.cpp +++ b/source/global_inputs.cpp @@ -11,7 +11,7 @@ #include "param.h" // Para Param, ParamGame, param #include "screen.h" // Para Screen #include "section.h" // Para Name, name, Options, options, AttractMode -#include "ui/service_menu.h" // Para ServiceMenu +#include "ui/service_menu.h" // Para ServiceMenu #include "utils.h" // Para boolToOnOff namespace GlobalInputs @@ -192,13 +192,13 @@ namespace GlobalInputs } // Comprueba el boton de servicio - void checkServiceButton() + bool checkServiceButton() { // Teclado if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleServiceMenu(); - return; + return true; } // Mandos @@ -208,17 +208,18 @@ namespace GlobalInputs if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { toggleServiceMenu(); - return; + return true; } } } + return false; } // Comprueba las entradas del menú de servicio - void checkServiceInputs() + bool checkServiceInputs() { if (!ServiceMenu::get()->isEnabled()) - return; + return false; // Teclado { @@ -226,42 +227,42 @@ namespace GlobalInputs if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->setSelectorUp(); - return; + return true; } // Abajo if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->setSelectorDown(); - return; + return true; } // Derecha if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->adjustOption(true); - return; + return true; } // Izquierda if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->adjustOption(false); - return; + return true; } // Aceptar if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->selectOption(); - return; + return true; } // Atras if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { ServiceMenu::get()->moveBack(); - return; + return true; } } @@ -273,49 +274,50 @@ namespace GlobalInputs if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->setSelectorUp(); - return; + return true; } // Abajo if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->setSelectorDown(); - return; + return true; } // Derecha if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->adjustOption(true); - return; + return true; } // Izquierda if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->adjustOption(false); - return; + return true; } // Aceptar if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->selectOption(); - return; + return true; } // Atras if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) { ServiceMenu::get()->moveBack(); - return; + return true; } } } + return false; } // Comprueba las entradas fuera del menú de servicio - void checkInputs() + bool checkInputs() { // Teclado { @@ -325,7 +327,7 @@ namespace GlobalInputs Screen::get()->toggleFullscreen(); const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10"); Notifier::get()->show({MODE}); - return; + return true; } // Comprueba el teclado para decrementar el tamaño de la ventana @@ -335,7 +337,7 @@ namespace GlobalInputs { Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)}); } - return; + return true; } // Comprueba el teclado para incrementar el tamaño de la ventana @@ -345,70 +347,70 @@ namespace GlobalInputs { Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)}); } - return; + return true; } // Salir if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { quit(); - return; + return true; } // Saltar sección - if (Input::get()->checkAnyButtonPressed() && !ServiceMenu::get()->isEnabled()) + if (Input::get()->checkAnyButton() && !ServiceMenu::get()->isEnabled()) { skipSection(); - return; + return true; } // Reset if (Input::get()->checkInput(InputAction::RESET, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { reset(); - return; + return true; } // Audio if (Input::get()->checkInput(InputAction::TOGGLE_AUDIO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleAudio(); - return; + return true; } // Autofire if (Input::get()->checkInput(InputAction::TOGGLE_AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleFireMode(); - return; + return true; } // Idioma if (Input::get()->checkInput(InputAction::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { changeLang(); - return; + return true; } // Shaders if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleShaders(); - return; + return true; } // Integer Scale if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleIntegerScale(); - return; + return true; } // VSync if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_VSYNC, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { toggleVSync(); - return; + return true; } #ifdef DEBUG @@ -416,17 +418,23 @@ namespace GlobalInputs if (Input::get()->checkInput(InputAction::SHOW_INFO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { Screen::get()->toggleDebugInfo(); - return; + return true; } #endif } + return false; } // Comprueba los inputs que se pueden introducir en cualquier sección del juego - void check() + bool check() { - checkServiceButton(); - checkServiceInputs(); - checkInputs(); + Input::get()->update(); + if (checkServiceButton()) + return true; + if (checkServiceInputs()) + return true; + if (checkInputs()) + return true; + return false; } } \ No newline at end of file diff --git a/source/global_inputs.h b/source/global_inputs.h index e351769..1aabae1 100644 --- a/source/global_inputs.h +++ b/source/global_inputs.h @@ -3,5 +3,5 @@ namespace GlobalInputs { // Comprueba los inputs que se pueden introducir en cualquier sección del juego - void check(); + bool check(); } \ No newline at end of file diff --git a/source/input.cpp b/source/input.cpp index b8c1283..510067e 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -68,34 +68,13 @@ bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device, if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY) { - const bool *keyStates = SDL_GetKeyboardState(nullptr); - if (repeat) - { - success_keyboard = keyStates[key_bindings_[input_index].scancode] != 0; + { // El usuario quiere saber si está pulsada (estado mantenido) + return key_bindings_[input_index].is_held; } else - { - if (!key_bindings_[input_index].active) - { - if (keyStates[key_bindings_[input_index].scancode] != 0) - { - key_bindings_[input_index].active = true; - success_keyboard = true; - } - else - { - success_keyboard = false; - } - } - else - { - if (keyStates[key_bindings_[input_index].scancode] == 0) - { - key_bindings_[input_index].active = false; - } - success_keyboard = false; - } + { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma) + return key_bindings_[input_index].just_pressed; } } @@ -108,31 +87,12 @@ bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device, if (!success_controller) { if (repeat) - { - success_controller = SDL_GetGamepadButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) != 0; + { // El usuario quiere saber si está pulsada (estado mantenido) + return controller_bindings_.at(controller_index).at(input_index).is_held; } else - { - if (!controller_bindings_.at(controller_index).at(input_index).active) - { - if (SDL_GetGamepadButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) != 0) - { - controller_bindings_.at(controller_index).at(input_index).active = true; - success_controller = true; - } - else - { - success_controller = false; - } - } - else - { - if (SDL_GetGamepadButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) == 0) - { - controller_bindings_.at(controller_index).at(input_index).active = false; - } - success_controller = false; - } + { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma) + return controller_bindings_.at(controller_index).at(input_index).just_pressed; } } } @@ -144,47 +104,48 @@ bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device, // Comprueba si hay almenos un input activo bool Input::checkAnyInput(InputDeviceToUse device, int controller_index) { - if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY) - { - const bool *mKeystates = SDL_GetKeyboardState(nullptr); + // Obtenemos el número total de acciones posibles para iterar sobre ellas. + const int num_actions = static_cast(InputAction::SIZE); - for (int i = 0; i < (int)key_bindings_.size(); ++i) - { - if (mKeystates[key_bindings_[i].scancode] != 0 && !key_bindings_[i].active) - { - key_bindings_[i].active = true; - return true; - } - } - } + // --- Comprobación del Teclado --- + if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY) + { + for (int i = 0; i < num_actions; ++i) + { + // Simplemente leemos el estado pre-calculado por Input::update(). + // Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'. + if (key_bindings_.at(i).just_pressed) + { + return true; // Se encontró una acción recién pulsada. + } + } + } - if (gameControllerFound()) - { - if (device == InputDeviceToUse::CONTROLLER || device == InputDeviceToUse::ANY) - { - for (int i = 0; i < (int)controller_bindings_.size(); ++i) - { - if (SDL_GetGamepadButton(connected_controllers_[controller_index], controller_bindings_[controller_index][i].button) != 0 && !controller_bindings_[controller_index][i].active) - { - controller_bindings_[controller_index][i].active = true; - return true; - } - } - } - } + // --- Comprobación del Mando --- + // Comprobamos si hay mandos y si el índice solicitado es válido. + if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) + { + if (device == InputDeviceToUse::CONTROLLER || device == InputDeviceToUse::ANY) + { + // Bucle CORREGIDO: Iteramos sobre todas las acciones, no sobre el número de mandos. + for (int i = 0; i < num_actions; ++i) + { + // Leemos el estado pre-calculado para el mando y la acción específicos. + if (controller_bindings_.at(controller_index).at(i).just_pressed) + { + return true; // Se encontró una acción recién pulsada en el mando. + } + } + } + } - return false; + // Si llegamos hasta aquí, no se detectó ninguna nueva pulsación. + return false; } // Comprueba si hay algún botón pulsado. Devuelve 0 en caso de no encontrar nada o el indice del dispositivo + 1. Se hace así para poder gastar el valor devuelto como un valor "booleano" -int Input::checkAnyButtonPressed(bool repeat) +int Input::checkAnyButton(bool repeat) { - // Si está pulsado el botón de servicio, ningún botón se puede considerar pulsado - if (checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::ANY)) - { - return 0; - } - // Solo comprueba los botones definidos previamente for (auto bi : button_inputs_) { @@ -218,7 +179,7 @@ bool Input::discoverGameControllers() } // En SDL3, SDL_GetJoysticks devuelve un array de IDs, no un contador - SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&num_joysticks_); + SDL_JoystickID *joystick_ids = SDL_GetJoysticks(&num_joysticks_); num_gamepads_ = 0; // Cuenta el número de mandos @@ -228,7 +189,7 @@ bool Input::discoverGameControllers() // Usar el ID del joystick, no el índice auto joy = SDL_OpenJoystick(joystick_ids[i]); joysticks_.push_back(joy); - + // En SDL3, SDL_IsGamepad toma un SDL_JoystickID, no un índice if (SDL_IsGamepad(joystick_ids[i])) { @@ -261,11 +222,11 @@ bool Input::discoverGameControllers() if (pad != nullptr) { connected_controllers_.push_back(pad); - + // Obtener el nombre usando el ID del joystick - const char* name_cstr = SDL_GetGamepadNameForID(joystick_ids[i]); + const char *name_cstr = SDL_GetGamepadNameForID(joystick_ids[i]); std::string name = name_cstr ? name_cstr : "Unknown Gamepad"; - + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "#%d: %s", i, name.c_str()); controller_names_.push_back(name); } @@ -453,15 +414,49 @@ void Input::initSDLGamePad() } } -void Input::resetInputStates() { +void Input::resetInputStates() +{ // Resetear todos los KeyBindings.active a false - for (auto &key : key_bindings_) { - key.active = false; + for (auto &key : key_bindings_) + { + key.is_held = false; + key.just_pressed = false; } // Resetear todos los ControllerBindings.active a false - for (auto &controller_vec : controller_bindings_) { - for (auto &binding : controller_vec) { - binding.active = false; + for (auto &controller_vec : controller_bindings_) + { + for (auto &binding : controller_vec) + { + binding.is_held = false; + binding.just_pressed = false; + } + } +} + +void Input::update() +{ + // --- TECLADO --- + const bool *key_states = SDL_GetKeyboardState(nullptr); + + for (int i = 0; i < key_bindings_.size(); ++i) + { + bool key_is_down_now = key_states[key_bindings_[i].scancode]; + + // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo + key_bindings_[i].just_pressed = key_is_down_now && !key_bindings_[i].is_held; + key_bindings_[i].is_held = key_is_down_now; + } + + // --- MANDOS --- + for (int c = 0; c < num_gamepads_; ++c) + { + for (int i = 0; i < controller_bindings_[c].size(); ++i) + { + bool button_is_down_now = SDL_GetGamepadButton(connected_controllers_.at(c), controller_bindings_.at(c).at(i).button) != 0; + + // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo + controller_bindings_[c][i].just_pressed = button_is_down_now && !controller_bindings_[c][i].is_held; + controller_bindings_[c][i].is_held = button_is_down_now; } } } \ No newline at end of file diff --git a/source/input.h b/source/input.h index a3f1142..0bd40e5 100644 --- a/source/input.h +++ b/source/input.h @@ -85,9 +85,10 @@ public: void bindGameControllerButton(int controller_index, InputAction inputTarget, InputAction inputSource); // Asigna inputs a otros inputs del mando // --- Métodos de consulta de entrada --- + void update(); // Comprueba fisicamente los botones y teclas que se han pulsado bool checkInput(InputAction input, bool repeat = true, InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0); // Comprueba si un input está activo bool checkAnyInput(InputDeviceToUse device = InputDeviceToUse::ANY, int controller_index = 0); // Comprueba si hay al menos un input activo - int checkAnyButtonPressed(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT); // Comprueba si hay algún botón pulsado + int checkAnyButton(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT); // Comprueba si hay algún botón pulsado // --- Métodos de gestión de mandos --- bool discoverGameControllers(); // Busca si hay mandos conectados @@ -113,21 +114,23 @@ private: // --- Estructuras internas --- struct KeyBindings { - Uint8 scancode; // Scancode asociado - bool active; // Indica si está activo + Uint8 scancode; // Scancode asociado + bool is_held; // Está pulsada ahora mismo + bool just_pressed; // Se acaba de pulsar en este fotograma - KeyBindings(Uint8 sc = 0, bool act = false) - : scancode(sc), active(act) {} + KeyBindings(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false) + : scancode(scancode), is_held(is_held), just_pressed(just_pressed) {} }; struct ControllerBindings { SDL_GamepadButton button; // GameControllerButton asociado - bool active; // Indica si está activo + bool is_held; // Está pulsada ahora mismo + bool just_pressed; // Se acaba de pulsar en este fotograma bool axis_active; // Estado del eje - ControllerBindings(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool act = false, bool axis_act = false) - : button(btn), active(act), axis_active(axis_act) {} + ControllerBindings(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false) + : button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {} }; // --- Variables internas --- @@ -142,7 +145,7 @@ private: std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt // --- Métodos internos --- - void initSDLGamePad(); // Inicializa SDL para la gestión de mandos + void initSDLGamePad(); // Inicializa SDL para la gestión de mandos bool checkAxisInput(InputAction input, int controller_index, bool repeat); // Comprueba el eje del mando // --- Constructor y destructor ---