From 13513384d12ee33e68d0388e3a70bc1639f232ce Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 2 Nov 2025 17:31:44 +0100 Subject: [PATCH] treballant en redefine keys --- source/game/scenes/title.cpp | 182 +++++++++++++++++++++++++++++++++-- source/game/scenes/title.hpp | 18 ++++ 2 files changed, 192 insertions(+), 8 deletions(-) diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 384bacb3..8a6108dd 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -11,6 +11,7 @@ #include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/rendering/text.hpp" // Para Text, TEXT_CENTER, TEXT_COLOR +#include "core/resources/asset.hpp" // Para Asset #include "core/resources/resource.hpp" // Para Resource #include "core/system/global_events.hpp" // Para check #include "game/gameplay/cheevos.hpp" // Para Cheevos, Achievement @@ -33,7 +34,9 @@ Title::Title() last_active_letter_(0), state_time_(0.0F), fade_accumulator_(0.0F), - exit_scene_(SceneManager::Scene::GAME) { + exit_scene_(SceneManager::Scene::GAME), + controls_menu_state_(ControlsMenuState::MAIN), + remap_step_(0) { // Inicializa variables state_ = SceneManager::options == SceneManager::Options::TITLE_WITH_LOADING_SCREEN ? State::SHOW_LOADING_SCREEN : State::MAIN_MENU; SceneManager::current = SceneManager::Scene::TITLE; @@ -88,6 +91,7 @@ void Title::handleEvents() { case SDLK_2: transitionToState(State::CONTROLS_MENU); + controls_menu_state_ = ControlsMenuState::MAIN; break; case SDLK_3: @@ -99,6 +103,31 @@ void Title::handleEvents() { } break; + case State::CONTROLS_MENU: + if (controls_menu_state_ == ControlsMenuState::MAIN) { + // Menu principal de controles + switch (event.key.key) { + case SDLK_1: + // Iniciar redefinicion de teclado + controls_menu_state_ = ControlsMenuState::KEYBOARD_REMAP; + remap_step_ = 0; + remap_error_message_.clear(); + break; + + case SDLK_2: + // Redefinir joystick (futuro) + // controls_menu_state_ = ControlsMenuState::JOYSTICK_REMAP; + break; + + default: + break; + } + } else if (controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP) { + // Captura de teclas para redefinir + handleControlsMenuKeyboardRemap(event); + } + break; + default: break; } @@ -132,9 +161,12 @@ void Title::handleInput(float delta_time) { break; case State::CONTROLS_MENU: - if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT) || - Input::get()->checkAction(InputAction::CANCEL, Input::DO_NOT_ALLOW_REPEAT)) { - transitionToState(State::MAIN_MENU); + // Solo permitir salir si estamos en el menu principal de controles + if (controls_menu_state_ == ControlsMenuState::MAIN) { + if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT) || + Input::get()->checkAction(InputAction::CANCEL, Input::DO_NOT_ALLOW_REPEAT)) { + transitionToState(State::MAIN_MENU); + } } break; @@ -438,10 +470,16 @@ void Title::renderCheevosMenu() { // Dibuja el menu de controles void Title::renderControlsMenu() { - const Uint8 COLOR = stringToColor("green"); - const int TEXT_SIZE = menu_text_->getCharacterSize(); - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1. REDEFINE KEYBOARD", 1, COLOR); - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2. REDEFINE JOYSTICK", 1, COLOR); + // Delegar al render apropiado segun el subestado + if (controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP) { + renderKeyboardRemap(); + } else { + // Menu principal de controles + const Uint8 COLOR = stringToColor("green"); + const int TEXT_SIZE = menu_text_->getCharacterSize(); + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1. REDEFINE KEYBOARD", 1, COLOR); + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2. REDEFINE JOYSTICK", 1, COLOR); + } } // Dibuja los elementos en la surface @@ -485,4 +523,132 @@ void Title::fillTitleSurface() { // Deja el renderizador como estaba Screen::get()->setRendererSurface(previuos_renderer); +} + +// Maneja la captura de teclas para redefinir el teclado +void Title::handleControlsMenuKeyboardRemap(const SDL_Event& event) { + SDL_Scancode scancode = event.key.scancode; + + // Si presiona ESC, cancela y vuelve al menu principal de controles + if (scancode == SDL_SCANCODE_ESCAPE) { + controls_menu_state_ = ControlsMenuState::MAIN; + remap_error_message_.clear(); + return; + } + + // Valida la tecla + if (!isKeyValid(scancode)) { + remap_error_message_ = "INVALID KEY! TRY ANOTHER"; + return; + } + + // Verifica duplicados + if (isKeyDuplicate(scancode, remap_step_)) { + remap_error_message_ = "KEY ALREADY USED! TRY ANOTHER"; + return; + } + + // Tecla valida, guardar + temp_keys_[remap_step_] = scancode; + remap_error_message_.clear(); + remap_step_++; + + // Si completamos los 3 pasos, aplicar y guardar + if (remap_step_ >= 3) { + applyKeyboardRemap(); + controls_menu_state_ = ControlsMenuState::MAIN; + } +} + +// Valida si una tecla es permitida +bool Title::isKeyValid(SDL_Scancode scancode) { + // Prohibir ESC (reservado para cancelar) + if (scancode == SDL_SCANCODE_ESCAPE) { + return false; + } + + // Prohibir teclas F1-F12 (reservadas para funciones del sistema) + if (scancode >= SDL_SCANCODE_F1 && scancode <= SDL_SCANCODE_F12) { + return false; + } + + // Prohibir Enter/Return (reservado para confirmaciones) + if (scancode == SDL_SCANCODE_RETURN || scancode == SDL_SCANCODE_RETURN2) { + return false; + } + + return true; +} + +// Verifica si una tecla ya fue usada en pasos anteriores +bool Title::isKeyDuplicate(SDL_Scancode scancode, int current_step) { + for (int i = 0; i < current_step; i++) { + if (temp_keys_[i] == scancode) { + return true; + } + } + return false; +} + +// Retorna el nombre de la accion para el paso actual +std::string Title::getActionName(int step) { + switch (step) { + case 0: + return "LEFT"; + case 1: + return "RIGHT"; + case 2: + return "JUMP"; + default: + return "UNKNOWN"; + } +} + +// Aplica y guarda las teclas redefinidas +void Title::applyKeyboardRemap() { + // Guardar las nuevas teclas en Options::controls + Options::controls.key_left = temp_keys_[0]; + Options::controls.key_right = temp_keys_[1]; + Options::controls.key_jump = temp_keys_[2]; + + // Aplicar los bindings al sistema de Input + Input::get()->applyKeyboardBindingsFromOptions(); + + // Guardar a archivo de configuracion + Options::saveToFile(Asset::get()->get("config.txt")); +} + +// Dibuja la pantalla de redefinir teclado +void Title::renderKeyboardRemap() { + const Uint8 COLOR = stringToColor("green"); + const Uint8 ERROR_COLOR = stringToColor("red"); + const int TEXT_SIZE = menu_text_->getCharacterSize(); + + // Titulo + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 9 * TEXT_SIZE, "REDEFINE KEYBOARD", 1, COLOR); + + // Mensaje principal: "PRESS KEY FOR [ACTION]" + const std::string ACTION = getActionName(remap_step_); + const std::string MESSAGE = "PRESS KEY FOR " + ACTION; + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 12 * TEXT_SIZE, MESSAGE, 1, COLOR); + + // Mostrar teclas ya capturadas + if (remap_step_ > 0) { + const std::string LEFT_KEY = SDL_GetScancodeName(temp_keys_[0]); + const std::string LEFT_MSG = "LEFT: " + LEFT_KEY; + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 14 * TEXT_SIZE, LEFT_MSG, 1, COLOR); + } + if (remap_step_ > 1) { + const std::string RIGHT_KEY = SDL_GetScancodeName(temp_keys_[1]); + const std::string RIGHT_MSG = "RIGHT: " + RIGHT_KEY; + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, RIGHT_MSG, 1, COLOR); + } + + // Mensaje de error si existe + if (!remap_error_message_.empty()) { + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 17 * TEXT_SIZE, remap_error_message_, 1, ERROR_COLOR); + } + + // Instrucciones para cancelar + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 19 * TEXT_SIZE, "(ESC TO CANCEL)", 1, COLOR); } \ No newline at end of file diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index 672424d2..44b4c3fd 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -40,6 +40,12 @@ class Title { POST_FADE_MENU, }; + enum class ControlsMenuState { + MAIN, // Mostrar menu principal de controles + KEYBOARD_REMAP, // Redefinir teclas del teclado + JOYSTICK_REMAP, // Redefinir botones del joystick (futuro) + }; + // --- Constantes de tiempo (en segundos) --- static constexpr float SHOW_LOADING_DURATION = 5.0F; // Tiempo mostrando loading screen (antes 500 frames) static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade (antes cada 4 frames) @@ -77,6 +83,12 @@ class Title { float fade_accumulator_; // Acumulador para controlar el fade por tiempo SceneManager::Scene exit_scene_; // Escena de destino al salir del título + // --- Variables para redefinir controles --- + ControlsMenuState controls_menu_state_; // Subestado del menu de controles + int remap_step_; // Paso actual en la redefinicion (0=LEFT, 1=RIGHT, 2=JUMP) + SDL_Scancode temp_keys_[3]; // Almacenamiento temporal de teclas capturadas + std::string remap_error_message_; // Mensaje de error si la tecla es invalida + // --- Funciones --- void update(); // Actualiza las variables void render(); // Dibuja en pantalla @@ -98,7 +110,13 @@ class Title { void renderMainMenu(); // Dibuja el menu principal void renderCheevosMenu(); // Dibuja el menu de logros void renderControlsMenu(); // Dibuja el menu de controles + void renderKeyboardRemap(); // Dibuja la pantalla de redefinir teclado void moveCheevosList(int direction, float delta_time); // Desplaza la lista de logros (time-based) + void handleControlsMenuKeyboardRemap(const SDL_Event& event); // Maneja la captura de teclas + bool isKeyValid(SDL_Scancode scancode); // Valida si una tecla es permitida + bool isKeyDuplicate(SDL_Scancode scancode, int current_step); // Valida si una tecla esta duplicada + void applyKeyboardRemap(); // Aplica y guarda las teclas redefinidas + std::string getActionName(int step); // Retorna el nombre de la accion (LEFT/RIGHT/JUMP) void createCheevosTexture(); // Crea y rellena la surface para mostrar los logros void resetCheevosScroll(); // Resetea el scroll de la lista de logros void fillTitleSurface(); // Dibuja los elementos en la surface