From cdc4d0739418cee18601ff699a1723a9d5db9869 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 4 Dec 2025 08:00:13 +0100 Subject: [PATCH] animacio del titol als 10 segons --- source/game/escenes/escena_titol.cpp | 145 ++++++++++++++++++++++++--- source/game/escenes/escena_titol.hpp | 27 +++++ 2 files changed, 160 insertions(+), 12 deletions(-) diff --git a/source/game/escenes/escena_titol.cpp b/source/game/escenes/escena_titol.cpp index 13c8277..23ab711 100644 --- a/source/game/escenes/escena_titol.cpp +++ b/source/game/escenes/escena_titol.cpp @@ -25,7 +25,11 @@ EscenaTitol::EscenaTitol(SDLManager& sdl) : sdl_(sdl), text_(sdl.obte_renderer()), estat_actual_(EstatTitol::INIT), - temps_acumulat_(0.0f) { + temps_acumulat_(0.0f), + temps_animacio_(0.0f), + temps_estat_main_(0.0f), + animacio_activa_(false), + factor_lerp_(0.0f) { std::cout << "Escena Titol: Inicialitzant...\n"; // Crear starfield de fons @@ -198,6 +202,19 @@ void EscenaTitol::inicialitzar_titol() { std::cout << "[EscenaTitol] Línia 2 (ATTACK!): " << lletres_attack_.size() << " lletres, ancho total: " << ancho_total_attack << " px\n"; + + // Guardar posicions originals per l'animació orbital + posicions_originals_orni_.clear(); + for (const auto& lletra : lletres_orni_) { + posicions_originals_orni_.push_back(lletra.posicio); + } + + posicions_originals_attack_.clear(); + for (const auto& lletra : lletres_attack_) { + posicions_originals_attack_.push_back(lletra.posicio); + } + + std::cout << "[EscenaTitol] Animació: Posicions originals guardades\n"; } void EscenaTitol::executar() { @@ -273,12 +290,60 @@ void EscenaTitol::actualitzar(float delta_time) { temps_acumulat_ += delta_time; if (temps_acumulat_ >= DURACIO_INIT) { estat_actual_ = EstatTitol::MAIN; + temps_estat_main_ = 0.0f; // Reset timer al entrar a MAIN + animacio_activa_ = false; // Comença estàtic + factor_lerp_ = 0.0f; // Sense animació encara } break; - case EstatTitol::MAIN: - // No hi ha lògica d'actualització en l'estat MAIN + case EstatTitol::MAIN: { + temps_estat_main_ += delta_time; + + // Fase 1: Estàtic (0-10s) + if (temps_estat_main_ < DELAY_INICI_ANIMACIO) { + factor_lerp_ = 0.0f; + animacio_activa_ = false; + } + // Fase 2: Lerp (10-12s) + else if (temps_estat_main_ < DELAY_INICI_ANIMACIO + DURACIO_LERP) { + float temps_lerp = temps_estat_main_ - DELAY_INICI_ANIMACIO; + factor_lerp_ = temps_lerp / DURACIO_LERP; // 0.0 → 1.0 linealment + animacio_activa_ = true; + } + // Fase 3: Animació completa (12s+) + else { + factor_lerp_ = 1.0f; + animacio_activa_ = true; + } + + // Acumular temps escalat directament + if (animacio_activa_) { + temps_animacio_ += delta_time * factor_lerp_; + } + + // Usar amplituds i freqüències completes sempre + float amplitude_x_actual = ORBIT_AMPLITUDE_X; + float amplitude_y_actual = ORBIT_AMPLITUDE_Y; + float frequency_x_actual = ORBIT_FREQUENCY_X; + float frequency_y_actual = ORBIT_FREQUENCY_Y; + + // Calcular offset orbital + float offset_x = amplitude_x_actual * std::sin(2.0f * Defaults::Math::PI * frequency_x_actual * temps_animacio_); + float offset_y = amplitude_y_actual * std::sin(2.0f * Defaults::Math::PI * frequency_y_actual * temps_animacio_ + ORBIT_PHASE_OFFSET); + + // Aplicar offset a totes les lletres de "ORNI" + for (size_t i = 0; i < lletres_orni_.size(); ++i) { + lletres_orni_[i].posicio.x = posicions_originals_orni_[i].x + static_cast(std::round(offset_x)); + lletres_orni_[i].posicio.y = posicions_originals_orni_[i].y + static_cast(std::round(offset_y)); + } + + // Aplicar offset a totes les lletres de "ATTACK!" + for (size_t i = 0; i < lletres_attack_.size(); ++i) { + lletres_attack_[i].posicio.x = posicions_originals_attack_[i].x + static_cast(std::round(offset_x)); + lletres_attack_[i].posicio.y = posicions_originals_attack_[i].y + static_cast(std::round(offset_y)); + } break; + } case EstatTitol::TRANSITION: temps_acumulat_ += delta_time; @@ -303,7 +368,63 @@ void EscenaTitol::dibuixar() { // Estat MAIN i TRANSITION: Dibuixar títol i text (sobre el starfield) if (estat_actual_ == EstatTitol::MAIN || estat_actual_ == EstatTitol::TRANSITION) { - // === Dibuixar lletres del títol "ORNI ATTACK!" === + // === Calcular i renderitzar ombra (només si animació activa) === + if (animacio_activa_) { + float temps_shadow = temps_animacio_ - SHADOW_DELAY; + if (temps_shadow < 0.0f) temps_shadow = 0.0f; // Evitar temps negatiu + + // Usar amplituds i freqüències completes per l'ombra + float amplitude_x_shadow = ORBIT_AMPLITUDE_X; + float amplitude_y_shadow = ORBIT_AMPLITUDE_Y; + float frequency_x_shadow = ORBIT_FREQUENCY_X; + float frequency_y_shadow = ORBIT_FREQUENCY_Y; + + // Calcular offset de l'ombra + float shadow_offset_x = amplitude_x_shadow * std::sin(2.0f * Defaults::Math::PI * frequency_x_shadow * temps_shadow) + + SHADOW_OFFSET_X; + float shadow_offset_y = amplitude_y_shadow * std::sin(2.0f * Defaults::Math::PI * frequency_y_shadow * temps_shadow + ORBIT_PHASE_OFFSET) + + SHADOW_OFFSET_Y; + + // === RENDERITZAR OMBRA PRIMER (darrera del logo principal) === + + // Ombra "ORNI" + for (size_t i = 0; i < lletres_orni_.size(); ++i) { + Punt pos_shadow; + pos_shadow.x = posicions_originals_orni_[i].x + static_cast(std::round(shadow_offset_x)); + pos_shadow.y = posicions_originals_orni_[i].y + static_cast(std::round(shadow_offset_y)); + + Rendering::render_shape( + sdl_.obte_renderer(), + lletres_orni_[i].forma, + pos_shadow, + 0.0f, + ESCALA_TITULO, + true, + 1.0f, // progress = 1.0 (totalment visible) + SHADOW_BRIGHTNESS // brightness = 0.4 (brillantor reduïda) + ); + } + + // Ombra "ATTACK!" + for (size_t i = 0; i < lletres_attack_.size(); ++i) { + Punt pos_shadow; + pos_shadow.x = posicions_originals_attack_[i].x + static_cast(std::round(shadow_offset_x)); + pos_shadow.y = posicions_originals_attack_[i].y + static_cast(std::round(shadow_offset_y)); + + Rendering::render_shape( + sdl_.obte_renderer(), + lletres_attack_[i].forma, + pos_shadow, + 0.0f, + ESCALA_TITULO, + true, + 1.0f, // progress = 1.0 (totalment visible) + SHADOW_BRIGHTNESS + ); + } + } + + // === RENDERITZAR LOGO PRINCIPAL (damunt) === // Dibuixar "ORNI" (línia 1) for (const auto& lletra : lletres_orni_) { @@ -311,10 +432,10 @@ void EscenaTitol::dibuixar() { sdl_.obte_renderer(), lletra.forma, lletra.posicio, - 0.0f, // sense rotació - ESCALA_TITULO, // escala 80% - true, // dibuixar - 1.0f // progrés complet (totalment visible) + 0.0f, + ESCALA_TITULO, + true, + 1.0f // Brillantor completa ); } @@ -324,10 +445,10 @@ void EscenaTitol::dibuixar() { sdl_.obte_renderer(), lletra.forma, lletra.posicio, - 0.0f, // sense rotació - ESCALA_TITULO, // escala 80% - true, // dibuixar - 1.0f // progrés complet (totalment visible) + 0.0f, + ESCALA_TITULO, + true, + 1.0f // Brillantor completa ); } diff --git a/source/game/escenes/escena_titol.hpp b/source/game/escenes/escena_titol.hpp index 0fef599..c1cf089 100644 --- a/source/game/escenes/escena_titol.hpp +++ b/source/game/escenes/escena_titol.hpp @@ -50,6 +50,16 @@ class EscenaTitol { std::vector lletres_attack_; // Lletres de "ATTACK!" (línia 2) float y_attack_dinamica_; // Posició Y calculada dinàmicament per "ATTACK!" + // Estat d'animació del logo + float temps_animacio_; // Temps acumulat per animació orbital + std::vector posicions_originals_orni_; // Posicions originals de "ORNI" + std::vector posicions_originals_attack_; // Posicions originals de "ATTACK!" + + // Estat d'arrencada de l'animació + float temps_estat_main_; // Temps acumulat en estat MAIN + bool animacio_activa_; // Flag: true quan animació està activa + float factor_lerp_; // Factor de lerp actual (0.0 → 1.0) + // Constants static constexpr float DURACIO_INIT = 4.0f; // Duració de l'estat INIT (2 segons) static constexpr float DURACIO_TRANSITION = 1.5f; // Duració de la transició (1.5 segons) @@ -60,6 +70,23 @@ class EscenaTitol { static constexpr float BLINK_FREQUENCY = 3.0f; // Freqüència de parpelleig (3 Hz) static constexpr int MUSIC_FADE = 1000; // Duracio del fade de la musica del titol al començar a jugar + // Constants d'animació del logo + static constexpr float ORBIT_AMPLITUDE_X = 2.0f*2; // Amplitud oscil·lació horitzontal (píxels) + static constexpr float ORBIT_AMPLITUDE_Y = 1.5f*2; // Amplitud oscil·lació vertical (píxels) + static constexpr float ORBIT_FREQUENCY_X = 0.8f; // Velocitat oscil·lació horitzontal (Hz) + static constexpr float ORBIT_FREQUENCY_Y = 1.2f; // Velocitat oscil·lació vertical (Hz) + static constexpr float ORBIT_PHASE_OFFSET = 1.57f; // Desfasament entre X i Y (90° per circular) + + // Constants d'ombra del logo + static constexpr float SHADOW_DELAY = 0.5f; // Retard temporal de l'ombra (segons) + static constexpr float SHADOW_BRIGHTNESS = 0.4f; // Multiplicador de brillantor de l'ombra (0.0-1.0) + static constexpr float SHADOW_OFFSET_X = 2.0f; // Offset espacial X fix (píxels) + static constexpr float SHADOW_OFFSET_Y = 2.0f; // Offset espacial Y fix (píxels) + + // Temporització de l'arrencada de l'animació + static constexpr float DELAY_INICI_ANIMACIO = 10.0f; // 10s estàtic abans d'animar + static constexpr float DURACIO_LERP = 2.0f; // 2s per arribar a amplitud completa + // Mètodes privats void actualitzar(float delta_time); void dibuixar();