#include "game/scenes/game_over.hpp" #include #include // Para min, max #include // Para basic_string, operator+, to_string #include "core/audio/audio.hpp" // Para Audio #include "core/input/global_inputs.hpp" // Para check #include "core/input/input.hpp" // Para Input #include "core/rendering/screen.hpp" // Para Screen #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 "game/options.hpp" // Para Options, options, OptionsStats, Secti... #include "game/scene_manager.hpp" // Para SceneManager #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()->getAnimations("player_game_over.ani"))), tv_sprite_(std::make_shared(Resource::get()->getAnimations("tv.ani"))), delta_timer_(std::make_shared()) { SceneManager::current = SceneManager::Scene::GAME_OVER; SceneManager::options = SceneManager::Options::NONE; // 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 (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(); // Empieza en black } // Actualiza el objeto void GameOver::update() { const float DELTA_TIME = delta_timer_->tick(); elapsed_time_ += DELTA_TIME; handleEvents(); // Comprueba los eventos handleInput(); // Comprueba las entradas updateState(); // Actualiza el estado de la escena updateColor(); // Actualiza el color usado para renderizar los textos e imagenes player_sprite_->update(DELTA_TIME); // Actualiza el sprite tv_sprite_->update(DELTA_TIME); // Actualiza el sprite Audio::get()->update(); // Actualiza el objeto Audio Screen::get()->update(DELTA_TIME); // Actualiza el objeto Screen } // Dibuja el final en pantalla void GameOver::render() { 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, TEXT_Y, "G A M E O V E R", 1, color_); // 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, 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, 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(); } // Comprueba el manejador de eventos void GameOver::handleEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { GlobalEvents::handle(event); } } // Comprueba las entradas void GameOver::handleInput() { Input::get()->update(); GlobalInputs::handle(); } // Bucle principal void GameOver::run() { while (SceneManager::current == SceneManager::Scene::GAME_OVER) { update(); render(); } } // Actualiza el color usado para renderizar los textos e imagenes void GameOver::updateColor() { // Calcula el color basado en el estado actual switch (state_) { case State::WAITING: // Durante la espera, mantener en black color_ = colors_.back(); // black break; 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; } } // Dibuja los sprites void GameOver::renderSprites() { player_sprite_->render(1, color_); tv_sprite_->render(1, color_); } // 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 Audio::get()->playMusic("game_over.ogg", 0); } break; case State::FADE_IN: // Fade in de colores desde black if (elapsed_time_ >= FADE_IN_DURATION) { state_ = State::DISPLAY; elapsed_time_ = 0.0f; } break; 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; } }