#include "game/scenes/logo.hpp" #include #include // Para std::clamp #include // Para std::array #include // Para generador aleatorio #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.hpp" // Para Surface #include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/resources/resource_cache.hpp" // Para Resource #include "core/system/global_events.hpp" // Para check #include "game/options.hpp" // Para Options, SectionState, options, Section #include "game/scene_manager.hpp" // Para SceneManager #include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/easing_functions.hpp" // Para funciones de suavizado #include "utils/utils.hpp" // Para PaletteColor // Constructor Logo::Logo() : jailgames_surface_(Resource::Cache::get()->getSurface("jailgames.gif")), since_1998_surface_(Resource::Cache::get()->getSurface("since_1998.gif")), since_1998_sprite_(std::make_shared(since_1998_surface_, (256 - since_1998_surface_->getWidth()) / 2, 83 + jailgames_surface_->getHeight() + 5, since_1998_surface_->getWidth(), since_1998_surface_->getHeight())), delta_timer_(std::make_unique()) { // Configura variables since_1998_sprite_->setClip(0, 0, since_1998_surface_->getWidth(), since_1998_surface_->getHeight()); since_1998_color_ = static_cast(PaletteColor::BLACK); jailgames_color_ = static_cast(PaletteColor::BRIGHT_WHITE); // Inicializa variables SceneManager::current = SceneManager::Scene::LOGO; initSprites(); // Crea los sprites de cada linea initColors(); // Inicializa el vector de colores // Seleccionar función de easing aleatoria para la animación del logo // Usamos lambdas para funciones con parámetros opcionales static const std::array EASING_OPTIONS = { [](float t) { return Easing::backOut(t); }, // Overshoot retro [](float t) { return Easing::elasticOut(t); }, // Rebote múltiple con oscilación Easing::bounceOut, // Rebote físico decreciente Easing::cubicOut // Suavizado sin overshoot (para variedad) }; std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution dist(0, EASING_OPTIONS.size() - 1); easing_function_ = EASING_OPTIONS[dist(gen)]; // Cambia el color del borde Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); } // Comprueba el manejador de eventos void Logo::handleEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { GlobalEvents::handle(event); } } // Comprueba las entradas void Logo::handleInput() { Input::get()->update(); GlobalInputs::handle(); } // Gestiona el logo de JAILGAME void Logo::updateJAILGAMES(float delta_time) { // Solo actualizar durante el estado JAILGAMES_SLIDE_IN if (state_ != State::JAILGAMES_SLIDE_IN) { return; } // Calcular el progreso de la animación (0.0 a 1.0) const float progress = std::clamp(state_time_ / JAILGAMES_SLIDE_DURATION, 0.0F, 1.0F); // Aplicar función de suavizado seleccionada aleatoriamente (permite overshoot para efecto de rebote) // La posición final exacta se garantiza en updateState() antes de transicionar const float eased_progress = easing_function_(progress); // Actualizar cada línea del sprite JAILGAMES interpolando con easing for (size_t i = 0; i < jailgames_sprite_.size(); ++i) { // Interpolar entre posición inicial y destino usando el progreso suavizado const float initial_x = static_cast(jailgames_initial_x_[i]); const float dest_x = static_cast(JAILGAMES_DEST_X); const float new_x = initial_x + (dest_x - initial_x) * eased_progress; jailgames_sprite_[i]->setX(new_x); } } // Calcula el índice de color según el progreso (0.0-1.0) auto Logo::getColorIndex(float progress) const -> int { // Asegurar que progress esté en el rango [0.0, 1.0] progress = std::clamp(progress, 0.0F, 1.0F); // Mapear el progreso al índice de color (0-7) const int MAX_INDEX = static_cast(color_.size()) - 1; const int INDEX = static_cast(progress * MAX_INDEX); return INDEX; } // Gestiona el color de las texturas void Logo::updateTextureColors() { switch (state_) { case State::SINCE_1998_FADE_IN: { // Fade-in de "Since 1998" de negro a blanco const float PROGRESS = state_time_ / SINCE_1998_FADE_DURATION; since_1998_color_ = color_[getColorIndex(PROGRESS)]; break; } case State::DISPLAY: { // Asegurar que ambos logos estén en blanco durante el display jailgames_color_ = color_.back(); // BRIGHT_WHITE since_1998_color_ = color_.back(); // BRIGHT_WHITE break; } case State::FADE_OUT: { // Fade-out de ambos logos de blanco a negro const float PROGRESS = 1.0F - (state_time_ / FADE_OUT_DURATION); const int COLOR_INDEX = getColorIndex(PROGRESS); jailgames_color_ = color_[COLOR_INDEX]; since_1998_color_ = color_[COLOR_INDEX]; break; } default: // En otros estados, mantener los colores actuales break; } } // Transiciona a un nuevo estado void Logo::transitionToState(State new_state) { state_ = new_state; state_time_ = 0.0F; } // Actualiza el estado actual void Logo::updateState(float delta_time) { state_time_ += delta_time; // Gestionar transiciones entre estados basándose en el tiempo switch (state_) { case State::INITIAL: if (state_time_ >= INITIAL_DELAY) { transitionToState(State::JAILGAMES_SLIDE_IN); } break; case State::JAILGAMES_SLIDE_IN: if (state_time_ >= JAILGAMES_SLIDE_DURATION) { // Garantizar que todas las líneas estén exactamente en la posición final // antes de transicionar (previene race condition con updateJAILGAMES) for (auto& sprite : jailgames_sprite_) { sprite->setX(JAILGAMES_DEST_X); } transitionToState(State::SINCE_1998_FADE_IN); } break; case State::SINCE_1998_FADE_IN: if (state_time_ >= SINCE_1998_FADE_DURATION) { transitionToState(State::DISPLAY); } break; case State::DISPLAY: if (state_time_ >= DISPLAY_DURATION) { transitionToState(State::FADE_OUT); } break; case State::FADE_OUT: if (state_time_ >= FADE_OUT_DURATION) { transitionToState(State::END); endSection(); } break; case State::END: // Estado final, no hacer nada break; } } // Actualiza las variables void Logo::update() { const float DELTA_TIME = delta_timer_->tick(); handleEvents(); // Comprueba los eventos handleInput(); // Comprueba las entradas updateState(DELTA_TIME); // Actualiza el estado y gestiona transiciones updateJAILGAMES(DELTA_TIME); // Gestiona el logo de JAILGAME updateTextureColors(); // Gestiona el color de las texturas Audio::update(); // Actualiza el objeto Audio Screen::get()->update(DELTA_TIME); // Actualiza el objeto Screen } // Dibuja en pantalla void Logo::render() { // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); Screen::get()->clearSurface(static_cast(PaletteColor::BLACK)); // Dibuja los objetos for (const auto& sprite : jailgames_sprite_) { sprite->render(1, jailgames_color_); } since_1998_sprite_->render(1, since_1998_color_); // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); } // Bucle para el logo del juego void Logo::run() { while (SceneManager::current == SceneManager::Scene::LOGO) { update(); render(); } } // Termina la sección void Logo::endSection() { switch (SceneManager::options) { case SceneManager::Options::LOGO_TO_TITLE: SceneManager::current = SceneManager::Scene::TITLE; break; case SceneManager::Options::LOGO_TO_LOADING_SCREEN: SceneManager::current = SceneManager::Scene::LOADING_SCREEN; break; default: // Ninguna acción por defecto break; } } // Inicializa el vector de colores void Logo::initColors() { // Inicializa el vector de colores const std::vector COLORS = { static_cast(PaletteColor::BLACK), static_cast(PaletteColor::BLUE), static_cast(PaletteColor::RED), static_cast(PaletteColor::MAGENTA), static_cast(PaletteColor::GREEN), static_cast(PaletteColor::CYAN), static_cast(PaletteColor::YELLOW), static_cast(PaletteColor::BRIGHT_WHITE)}; for (const auto& color : COLORS) { color_.push_back(color); } } // Crea los sprites de cada linea void Logo::initSprites() { const float WIDTH = jailgames_surface_->getWidth(); jailgames_initial_x_.reserve(jailgames_surface_->getHeight()); for (int i = 0; i < jailgames_surface_->getHeight(); ++i) { jailgames_sprite_.push_back(std::make_shared(jailgames_surface_, 0, i, jailgames_surface_->getWidth(), 1)); jailgames_sprite_.back()->setClip(0, i, jailgames_surface_->getWidth(), 1); // Calcular posición inicial (alternando entre derecha e izquierda) constexpr int LINE_OFFSET = 6; const int initial_x = (i % 2 == 0) ? (256 + (i * LINE_OFFSET)) : (static_cast(-WIDTH) - (i * LINE_OFFSET)); jailgames_initial_x_.push_back(initial_x); jailgames_sprite_.at(i)->setX(initial_x); jailgames_sprite_.at(i)->setY(83 + i); } }