diff --git a/source/game/scene_manager.hpp b/source/game/scene_manager.hpp index c82b56a..a479a24 100644 --- a/source/game/scene_manager.hpp +++ b/source/game/scene_manager.hpp @@ -37,7 +37,7 @@ enum class Options { inline Scene current = Scene::LOGO; // Escena actual inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual #else -inline Scene current = Scene::TITLE; // Escena actual +inline Scene current = Scene::GAME_OVER; // Escena actual inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual #endif diff --git a/source/game/scenes/game_over.cpp b/source/game/scenes/game_over.cpp index bc7f88d..8549256 100644 --- a/source/game/scenes/game_over.cpp +++ b/source/game/scenes/game_over.cpp @@ -10,86 +10,85 @@ #include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/text.hpp" // Para TEXT_CENTER, TEXT_COLOR, Text #include "core/resources/resource.hpp" // Para Resource +#include "core/system/global_events.hpp" // Para check #include "external/jail_audio.h" // Para JA_PlayMusic #include "game/options.hpp" // Para Options, options, OptionsStats, Secti... #include "game/scene_manager.hpp" // Para SceneManager -#include "utils/defines.hpp" // Para GAMECANVAS_CENTER_X, GAME_SPEED -#include "core/system/global_events.hpp" // Para check +#include "utils/defines.hpp" // Para GAMECANVAS_CENTER_X +#include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/utils.hpp" // Para PaletteColor, stringToColor // Constructor GameOver::GameOver() : player_sprite_(std::make_shared(Resource::get()->getSurface("player_game_over.gif"), Resource::get()->getAnimations("player_game_over.ani"))), - tv_sprite_(std::make_shared(Resource::get()->getSurface("tv.gif"), Resource::get()->getAnimations("tv.ani"))) { + tv_sprite_(std::make_shared(Resource::get()->getSurface("tv.gif"), Resource::get()->getAnimations("tv.ani"))), + delta_timer_(std::make_shared()) { SceneManager::current = SceneManager::Scene::GAME_OVER; SceneManager::options = SceneManager::Options::NONE; - player_sprite_->setPosX(GAMECANVAS_CENTER_X + 10); - player_sprite_->setPosY(30); - tv_sprite_->setPosX(GAMECANVAS_CENTER_X - tv_sprite_->getWidth() - 10); - tv_sprite_->setPosY(30); + // Inicializa las posiciones de los sprites usando las constantes + player_sprite_->setPosX(GAMECANVAS_CENTER_X + PLAYER_X_OFFSET); + player_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET); + tv_sprite_->setPosX(GAMECANVAS_CENTER_X - tv_sprite_->getWidth() - TV_X_OFFSET); + tv_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET); Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); - // Inicializa el vector de colores + // Inicializa el vector de colores (de brillante a oscuro para fade) const std::vector COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; for (const auto& color : COLORS) { colors_.push_back(stringToColor(color)); } - color_ = colors_.back(); + color_ = colors_.back(); // Empieza en black } // Actualiza el objeto void GameOver::update() { - // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego - if (SDL_GetTicks() - ticks_ > GAME_SPEED) { - // Actualiza el contador de ticks - ticks_ = SDL_GetTicks(); + // Obtiene el delta time desde el último frame + const float delta = delta_timer_->tick(); + elapsed_time_ += delta; - // Comprueba las entradas - checkInput(); + // Comprueba las entradas + checkInput(); - // Actualiza el color usado para renderizar los textos e imagenes - updateColor(); + // Actualiza el estado de la escena + updateState(); - // Actualiza los contadores - updateCounters(); + // Actualiza el color usado para renderizar los textos e imagenes + updateColor(); - // Actualiza los dos sprites - player_sprite_->update(); - tv_sprite_->update(); + // Actualiza los dos sprites (con delta time escalado por velocidad) + player_sprite_->update(); + tv_sprite_->update(); - // Actualiza el objeto Screen - Screen::get()->update(); - } + // Actualiza el objeto Screen + Screen::get()->update(); } // Dibuja el final en pantalla void GameOver::render() { - constexpr int Y = 32; - Screen::get()->start(); Screen::get()->clearSurface(static_cast(PaletteColor::BLACK)); auto text = Resource::get()->getText("smb2"); // Escribe el texto de GAME OVER - text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y, "G A M E O V E R", 1, color_); + text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, TEXT_Y, "G A M E O V E R", 1, color_); - // Dibuja los sprites - player_sprite_->setPosY(Y + 30); - tv_sprite_->setPosY(Y + 30); + // Dibuja los sprites (ya posicionados en el constructor, solo ajustamos Y) + player_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET); + tv_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET); renderSprites(); // Escribe el texto con las habitaciones y los items const std::string ITEMS_TEXT = std::to_string(Options::stats.items / 100) + std::to_string((Options::stats.items % 100) / 10) + std::to_string(Options::stats.items % 10); const std::string ROOMS_TEXT = std::to_string(Options::stats.rooms / 100) + std::to_string((Options::stats.rooms % 100) / 10) + std::to_string(Options::stats.rooms % 10); - text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 80, "ITEMS: " + ITEMS_TEXT, 1, color_); - text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 90, "ROOMS: " + ROOMS_TEXT, 1, color_); + text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, TEXT_Y + ITEMS_Y_OFFSET, "ITEMS: " + ITEMS_TEXT, 1, color_); + text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, TEXT_Y + ROOMS_Y_OFFSET, "ROOMS: " + ROOMS_TEXT, 1, color_); // Escribe el texto con "Tu peor pesadilla" - text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 110, "YOUR WORST NIGHTMARE IS", 1, color_); - text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 120, Options::stats.worst_nightmare, 1, color_); + text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, TEXT_Y + NIGHTMARE_TITLE_Y_OFFSET, "YOUR WORST NIGHTMARE IS", 1, color_); + text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, TEXT_Y + NIGHTMARE_TEXT_Y_OFFSET, Options::stats.worst_nightmare, 1, color_); // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); @@ -119,16 +118,41 @@ void GameOver::run() { // Actualiza el color usado para renderizar los textos e imagenes void GameOver::updateColor() { - const int HALF = COUNTER_SECTION_END / 2; + // Calcula el color basado en el estado actual + switch (state_) { + case State::WAITING: + // Durante la espera, mantener en black + color_ = colors_.back(); // black + break; - if (counter_ < HALF) { - const float STEP = std::min(counter_, COUNTER_FADE_LENGHT) / (float)COUNTER_FADE_LENGHT; - const int INDEX = (colors_.size() - 1) - int((colors_.size() - 1) * STEP); - color_ = colors_[INDEX]; - } else { - const float STEP = std::min(std::max(counter_, COUNTER_INIT_FADE) - COUNTER_INIT_FADE, COUNTER_FADE_LENGHT) / (float)COUNTER_FADE_LENGHT; - const int INDEX = (colors_.size() - 1) * STEP; - color_ = colors_[INDEX]; + case State::FADE_IN: { + // Fade in: de black (último color) a white (primer color) + // Progreso: 0.0 (black) -> 1.0 (white) + const float progress = std::min(elapsed_time_ / FADE_IN_DURATION, 1.0f); + const int index = (colors_.size() - 1) - static_cast((colors_.size() - 1) * progress); + color_ = colors_[std::clamp(index, 0, static_cast(colors_.size() - 1))]; + break; + } + + case State::DISPLAY: + // Durante display, mantener el color más brillante + color_ = colors_[0]; // white + break; + + case State::FADE_OUT: { + // Fade out: de white (primer color) a black (último color) + // Progreso: 0.0 (white) -> 1.0 (black) + const float progress = std::min(elapsed_time_ / FADE_OUT_DURATION, 1.0f); + const int index = static_cast((colors_.size() - 1) * progress); + color_ = colors_[std::clamp(index, 0, static_cast(colors_.size() - 1))]; + break; + } + + case State::ENDING: + case State::TRANSITION: + // Al final, mantener en black + color_ = colors_.back(); // black + break; } } @@ -138,23 +162,56 @@ void GameOver::renderSprites() { tv_sprite_->render(1, color_); } -// Actualiza los contadores -void GameOver::updateCounters() { - // Actualiza el contador - if (pre_counter_ < 50) { - pre_counter_++; - } else { - counter_++; - } +// Actualiza el estado de la escena y gestiona transiciones +void GameOver::updateState() { + // Máquina de estados basada en tiempo transcurrido + switch (state_) { + case State::WAITING: + // Espera inicial antes de empezar + if (elapsed_time_ >= WAITING_DURATION) { + state_ = State::FADE_IN; + elapsed_time_ = 0.0f; + // Hace sonar la música cuando termina la espera + JA_PlayMusic(Resource::get()->getMusic("game_over.ogg"), 0); + } + break; - // Hace sonar la música - if (counter_ == 1) { - JA_PlayMusic(Resource::get()->getMusic("game_over.ogg"), 0); - } + case State::FADE_IN: + // Fade in de colores desde black + if (elapsed_time_ >= FADE_IN_DURATION) { + state_ = State::DISPLAY; + elapsed_time_ = 0.0f; + } + break; - // Comprueba si ha terminado la sección - else if (counter_ == COUNTER_SECTION_END) { - SceneManager::current = SceneManager::Scene::LOGO; - SceneManager::options = SceneManager::Options::LOGO_TO_TITLE; + case State::DISPLAY: + // Mostrando contenido con color brillante + if (elapsed_time_ >= DISPLAY_DURATION) { + state_ = State::FADE_OUT; + elapsed_time_ = 0.0f; + } + break; + + case State::FADE_OUT: + // Fade out hacia black + if (elapsed_time_ >= FADE_OUT_DURATION) { + state_ = State::ENDING; + elapsed_time_ = 0.0f; + } + break; + + case State::ENDING: + // Pantalla en negro antes de salir + if (elapsed_time_ >= ENDING_DURATION) { + state_ = State::TRANSITION; + elapsed_time_ = 0.0f; + } + break; + + case State::TRANSITION: + // Transición a la escena de logo + SceneManager::current = SceneManager::Scene::LOGO; + SceneManager::options = SceneManager::Options::LOGO_TO_TITLE; + break; } } \ No newline at end of file diff --git a/source/game/scenes/game_over.hpp b/source/game/scenes/game_over.hpp index 3b78937..8eabccf 100644 --- a/source/game/scenes/game_over.hpp +++ b/source/game/scenes/game_over.hpp @@ -5,53 +5,62 @@ #include // Para shared_ptr #include // Para vector class SurfaceAnimatedSprite; // lines 7-7 +class DeltaTimer; // Forward declaration class GameOver { - private: - // Constantes - static constexpr int COUNTER_SECTION_END = 400; // Contador: cuando acaba la sección - static constexpr int COUNTER_INIT_FADE = 310; // Contador: cuando emiepza el fade - static constexpr int COUNTER_FADE_LENGHT = 20; // Contador: duración del fade - - // Objetos y punteros - std::shared_ptr player_sprite_; // Sprite con el jugador - std::shared_ptr tv_sprite_; // Sprite con el televisor - - // Variables - int pre_counter_ = 0; // Contador previo - int counter_ = 0; // Contador - Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa - std::vector colors_; // Vector con los colores para el fade - Uint8 color_; // Color usado para el texto y los sprites - - // Actualiza el objeto - void update(); - - // Dibuja el final en pantalla - void render(); - - // Comprueba el manejador de eventos - static void checkEvents(); - - // Comprueba las entradas - static void checkInput(); - - // Actualiza el color usado para renderizar los textos e imagenes - void updateColor(); - - // Dibuja los sprites - void renderSprites(); - - // Actualiza los contadores - void updateCounters(); - public: - // Constructor + // Constructor y Destructor GameOver(); - - // Destructor ~GameOver() = default; // Bucle principal void run(); + + private: + // --- Estados --- + enum class State { + WAITING, // Espera inicial antes de empezar + FADE_IN, // Fade in de colores desde black + DISPLAY, // Mostrando contenido con color brillante + FADE_OUT, // Fade out hacia black + ENDING, // Pantalla en negro antes de salir + TRANSITION // Cambio a logo + }; + + // --- Constantes de Duración (segundos) --- + static constexpr float WAITING_DURATION = 0.8f; // Espera inicial + static constexpr float FADE_IN_DURATION = 0.32f; // Duración del fade in + static constexpr float DISPLAY_DURATION = 4.64f; // Duración mostrando contenido + static constexpr float FADE_OUT_DURATION = 0.32f; // Duración del fade out + static constexpr float ENDING_DURATION = 1.12f; // Espera en negro antes de salir + + // --- Constantes de Posición --- + static constexpr int TEXT_Y = 32; // Posición Y del texto principal + static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y + static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro + static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro + static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y + static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y + static constexpr int NIGHTMARE_TITLE_Y_OFFSET = 110; // Offset Y del título nightmare desde TEXT_Y + static constexpr int NIGHTMARE_TEXT_Y_OFFSET = 120; // Offset Y del texto nightmare desde TEXT_Y + + // --- Objetos y punteros --- + std::shared_ptr player_sprite_; // Sprite con el jugador + std::shared_ptr tv_sprite_; // Sprite con el televisor + std::shared_ptr delta_timer_; // Timer para time-based logic + + // --- Variables --- + State state_ = State::WAITING; // Estado actual de la escena + float elapsed_time_ = 0.0f; // Tiempo transcurrido en el estado actual + std::vector colors_; // Vector con los colores para el fade + Uint8 color_; // Color usado para el texto y los sprites + + // --- Funciones --- + void update(); // Actualiza el objeto + void render(); // Dibuja el final en pantalla + static void checkEvents(); // Comprueba el manejador de eventos + static void checkInput(); // Comprueba las entradas + void updateState(); // Actualiza el estado y transiciones + void updateColor(); // Actualiza el color usado para renderizar los textos e imagenes + void renderSprites(); // Dibuja los sprites }; \ No newline at end of file