From e67aeb10feb6b6aa603f643b449505ee3d1bc80c Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 13 Apr 2026 17:57:13 +0200 Subject: [PATCH] fix: controls en el mando --- source/core/input/global_inputs.cpp | 5 +++-- source/core/input/input.cpp | 17 +++++++++++++---- source/core/input/input.hpp | 7 ++++++- source/core/system/director.cpp | 1 + source/core/system/global_events.cpp | 11 ++++++++++- source/game/scenes/title.cpp | 10 ++++++++-- source/game/ui/notifier.hpp | 6 +++--- 7 files changed, 44 insertions(+), 13 deletions(-) diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index 7c284d6..885c8a3 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -154,8 +154,9 @@ namespace GlobalInputs { // Detecta qué acción global ha sido presionada (si alguna) auto getPressedAction() -> InputAction { // NOLINT(readability-function-cognitive-complexity) // Qualsevol botó del comandament actua com a ACCEPT (saltar escenes - // d'attract mode: logo, loading, credits, demo, ending...). Es prioritza - // sobre EXIT perquè s'envia com a flag d'event, no com a check d'acció. + // d'attract mode: logo, loading, credits, demo, ending...). El botó + // BACK queda filtrat prèviament a GlobalEvents per no colidir amb EXIT + // (excepte en emscripten, on BACK no pot sortir i sí pot saltar). if (GlobalEvents::consumeGamepadButtonPressed()) { return InputAction::ACCEPT; } diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index adb3475..1f2a006 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -390,12 +390,21 @@ void Input::update() { // NOLINT(readability-convert-member-functions-to-static // --- MANDOS --- for (const auto& gamepad : gamepads_) { - for (auto& binding : gamepad->bindings) { - bool button_is_down_now = static_cast(SDL_GetGamepadButton(gamepad->pad, static_cast(binding.second.button))) != 0; + for (auto& [action, state] : gamepad->bindings) { + bool is_down_now = static_cast(SDL_GetGamepadButton(gamepad->pad, static_cast(state.button))) != 0; + + // JUMP accepta qualsevol dels 4 botons frontals (South/East/North/West) + if (action == Action::JUMP) { + is_down_now = is_down_now || + (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_SOUTH) != 0) || + (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_EAST) != 0) || + (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_NORTH) != 0) || + (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_WEST) != 0); + } // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo - binding.second.just_pressed = button_is_down_now && !binding.second.is_held; - binding.second.is_held = button_is_down_now; + state.just_pressed = is_down_now && !state.is_held; + state.is_held = is_down_now; } } } diff --git a/source/core/input/input.hpp b/source/core/input/input.hpp index 698137d..ade3261 100644 --- a/source/core/input/input.hpp +++ b/source/core/input/input.hpp @@ -60,7 +60,12 @@ class Input { // Movimiento del jugador {Action::LEFT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}}, {Action::RIGHT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}}, - {Action::JUMP, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_WEST)}}} {} + {Action::JUMP, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_WEST)}}, + // Botó BACK del mando → sortir escena / tancar joc + {Action::EXIT, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_BACK)}}, + {Action::CANCEL, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_BACK)}}, + // Botó START del mando → pausa + {Action::PAUSE, ButtonState{.button = static_cast(SDL_GAMEPAD_BUTTON_START)}}} {} ~Gamepad() { if (pad != nullptr) { diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 2c12eb4..dd66a48 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -151,6 +151,7 @@ Director::Director() { // perquè la textura 256x192 no es vegi minúscula al canvas HTML, // i desactivem el borde per aprofitar al màxim l'espai del canvas. Options::video.fullscreen = false; + Options::video.integer_scale = false; Options::window.zoom = 4; Options::video.border.enabled = true; Options::video.border.height = 8; diff --git a/source/core/system/global_events.cpp b/source/core/system/global_events.cpp index e4e3c2d..fea4c18 100644 --- a/source/core/system/global_events.cpp +++ b/source/core/system/global_events.cpp @@ -39,9 +39,18 @@ namespace GlobalEvents { } } - // Marcar polsació de qualsevol botó del comandament (els consumirà GlobalInputs). + // Marcar polsació de qualsevol botó del comandament (els consumirà GlobalInputs + // per saltar escenes d'attract mode). El botó BACK queda exclòs perquè es + // reserva per a l'acció EXIT — excepte a emscripten, on no es pot sortir del + // joc i el BACK pot actuar com a botó genèric per saltar escenes. if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { +#ifdef __EMSCRIPTEN__ gamepad_button_pressed_ = true; +#else + if (event.gbutton.button != SDL_GAMEPAD_BUTTON_BACK) { + gamepad_button_pressed_ = true; + } +#endif } // Enrutar eventos de texto a la consola cuando está activa diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 3baf982..bdfc002 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -93,10 +93,16 @@ void Title::handleEvent(const SDL_Event& event) { } // Qualsevol botó del comandament al menú principal inicia partida directament - // (els bindings ja estan definits, no cal "pulsar 1" amb el teclat). + // (els bindings ja estan definits, no cal "pulsar 1" amb el teclat). El botó + // BACK queda exclòs perquè es reserva per a EXIT — excepte a emscripten, on + // no es pot sortir del joc i BACK pot actuar com a botó genèric d'inici. if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN && state_ == State::MAIN_MENU && - !is_remapping_keyboard_ && !is_remapping_joystick_) { + !is_remapping_keyboard_ && !is_remapping_joystick_ +#ifndef __EMSCRIPTEN__ + && event.gbutton.button != SDL_GAMEPAD_BUTTON_BACK +#endif + ) { handleMainMenuKeyPress(SDLK_1); // PLAY return; } diff --git a/source/game/ui/notifier.hpp b/source/game/ui/notifier.hpp index 2b2b26b..b22d671 100644 --- a/source/game/ui/notifier.hpp +++ b/source/game/ui/notifier.hpp @@ -79,7 +79,7 @@ class Notifier { Status state{Status::RISING}; Shape shape{Shape::SQUARED}; SDL_FRect rect{.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; // rect.y es relativo a la base de la pila - int y{0}; // Top objetivo de la notificación relativo a la base de la pila + int y{0}; // Top objetivo de la notificación relativo a la base de la pila int travel_dist{0}; std::string code; bool can_be_removed{true}; @@ -97,8 +97,8 @@ class Notifier { static Notifier* notifier; // Métodos privados - void clearFinishedNotifications(); // Elimina las notificaciones finalizadas - void clearNotifications(); // Finaliza y elimina todas las notificaciones activas + void clearFinishedNotifications(); // Elimina las notificaciones finalizadas + void clearNotifications(); // Finaliza y elimina todas las notificaciones activas [[nodiscard]] auto getStackBaseY() const -> int; // Y absoluta de la base de la pila (leída de Console) // Constructor y destructor privados [SINGLETON]