diff --git a/source/game/scene_manager.hpp b/source/game/scene_manager.hpp index 9ee627a..e718ee9 100644 --- a/source/game/scene_manager.hpp +++ b/source/game/scene_manager.hpp @@ -34,7 +34,7 @@ enum class Options { // --- Variables de estado globales --- #ifdef _DEBUG -inline Scene current = Scene::GAME; // Escena actual +inline Scene current = Scene::TITLE; // Escena actual inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual #else inline Scene current = Scene::LOGO; // Escena actual diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 8e8df34..0a90152 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -35,9 +35,11 @@ Title::Title() state_time_(0.0F), fade_accumulator_(0.0F), exit_scene_(SceneManager::Scene::GAME), - controls_menu_state_(ControlsMenuState::MAIN), + is_remapping_keyboard_(false), + is_remapping_joystick_(false), remap_step_(0), - axis_cooldown_(0.0F) { + axis_cooldown_(0.0F), + remap_completed_(false) { // Inicializa variables state_ = SceneManager::options == SceneManager::Options::TITLE_WITH_LOADING_SCREEN ? State::SHOW_LOADING_SCREEN : State::MAIN_MENU; SceneManager::current = SceneManager::Scene::TITLE; @@ -81,29 +83,20 @@ void Title::handleEvents() { GlobalEvents::handle(event); // Manejo especial para captura de botones de gamepad - if (state_ == State::CONTROLS_MENU && - controls_menu_state_ == ControlsMenuState::JOYSTICK_REMAP && + if (is_remapping_joystick_ && !remap_completed_ && (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN || event.type == SDL_EVENT_GAMEPAD_AXIS_MOTION)) { - handleControlsMenuJoystickRemap(event); + handleJoystickRemap(event); continue; // No procesar más este evento } if (event.type == SDL_EVENT_KEY_DOWN) { - switch (state_) { - case State::MAIN_MENU: - handleMainMenuKeyPress(event.key.key); - break; - - case State::CONTROLS_MENU: - if (controls_menu_state_ == ControlsMenuState::MAIN) { - handleControlsMenuKeyPress(event.key.key); - } else if (controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP) { - handleControlsMenuKeyboardRemap(event); - } - break; - - default: - break; + // Si estamos en modo remap de teclado, capturar tecla + if (is_remapping_keyboard_ && !remap_completed_) { + handleKeyboardRemap(event); + } + // Si estamos en el menú principal normal + else if (state_ == State::MAIN_MENU && !is_remapping_keyboard_ && !is_remapping_joystick_) { + handleMainMenuKeyPress(event.key.key); } } } @@ -113,43 +106,39 @@ void Title::handleEvents() { void Title::handleMainMenuKeyPress(SDL_Keycode key) { switch (key) { case SDLK_1: + // PLAY exit_scene_ = SceneManager::Scene::GAME; transitionToState(State::FADE_MENU); Audio::get()->fadeOutMusic(1000); break; case SDLK_2: - transitionToState(State::CONTROLS_MENU); - controls_menu_state_ = ControlsMenuState::MAIN; + // REDEFINE KEYBOARD + is_remapping_keyboard_ = true; + is_remapping_joystick_ = false; + remap_step_ = 0; + remap_completed_ = false; + remap_error_message_.clear(); + state_time_ = 0.0F; break; case SDLK_3: - transitionToState(State::CHEEVOS_MENU); - break; - - default: - break; - } -} - -// Maneja las teclas del menu de controles -void Title::handleControlsMenuKeyPress(SDL_Keycode key) { - switch (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 - solo si hay gamepads conectados + // REDEFINE JOYSTICK (siempre visible, pero solo funciona si hay gamepad) if (Input::get()->gameControllerFound()) { - controls_menu_state_ = ControlsMenuState::JOYSTICK_REMAP; + is_remapping_keyboard_ = false; + is_remapping_joystick_ = true; remap_step_ = 0; + remap_completed_ = false; remap_error_message_.clear(); - axis_cooldown_ = 0.0F; // Resetear cooldown + axis_cooldown_ = 0.0F; + state_time_ = 0.0F; } + // Si no hay gamepad, simplemente no hacer nada + break; + + case SDLK_4: + // PROJECTS + transitionToState(State::CHEEVOS_MENU); break; default: @@ -161,6 +150,20 @@ void Title::handleControlsMenuKeyPress(SDL_Keycode key) { void Title::handleInput(float delta_time) { Input::get()->update(); + // Permitir cancelar remap con ESC/CANCEL + if ((is_remapping_keyboard_ || is_remapping_joystick_) && !remap_completed_) { + if (Input::get()->checkAction(InputAction::CANCEL, Input::DO_NOT_ALLOW_REPEAT)) { + is_remapping_keyboard_ = false; + is_remapping_joystick_ = false; + remap_step_ = 0; + remap_completed_ = false; + remap_error_message_.clear(); + } + // Durante el remap, no procesar otras entradas + GlobalInputs::handle(); + return; + } + switch (state_) { case State::SHOW_LOADING_SCREEN: if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) { @@ -182,16 +185,6 @@ void Title::handleInput(float delta_time) { } break; - case State::CONTROLS_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; - default: break; } @@ -278,10 +271,6 @@ void Title::updateState(float delta_time) { updateCheevosMenu(delta_time); break; - case State::CONTROLS_MENU: - updateControlsMenu(delta_time); - break; - case State::FADE_MENU: updateFadeMenu(delta_time); break; @@ -326,13 +315,39 @@ void Title::updateMainMenu(float delta_time) { // Actualiza la marquesina updateMarquee(delta_time); - // Incrementa el temporizador solo en el menú principal - state_time_ += delta_time; + // Si estamos en modo remap, manejar la lógica específica + if (is_remapping_keyboard_ || is_remapping_joystick_) { + // Decrementar cooldown de ejes si estamos capturando botones de joystick + if (is_remapping_joystick_ && axis_cooldown_ > 0.0F) { + axis_cooldown_ -= delta_time; + axis_cooldown_ = std::max(axis_cooldown_, 0.0F); + } - // Si el tiempo alcanza el timeout, va a créditos con fade - if (state_time_ >= MAIN_MENU_IDLE_TIMEOUT) { - exit_scene_ = SceneManager::Scene::CREDITS; - transitionToState(State::FADE_MENU); + // Si el remap está completado, esperar antes de guardar + if (remap_completed_) { + state_time_ += delta_time; + if (state_time_ >= KEYBOARD_REMAP_DISPLAY_DELAY) { + if (is_remapping_keyboard_) { + applyKeyboardRemap(); + } else if (is_remapping_joystick_) { + applyJoystickRemap(); + } + // Resetear estado de remap + is_remapping_keyboard_ = false; + is_remapping_joystick_ = false; + remap_completed_ = false; + state_time_ = 0.0F; + } + } + } else { + // Incrementa el temporizador solo en el menú principal normal + state_time_ += delta_time; + + // Si el tiempo alcanza el timeout, va a créditos con fade + if (state_time_ >= MAIN_MENU_IDLE_TIMEOUT) { + exit_scene_ = SceneManager::Scene::CREDITS; + transitionToState(State::FADE_MENU); + } } } @@ -343,39 +358,6 @@ void Title::updateCheevosMenu(float delta_time) { // No incrementar state_time_ (no timeout en este estado) } -// Actualiza el estado CONTROLS_MENU -void Title::updateControlsMenu(float delta_time) { - // Actualiza la marquesina (sigue visible en fondo) - updateMarquee(delta_time); - - // Decrementar cooldown de ejes si estamos capturando botones - if (controls_menu_state_ == ControlsMenuState::JOYSTICK_REMAP && axis_cooldown_ > 0.0F) { - axis_cooldown_ -= delta_time; - axis_cooldown_ = std::max(axis_cooldown_, 0.0F); - } - - // Si estamos mostrando las teclas definidas, esperar antes de guardar - if (controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP_COMPLETE) { - state_time_ += delta_time; - if (state_time_ >= KEYBOARD_REMAP_DISPLAY_DELAY) { - // Aplicar y guardar las teclas - applyKeyboardRemap(); - // Volver al menu principal - transitionToState(State::MAIN_MENU); - } - } - // Si estamos mostrando los botones definidos, esperar antes de guardar - else if (controls_menu_state_ == ControlsMenuState::JOYSTICK_REMAP_COMPLETE) { - state_time_ += delta_time; - if (state_time_ >= KEYBOARD_REMAP_DISPLAY_DELAY) { - // Aplicar y guardar los botones - applyJoystickRemap(); - // Volver al menu principal - transitionToState(State::MAIN_MENU); - } - } -} - // Actualiza el estado FADE_MENU void Title::updateFadeMenu(float delta_time) { fade_accumulator_ += delta_time; @@ -504,11 +486,23 @@ void Title::renderGameLogo() { // Dibuja el menu principal void Title::renderMainMenu() { + // Si estamos en modo remap, mostrar la pantalla correspondiente + if (is_remapping_keyboard_) { + renderKeyboardRemap(); + return; + } + if (is_remapping_joystick_) { + renderJoystickRemap(); + return; + } + + // Menú principal normal con 4 opciones 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. PLAY", 1, COLOR); - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2. CONTROLS", 1, COLOR); - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3. PROJECTS", 1, COLOR); + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2. REDEFINE KEYBOARD", 1, COLOR); + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3. REDEFINE JOYSTICK", 1, COLOR); + menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 17 * TEXT_SIZE, "4. PROJECTS", 1, COLOR); } // Dibuja el menu de logros @@ -516,30 +510,6 @@ void Title::renderCheevosMenu() { cheevos_sprite_->render(); } -// Dibuja el menu de controles -void Title::renderControlsMenu() { - // Delegar al render apropiado segun el subestado - if (controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP || - controls_menu_state_ == ControlsMenuState::KEYBOARD_REMAP_COMPLETE) { - renderKeyboardRemap(); - } else if (controls_menu_state_ == ControlsMenuState::JOYSTICK_REMAP || - controls_menu_state_ == ControlsMenuState::JOYSTICK_REMAP_COMPLETE) { - renderJoystickRemap(); - } else { - // Menu principal de controles - const Uint8 COLOR = stringToColor("green"); - const Uint8 DISABLED_COLOR = stringToColor("dark grey"); - 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); - - // Deshabilitar opcion de joystick si no hay gamepads conectados - const bool GAMEPAD_AVAILABLE = Input::get()->gameControllerFound(); - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2. REDEFINE JOYSTICK", 1, GAMEPAD_AVAILABLE ? COLOR : DISABLED_COLOR); - - menu_text_->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 17 * TEXT_SIZE, "ENTER TO GO BACK", 1, COLOR); - } -} - // Dibuja los elementos en la surface void Title::fillTitleSurface() { // Renderiza sobre la textura @@ -563,12 +533,6 @@ void Title::fillTitleSurface() { renderMarquee(); break; - case State::CONTROLS_MENU: - renderGameLogo(); - renderControlsMenu(); - renderMarquee(); - break; - case State::SHOW_LOADING_SCREEN: case State::FADE_LOADING_SCREEN: loading_screen_sprite_->render(); @@ -584,7 +548,7 @@ void Title::fillTitleSurface() { } // Maneja la captura de teclas para redefinir el teclado -void Title::handleControlsMenuKeyboardRemap(const SDL_Event& event) { +void Title::handleKeyboardRemap(const SDL_Event& event) { SDL_Scancode scancode = event.key.scancode; // Valida la tecla @@ -606,7 +570,7 @@ void Title::handleControlsMenuKeyboardRemap(const SDL_Event& event) { // Si completamos los 3 pasos, mostrar resultado y esperar if (remap_step_ >= 3) { - controls_menu_state_ = ControlsMenuState::KEYBOARD_REMAP_COMPLETE; + remap_completed_ = true; state_time_ = 0.0F; // Resetear el timer para el delay de 1 segundo } } @@ -749,7 +713,7 @@ void Title::renderJoystickRemap() { } // Maneja la captura de botones del gamepad para redefinir -void Title::handleControlsMenuJoystickRemap(const SDL_Event& event) { +void Title::handleJoystickRemap(const SDL_Event& event) { int captured_button = -1; // Capturar botones del gamepad @@ -804,7 +768,7 @@ void Title::handleControlsMenuJoystickRemap(const SDL_Event& event) { // Si completamos los 3 pasos, mostrar resultado y esperar if (remap_step_ >= 3) { - controls_menu_state_ = ControlsMenuState::JOYSTICK_REMAP_COMPLETE; + remap_completed_ = true; state_time_ = 0.0F; // Resetear el timer para el delay } } diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index 7db18cf..b02638c 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -35,19 +35,10 @@ class Title { FADE_LOADING_SCREEN, MAIN_MENU, CHEEVOS_MENU, - CONTROLS_MENU, FADE_MENU, POST_FADE_MENU, }; - enum class ControlsMenuState { - MAIN, // Mostrar menu principal de controles - KEYBOARD_REMAP, // Redefinir teclas del teclado - KEYBOARD_REMAP_COMPLETE, // Mostrar teclas definidas antes de guardar - JOYSTICK_REMAP, // Redefinir botones del joystick - JOYSTICK_REMAP_COMPLETE, // Mostrar botones definidos antes de guardar - }; - // --- 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) @@ -87,19 +78,20 @@ class Title { 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 + bool is_remapping_keyboard_; // True si estamos redefiniendo teclado + bool is_remapping_joystick_; // True si estamos redefiniendo joystick int remap_step_; // Paso actual en la redefinicion (0=LEFT, 1=RIGHT, 2=JUMP) SDL_Scancode temp_keys_[3]; // Almacenamiento temporal de teclas capturadas int temp_buttons_[3]; // Almacenamiento temporal de botones de gamepad capturados std::string remap_error_message_; // Mensaje de error si la tecla/boton es invalido float axis_cooldown_; // Cooldown para evitar múltiples capturas de ejes + bool remap_completed_; // True cuando se completa el remap (mostrar antes de guardar) // --- Funciones --- void update(); // Actualiza las variables void render(); // Dibuja en pantalla void handleEvents(); // Comprueba el manejador de eventos void handleMainMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu principal - void handleControlsMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu de controles void handleInput(float delta_time); // Comprueba las entradas void updateState(float delta_time); // Actualiza el estado actual void transitionToState(State new_state); // Transiciona a un nuevo estado @@ -107,7 +99,6 @@ class Title { void updateFadeLoadingScreen(float delta_time); // Actualiza FADE_LOADING_SCREEN void updateMainMenu(float delta_time); // Actualiza MAIN_MENU void updateCheevosMenu(float delta_time); // Actualiza CHEEVOS_MENU - void updateControlsMenu(float delta_time); // Actualiza CONTROLS_MENU void updateFadeMenu(float delta_time); // Actualiza FADE_MENU void updatePostFadeMenu(float delta_time); // Actualiza POST_FADE_MENU void initMarquee(); // Inicializa la marquesina @@ -116,12 +107,11 @@ class Title { void renderGameLogo(); // Dibuja el logo con el titulo del juego 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 renderJoystickRemap(); // Dibuja la pantalla de redefinir joystick 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 - void handleControlsMenuJoystickRemap(const SDL_Event& event); // Maneja la captura de botones del gamepad + void handleKeyboardRemap(const SDL_Event& event); // Maneja la captura de teclas + void handleJoystickRemap(const SDL_Event& event); // Maneja la captura de botones del gamepad static auto isKeyValid(SDL_Scancode scancode) -> bool; // Valida si una tecla es permitida auto isKeyDuplicate(SDL_Scancode scancode, int current_step) -> bool; // Valida si una tecla esta duplicada auto isButtonDuplicate(int button, int current_step) -> bool; // Valida si un boton esta duplicado