From af7420d7c705bc9dacb273805c4f03803989f6fe Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 2 Nov 2025 14:04:33 +0100 Subject: [PATCH] Title: afegit fade i post_fade --- source/game/scene_manager.hpp | 2 +- source/game/scenes/title.cpp | 264 ++++++++++++++++++++++------------ source/game/scenes/title.hpp | 51 ++++--- 3 files changed, 204 insertions(+), 113 deletions(-) diff --git a/source/game/scene_manager.hpp b/source/game/scene_manager.hpp index 7cf180d9..e718ee95 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::LOADING_SCREEN; // 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 691b4311..dc8d8252 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -21,19 +21,20 @@ // Constructor Title::Title() - : title_logo_surface_(Resource::get()->getSurface("title_logo.gif")), - title_logo_sprite_(std::make_shared(title_logo_surface_, 29, 9, title_logo_surface_->getWidth(), title_logo_surface_->getHeight())), + : game_logo_surface_(Resource::get()->getSurface("title_logo.gif")), + game_logo_sprite_(std::make_unique(game_logo_surface_, 29, 9, game_logo_surface_->getWidth(), game_logo_surface_->getHeight())), loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")), - loading_screen_sprite_(std::make_shared(loading_screen_surface_, 0, 0, loading_screen_surface_->getWidth(), loading_screen_surface_->getHeight())), - bg_surface_(std::make_shared(Options::game.width, Options::game.height)), + loading_screen_sprite_(std::make_unique(loading_screen_surface_, 0, 0, loading_screen_surface_->getWidth(), loading_screen_surface_->getHeight())), + title_surface_(std::make_shared(Options::game.width, Options::game.height)), delta_timer_(std::make_unique()), marquee_text_(Resource::get()->getText("gauntlet")), + menu_text_(Resource::get()->getText("gauntlet")), first_active_letter_(0), last_active_letter_(0), state_time_(0.0F), fade_accumulator_(0.0F) { // Inicializa variables - state_ = SceneManager::options == SceneManager::Options::TITLE_WITH_LOADING_SCREEN ? State::SHOW_LOADING_SCREEN : State::SHOW_MENU; + state_ = SceneManager::options == SceneManager::Options::TITLE_WITH_LOADING_SCREEN ? State::SHOW_LOADING_SCREEN : State::MAIN_MENU; SceneManager::current = SceneManager::Scene::TITLE; SceneManager::options = SceneManager::Options::NONE; initMarquee(); @@ -44,9 +45,6 @@ Title::Title() // Cambia el color del borde Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); - // Rellena la textura de fondo con todos los gráficos - fillSurface(); - // Inicia la musica playMusic("title.ogg"); } @@ -77,22 +75,29 @@ void Title::handleEvents() { while (SDL_PollEvent(&event)) { GlobalEvents::handle(event); - // Solo se comprueban estas teclas si no está activo el menu de logros if (event.type == SDL_EVENT_KEY_DOWN) { - if (!show_cheevos_) { - switch (event.key.key) { - case SDLK_1: - SceneManager::current = SceneManager::Scene::GAME; - SceneManager::options = SceneManager::Options::NONE; - break; + switch (state_) { + case State::MAIN_MENU: + switch (event.key.key) { + case SDLK_1: + transitionToState(State::FADE_MENU); + break; - case SDLK_2: - show_cheevos_ = true; - break; + case SDLK_2: + transitionToState(State::CONTROLS_MENU); + break; - default: - break; - } + case SDLK_3: + transitionToState(State::CHEEVOS_MENU); + break; + + default: + break; + } + break; + + default: + break; } } } @@ -102,20 +107,36 @@ void Title::handleEvents() { void Title::handleInput(float delta_time) { Input::get()->update(); - if (show_cheevos_) { - if (Input::get()->checkAction(InputAction::RIGHT, Input::ALLOW_REPEAT)) { - moveCheevosList(1, delta_time); - } else if (Input::get()->checkAction(InputAction::LEFT, Input::ALLOW_REPEAT)) { - moveCheevosList(0, delta_time); - } else if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) { - hideCheevosList(); - } - } + switch (state_) { + case State::SHOW_LOADING_SCREEN: + if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) { + transitionToState(State::FADE_LOADING_SCREEN); + } + break; - if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) { - if (state_ == State::SHOW_LOADING_SCREEN) { - transitionToState(State::FADE_LOADING_SCREEN); - } + case State::CHEEVOS_MENU: + if (Input::get()->checkAction(InputAction::RIGHT, Input::ALLOW_REPEAT)) { + moveCheevosList(1, delta_time); + } else if (Input::get()->checkAction(InputAction::LEFT, Input::ALLOW_REPEAT)) { + moveCheevosList(0, delta_time); + } + + if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT) || + Input::get()->checkAction(InputAction::CANCEL, Input::DO_NOT_ALLOW_REPEAT)) { + resetCheevosScroll(); + transitionToState(State::MAIN_MENU); + } + 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); + } + break; + + default: + break; } GlobalInputs::handle(); @@ -163,7 +184,7 @@ void Title::renderMarquee() { static_cast(letter.x), // Conversión explícita float→int static_cast(MARQUEE_Y), // Usar constante std::string(1, letter.letter), // Convertir char a string - static_cast(PaletteColor::BRIGHT_RED)); + static_cast(PaletteColor::MAGENTA)); } } } @@ -183,10 +204,9 @@ void Title::update() { // Actualiza el estado actual void Title::updateState(float delta_time) { - state_time_ += delta_time; - switch (state_) { case State::SHOW_LOADING_SCREEN: + state_time_ += delta_time; if (state_time_ >= SHOW_LOADING_DURATION) { transitionToState(State::FADE_LOADING_SCREEN); } @@ -197,22 +217,57 @@ void Title::updateState(float delta_time) { if (fade_accumulator_ >= FADE_STEP_INTERVAL) { fade_accumulator_ = 0.0F; if (loading_screen_surface_->fadeSubPalette()) { - transitionToState(State::SHOW_MENU); + transitionToState(State::MAIN_MENU); } } break; - case State::SHOW_MENU: + case State::MAIN_MENU: // Actualiza la marquesina updateMarquee(delta_time); + // Incrementa el temporizador solo en el menú principal + state_time_ += delta_time; + // Si el tiempo alcanza el timeout, va a créditos - if (state_time_ >= AUTO_CREDITS_TIMEOUT && !show_cheevos_) { + if (state_time_ >= AUTO_CREDITS_TIMEOUT) { SceneManager::current = SceneManager::Scene::CREDITS; SceneManager::options = SceneManager::Options::NONE; } break; + case State::CHEEVOS_MENU: + // Actualiza la marquesina (sigue visible en fondo) + updateMarquee(delta_time); + // No incrementar state_time_ (no timeout en este estado) + break; + + case State::CONTROLS_MENU: + // Actualiza la marquesina (sigue visible en fondo) + updateMarquee(delta_time); + // No incrementar state_time_ (no timeout en este estado) + break; + + case State::FADE_MENU: + fade_accumulator_ += delta_time; + if (fade_accumulator_ >= FADE_STEP_INTERVAL) { + fade_accumulator_ = 0.0F; + if (title_surface_->fadeSubPalette()) { + transitionToState(State::POST_FADE_MENU); + } + } + // Actualiza la marquesina (sigue visible en fondo) + updateMarquee(delta_time); + break; + + case State::POST_FADE_MENU: + state_time_ += delta_time; + if (state_time_ >= POST_FADE_DELAY) { + SceneManager::current = SceneManager::Scene::GAME; + SceneManager::options = SceneManager::Options::NONE; + } + break; + default: break; } @@ -227,33 +282,15 @@ void Title::transitionToState(State new_state) { // Dibuja en pantalla void Title::render() { + // Rellena la surface + fillTitleSurface(); + // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); Screen::get()->clearSurface(static_cast(PaletteColor::BLACK)); - switch (state_) { - case State::SHOW_MENU: - // Dibuja la textura de fondo - bg_surface_->render(0, 0); - - // Dibuja la marquesina - renderMarquee(); - - // Dibuja la información de logros - if (show_cheevos_) { - cheevos_sprite_->render(); - } - break; - - case State::SHOW_LOADING_SCREEN: - case State::FADE_LOADING_SCREEN: - loading_screen_sprite_->render(); - title_logo_sprite_->render(); - break; - - default: - break; - } + // Dibuja en pantalla la surface con la composicion + title_surface_->render(); // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); @@ -284,30 +321,6 @@ void Title::moveCheevosList(int direction, float delta_time) { cheevos_sprite_->setClip(cheevos_surface_view_); } -// Rellena la textura de fondo con todos los gráficos -void Title::fillSurface() { - // Coloca el puntero del renderizador sobre la textura - auto previuos_renderer = Screen::get()->getRendererSurface(); - Screen::get()->setRendererSurface(bg_surface_); - - // Rellena la textura de color - bg_surface_->clear(static_cast(PaletteColor::BLACK)); - - // Pinta el gráfico del titulo a partir del sprite - title_logo_sprite_->render(); - - // Escribe el texto en la textura - auto text = Resource::get()->getText("smb2"); - const Uint8 COLOR = stringToColor("green"); - const int TEXT_SIZE = text->getCharacterSize(); - text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1.PLAY", 1, COLOR); - text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2.ACHIEVEMENTS", 1, COLOR); - text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3.REDEFINE KEYS", 1, COLOR); - - // Devuelve el puntero del renderizador a su sitio - Screen::get()->setRendererSurface(previuos_renderer); -} - // Crea y rellena la textura para mostrar los logros void Title::createCheevosTexture() { // Crea la textura con el listado de logros @@ -355,14 +368,83 @@ void Title::createCheevosTexture() { Screen::get()->setRendererSurface(previuos_renderer); // Crea el sprite para el listado de logros - cheevos_sprite_ = std::make_shared(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight()); + cheevos_sprite_ = std::make_unique(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight()); cheevos_surface_view_ = {.x = 0, .y = 0, .w = cheevos_surface_->getWidth(), .h = CHEEVOS_TEXTURE_VIEW_HEIGHT}; cheevos_sprite_->setClip(cheevos_surface_view_); } -// Oculta la lista de logros -void Title::hideCheevosList() { - show_cheevos_ = false; +// Resetea el scroll de la lista de logros +void Title::resetCheevosScroll() { cheevos_surface_view_.y = 0; cheevos_sprite_->setClip(cheevos_surface_view_); +} + +// Dibuja el logo con el titulo del juego +void Title::renderGameLogo() { + game_logo_sprite_->render(); +} + +// Dibuja el menu principal +void Title::renderMainMenu() { + 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. ACHIEVEMENTS", 1, COLOR); +} + +// Dibuja el menu de logros +void Title::renderCheevosMenu() { + cheevos_sprite_->render(); +} + +// 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); +} + +// Dibuja los elementos en la surface +void Title::fillTitleSurface() { + // Renderiza sobre la textura + auto previuos_renderer = Screen::get()->getRendererSurface(); + Screen::get()->setRendererSurface(title_surface_); + + // Rellena la textura de color + title_surface_->clear(static_cast(PaletteColor::BLACK)); + + switch (state_) { + case State::MAIN_MENU: + case State::FADE_MENU: + renderGameLogo(); + renderMainMenu(); + renderMarquee(); + break; + + case State::CHEEVOS_MENU: + renderGameLogo(); + renderCheevosMenu(); + renderMarquee(); + break; + + case State::CONTROLS_MENU: + renderGameLogo(); + renderControlsMenu(); + renderMarquee(); + break; + + case State::SHOW_LOADING_SCREEN: + case State::FADE_LOADING_SCREEN: + loading_screen_sprite_->render(); + renderGameLogo(); + break; + + default: + break; + } + + // Deja el renderizador como estaba + Screen::get()->setRendererSurface(previuos_renderer); } \ No newline at end of file diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index 36db524b..9eb90276 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -32,13 +32,18 @@ class Title { enum class State { SHOW_LOADING_SCREEN, FADE_LOADING_SCREEN, - SHOW_MENU + MAIN_MENU, + CHEEVOS_MENU, + CONTROLS_MENU, + FADE_MENU, + POST_FADE_MENU, }; // --- 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.033F; // Intervalo entre pasos de fade (antes cada 4 frames) - static constexpr float AUTO_CREDITS_TIMEOUT = 22.0F; // Timeout para ir a créditos (antes 2200 frames) + static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade (antes cada 4 frames) + static constexpr float POST_FADE_DELAY = 1.0F; // Delay después del fade (pantalla en negro) + static constexpr float AUTO_CREDITS_TIMEOUT = 20.0F; // Timeout para ir a créditos (antes 2200 frames) static constexpr float MARQUEE_SPEED = 100.0F; // Velocidad de marquesina (pixels/segundo) static constexpr float CHEEVOS_SCROLL_SPEED = 120.0F; // Velocidad de scroll de logros (pixels/segundo) @@ -49,26 +54,26 @@ class Title { static constexpr float MARQUEE_LETTER_SPACING = 1.0F; // Espaciado entre letras // --- Objetos y punteros --- - std::shared_ptr title_logo_surface_; // Textura con los graficos - std::shared_ptr title_logo_sprite_; // SSprite para manejar la surface + std::shared_ptr game_logo_surface_; // Textura con los graficos + std::unique_ptr game_logo_sprite_; // SSprite para manejar la surface std::shared_ptr loading_screen_surface_; // Surface con los gráficos de la pantalla de carga - std::shared_ptr loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga - std::shared_ptr bg_surface_; // Textura para dibujar el fondo de la pantalla + std::unique_ptr loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga std::shared_ptr cheevos_surface_; // Textura con la lista de logros - std::shared_ptr cheevos_sprite_; // SSprite para manejar la surface con la lista de logros + std::unique_ptr cheevos_sprite_; // SSprite para manejar la surface con la lista de logros + std::shared_ptr title_surface_; // Surface donde se dibuja toda la clase + std::unique_ptr delta_timer_; // Timer para delta time + std::shared_ptr marquee_text_; // Texto para marquesina + std::shared_ptr menu_text_; // Texto para los menus // --- Variables de estado --- - std::unique_ptr delta_timer_; // Timer para delta time - std::shared_ptr marquee_text_; // Cache del texto para marquesina - std::string long_text_; // Texto que aparece en la parte inferior del titulo - std::vector letters_; // Vector con las letras de la marquesina - int first_active_letter_; // Primera letra activa (optimización) - int last_active_letter_; // Última letra activa (optimización) - bool show_cheevos_ = false; // Indica si se muestra por pantalla el listado de logros - SDL_FRect cheevos_surface_view_; // Zona visible de la surface con el listado de logros - State state_; // Estado en el que se encuentra el bucle principal - float state_time_; // Tiempo acumulado en el estado actual - float fade_accumulator_; // Acumulador para controlar el fade por tiempo + std::string long_text_; // Texto que aparece en la parte inferior del titulo + std::vector letters_; // Vector con las letras de la marquesina + int first_active_letter_; // Primera letra activa (optimización) + int last_active_letter_; // Última letra activa (optimización) + SDL_FRect cheevos_surface_view_; // Zona visible de la surface con el listado de logros + State state_; // Estado en el que se encuentra el bucle principal + float state_time_; // Tiempo acumulado en el estado actual + float fade_accumulator_; // Acumulador para controlar el fade por tiempo // --- Funciones --- void update(); // Actualiza las variables @@ -80,8 +85,12 @@ class Title { void initMarquee(); // Inicializa la marquesina void updateMarquee(float delta_time); // Actualiza la marquesina (time-based) void renderMarquee(); // Dibuja la marquesina + 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 moveCheevosList(int direction, float delta_time); // Desplaza la lista de logros (time-based) - void fillSurface(); // Rellena la surface de fondo con todos los gráficos void createCheevosTexture(); // Crea y rellena la surface para mostrar los logros - void hideCheevosList(); // Oculta la lista de logros + void resetCheevosScroll(); // Resetea el scroll de la lista de logros + void fillTitleSurface(); // Dibuja los elementos en la surface }; \ No newline at end of file