Files
pollo/source/game/scenes/logo.cpp
2025-11-23 12:26:42 +01:00

296 lines
11 KiB
C++

#include "game/scenes/logo.hpp"
#include <SDL3/SDL.h>
#include <algorithm> // Para std::clamp
#include <array> // Para std::array
#include <random> // 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/color.hpp" // Para Color
#include "utils/defines.hpp" // Para GameCanvas
#include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/easing_functions.hpp" // Para funciones de suavizado
// Constructor
Logo::Logo()
: jailgames_surface_(Resource::Cache::get()->getSurface("jailgames.gif")),
since_1998_surface_(Resource::Cache::get()->getSurface("since_1998.gif")),
delta_timer_(std::make_unique<DeltaTimer>()) {
// Calcula posiciones dinámicas basadas en el tamaño del canvas y las texturas
jailgames_dest_x_ = GameCanvas::CENTER_X - (jailgames_surface_->getWidth() / 2);
base_y_ = GameCanvas::CENTER_Y - (jailgames_surface_->getHeight() / 2);
// Crea el sprite "Since 1998" centrado horizontalmente, debajo del logo JAILGAMES
const int SINCE_1998_X = GameCanvas::CENTER_X - (since_1998_surface_->getWidth() / 2);
const int SINCE_1998_Y = base_y_ + jailgames_surface_->getHeight() + 5;
since_1998_sprite_ = std::make_shared<SurfaceSprite>(
since_1998_surface_,
SINCE_1998_X,
SINCE_1998_Y,
since_1998_surface_->getWidth(),
since_1998_surface_->getHeight());
// Configura variables
since_1998_sprite_->setClip(0, 0, since_1998_surface_->getWidth(), since_1998_surface_->getHeight());
since_1998_color_ = Color::index(Color::Cpc::BLACK);
jailgames_color_ = Color::index(Color::Cpc::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<EasingFunction, 4> 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<size_t> dist(0, EASING_OPTIONS.size() - 1);
easing_function_ = EASING_OPTIONS[dist(gen)];
// Cambia el color del borde
Screen::get()->setBorderColor(Color::index(Color::Cpc::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 auto INITIAL_X = static_cast<float>(jailgames_initial_x_[i]);
const auto DEST_X = static_cast<float>(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<int>(color_.size()) - 1;
const int INDEX = static_cast<int>(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(Color::index(Color::Cpc::BLACK));
// Dibuja los objetos
for (const auto& sprite : jailgames_sprite_) {
sprite->render(27, jailgames_color_);
}
since_1998_sprite_->render(27, 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::NONE:
SceneManager::current = SceneManager::Scene::TITLE;
break;
default:
// Ninguna acción por defecto
break;
}
}
// Inicializa el vector de colores
void Logo::initColors() {
// Inicializa el vector de colores
const std::vector<Uint8> COLORS = {
Color::index(Color::Cpc::BLACK),
Color::index(Color::Cpc::BLUE),
Color::index(Color::Cpc::RED),
Color::index(Color::Cpc::MAGENTA),
Color::index(Color::Cpc::GREEN),
Color::index(Color::Cpc::CYAN),
Color::index(Color::Cpc::YELLOW),
Color::index(Color::Cpc::BRIGHT_WHITE)};
for (const auto& color : COLORS) {
color_.push_back(color);
}
}
// Crea los sprites de cada linea
void Logo::initSprites() {
const int TEXTURE_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<SurfaceSprite>(jailgames_surface_, 0, i, TEXTURE_WIDTH, 1));
jailgames_sprite_.back()->setClip(0, i, TEXTURE_WIDTH, 1);
// Calcular posición inicial (alternando entre derecha e izquierda, fuera del canvas)
constexpr int LINE_OFFSET = 6;
const int INITIAL_X = (i % 2 == 0)
? (GameCanvas::WIDTH + (i * LINE_OFFSET))
: (-TEXTURE_WIDTH - (i * LINE_OFFSET));
jailgames_initial_x_.push_back(INITIAL_X);
jailgames_sprite_.at(i)->setX(INITIAL_X);
jailgames_sprite_.at(i)->setY(base_y_ + i);
}
}