From c959e0e3a07d46b8c2fe3f2de35f3eef69f712a8 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Tue, 16 Dec 2025 09:39:53 +0100 Subject: [PATCH] animacions de INIT_HUD amb control d'inici i final --- source/core/defaults.hpp | 22 ++++- source/core/math/easing.hpp | 24 ++++++ source/game/escenes/escena_joc.cpp | 132 ++++++++++++++++++++--------- source/game/escenes/escena_joc.hpp | 7 +- 4 files changed, 139 insertions(+), 46 deletions(-) diff --git a/source/core/defaults.hpp b/source/core/defaults.hpp index 1a2a65d..0231b69 100644 --- a/source/core/defaults.hpp +++ b/source/core/defaults.hpp @@ -131,10 +131,24 @@ constexpr float LEVEL_COMPLETED_DURATION = 3.0f; // Duración total constexpr float LEVEL_COMPLETED_TYPING_RATIO = 0.0f; // 0.0 = sin typewriter (directo) // Transición INIT_HUD (animación inicial del HUD) -constexpr float INIT_HUD_DURATION = 3.0f; // Duración total del estado -constexpr float INIT_HUD_RECT_RATIO = 0.67f; // Proporción animación rectángulo -constexpr float INIT_HUD_SCORE_RATIO = 0.83f; // Proporción animación marcador -constexpr float INIT_HUD_SHIP_RATIO = 1.0f; // Proporción animación nave +constexpr float INIT_HUD_DURATION = 3.0f; // Duración total del estado + +// Ratios de animación (inicio y fin como porcentajes del tiempo total) +// RECT (rectángulo de marges) +constexpr float INIT_HUD_RECT_RATIO_INIT = 0.33f; +constexpr float INIT_HUD_RECT_RATIO_END = 1.0f; + +// SCORE (marcador de puntuación) +constexpr float INIT_HUD_SCORE_RATIO_INIT = 0.17f; +constexpr float INIT_HUD_SCORE_RATIO_END = 1.0f; + +// SHIP1 (nave jugador 1) +constexpr float INIT_HUD_SHIP1_RATIO_INIT = 0.0f; +constexpr float INIT_HUD_SHIP1_RATIO_END = 1.0f; + +// SHIP2 (nave jugador 2) +constexpr float INIT_HUD_SHIP2_RATIO_INIT = 0.20f; +constexpr float INIT_HUD_SHIP2_RATIO_END = 1.0f; // Posición inicial de la nave en INIT_HUD (75% de altura de zona de juego) constexpr float INIT_HUD_SHIP_START_Y_RATIO = 0.75f; // 75% desde el top de PLAYAREA diff --git a/source/core/math/easing.hpp b/source/core/math/easing.hpp index f10a35d..7bc48d7 100644 --- a/source/core/math/easing.hpp +++ b/source/core/math/easing.hpp @@ -12,6 +12,30 @@ inline float ease_out_quad(float t) { return 1.0f - (1.0f - t) * (1.0f - t); } +// Ease-in quadratic: empieza lento, acelera +// t = progreso normalizado [0.0 - 1.0] +// retorna valor interpolado [0.0 - 1.0] +inline float ease_in_quad(float t) { + return t * t; +} + +// Ease-in-out quadratic: acelera al inicio, desacelera al final +// t = progreso normalizado [0.0 - 1.0] +// retorna valor interpolado [0.0 - 1.0] +inline float ease_in_out_quad(float t) { + return (t < 0.5f) + ? 2.0f * t * t + : 1.0f - (-2.0f * t + 2.0f) * (-2.0f * t + 2.0f) / 2.0f; +} + +// Ease-out cubic: desaceleración más suave que quadratic +// t = progreso normalizado [0.0 - 1.0] +// retorna valor interpolado [0.0 - 1.0] +inline float ease_out_cubic(float t) { + float t1 = 1.0f - t; + return 1.0f - t1 * t1 * t1; +} + // Interpolación lineal básica (para referencia) inline float lerp(float start, float end, float t) { return start + (end - start) * t; diff --git a/source/game/escenes/escena_joc.cpp b/source/game/escenes/escena_joc.cpp index 58c0822..e17f2cd 100644 --- a/source/game/escenes/escena_joc.cpp +++ b/source/game/escenes/escena_joc.cpp @@ -160,10 +160,10 @@ void EscenaJoc::inicialitzar() { puntuacio_per_jugador_[1] = 0; gestor_puntuacio_.reiniciar(); - // Set spawn point to center X, 75% Y (legacy, for INIT_HUD animation) - const SDL_FRect& zona = Defaults::Zones::PLAYAREA; - punt_spawn_.x = zona.x + zona.w * 0.5f; - punt_spawn_.y = zona.y + zona.h * Defaults::Game::INIT_HUD_SHIP_START_Y_RATIO; + // DEPRECATED: punt_spawn_ ja no s'usa, es calcula dinàmicament amb obtenir_punt_spawn(player_id) + // const SDL_FRect& zona = Defaults::Zones::PLAYAREA; + // punt_spawn_.x = zona.x + zona.w * 0.5f; + // punt_spawn_.y = zona.y + zona.h * Defaults::Game::INIT_HUD_SHIP_START_Y_RATIO; // Inicialitzar naus segons configuració (només jugadors actius) for (uint8_t i = 0; i < 2; i++) { @@ -318,22 +318,33 @@ void EscenaJoc::actualitzar(float delta_time) { break; } - // Calcular progrés de l'animació de la nau - float ship_progress = 1.0f - (stage_manager_->get_timer_transicio() / - Defaults::Game::INIT_HUD_DURATION); - ship_progress = std::min(1.0f, ship_progress); + // Calcular global progress (0.0 al inicio → 1.0 al final) + float global_progress = 1.0f - (stage_manager_->get_timer_transicio() / + Defaults::Game::INIT_HUD_DURATION); + global_progress = std::min(1.0f, global_progress); - // Calcular quant ha avançat l'animació de la nau - float ship_anim_progress = ship_progress / Defaults::Game::INIT_HUD_SHIP_RATIO; - ship_anim_progress = std::min(1.0f, ship_anim_progress); + // [NEW] Calcular progress independiente para cada nave + float ship1_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_SHIP1_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP1_RATIO_END + ); - // [NOU] Determinar quina nau ha d'animar-se (jugador actiu) - uint8_t ship_to_animate = config_partida_.jugador1_actiu ? 0 : 1; + float ship2_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP2_RATIO_END + ); - // Actualitzar posició de la nau activa segons animació - if (ship_anim_progress < 1.0f) { - Punt pos_animada = calcular_posicio_nau_init_hud(ship_anim_progress); - naus_[ship_to_animate].set_centre(pos_animada); // Nau del jugador actiu + // [MODIFICAT] Animar AMBAS naus con sus progress respectivos + if (config_partida_.jugador1_actiu && ship1_progress < 1.0f) { + Punt pos_p1 = calcular_posicio_nau_init_hud(ship1_progress, 0); + naus_[0].set_centre(pos_p1); + } + + if (config_partida_.jugador2_actiu && ship2_progress < 1.0f) { + Punt pos_p2 = calcular_posicio_nau_init_hud(ship2_progress, 1); + naus_[1].set_centre(pos_p2); } // Una vegada l'animació acaba, permetre control normal @@ -482,17 +493,30 @@ void EscenaJoc::dibuixar() { float total_time = Defaults::Game::INIT_HUD_DURATION; float global_progress = 1.0f - (timer / total_time); - // Progrés del rectangle (empieza inmediatament) - float rect_progress = global_progress / Defaults::Game::INIT_HUD_RECT_RATIO; - rect_progress = std::min(1.0f, rect_progress); + // [NEW] Calcular progress independiente para cada elemento + float rect_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_RECT_RATIO_INIT, + Defaults::Game::INIT_HUD_RECT_RATIO_END + ); - // Progrés del marcador (empieza inmediatament) - float score_progress = global_progress / Defaults::Game::INIT_HUD_SCORE_RATIO; - score_progress = std::min(1.0f, score_progress); + float score_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_SCORE_RATIO_INIT, + Defaults::Game::INIT_HUD_SCORE_RATIO_END + ); - // Progrés de la nau (empieza inmediatament) - float ship_progress = global_progress / Defaults::Game::INIT_HUD_SHIP_RATIO; - ship_progress = std::min(1.0f, ship_progress); + float ship1_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_SHIP1_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP1_RATIO_END + ); + + float ship2_progress = calcular_progress_rango( + global_progress, + Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP2_RATIO_END + ); // Dibuixar elements animats if (rect_progress > 0.0f) { @@ -503,10 +527,13 @@ void EscenaJoc::dibuixar() { dibuixar_marcador_animat(score_progress); } - // Dibuixar nau del jugador actiu (posició ja actualitzada en actualitzar()) - uint8_t ship_to_draw = config_partida_.jugador1_actiu ? 0 : 1; - if (ship_progress > 0.0f && !naus_[ship_to_draw].esta_tocada()) { - naus_[ship_to_draw].dibuixar(); + // [MODIFICAT] Dibuixar naus amb progress independent + if (ship1_progress > 0.0f && config_partida_.jugador1_actiu && !naus_[0].esta_tocada()) { + naus_[0].dibuixar(); + } + + if (ship2_progress > 0.0f && config_partida_.jugador2_actiu && !naus_[1].esta_tocada()) { + naus_[1].dibuixar(); } break; @@ -759,30 +786,55 @@ void EscenaJoc::dibuixar_marcador_animat(float progress) { text_.render(text, {x_final, y_animada}, escala, spacing); } -Punt EscenaJoc::calcular_posicio_nau_init_hud(float progress) const { +Punt EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const { // Animació de la nau pujant des de baix amb easing + // [MODIFICAT] Ambas naves usan ease_out_quad (desfase temporal via INIT/END) - // Calcular progrés amb easing + // Aplicar easing (uniforme para ambas naves) float eased_progress = Easing::ease_out_quad(progress); const SDL_FRect& zona = Defaults::Zones::PLAYAREA; - // Posició X final (centre de la zona de joc) - float x_final = zona.x + zona.w / 2.0f; + // Calcular posició final segons jugador (reutilitza obtenir_punt_spawn) + Punt spawn_final = obtenir_punt_spawn(player_id); + float x_final = spawn_final.x; + float y_final = spawn_final.y; - // Posició Y final (75% de l'altura de la zona de joc) - float y_final = zona.y + zona.h * Defaults::Game::INIT_HUD_SHIP_START_Y_RATIO; + // Y inicial: offscreen, 50px sota la zona de joc + float y_inicial = zona.y + zona.h + 50.0f; - // Posició Y inicial (offscreen, sota de la zona de joc) - float y_inicial = zona.y + zona.h + 50.0f; // 50px sota - - // X no canvia (sempre centrada) + // X no canvia (destí segons player_id) // Y interpola amb easing float y_animada = y_inicial + (y_final - y_inicial) * eased_progress; return {x_final, y_animada}; } +float EscenaJoc::calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const { + // Convierte global_progress (0.0→1.0) a element_progress usando ventana [INIT, END] + // + // Casos: + // - global_progress < INIT → 0.0 (no ha empezado) + // - global_progress > END → 1.0 (completado) + // - INIT ≤ global_progress ≤ END → interpola linealmente 0.0→1.0 + + // Validación de parámetros (evita división por cero) + if (ratio_init >= ratio_end) { + return (global_progress >= ratio_end) ? 1.0f : 0.0f; + } + + if (global_progress < ratio_init) { + return 0.0f; + } + + if (global_progress > ratio_end) { + return 1.0f; + } + + // Normalizar rango [INIT, END] a [0.0, 1.0] + return (global_progress - ratio_init) / (ratio_end - ratio_init); +} + std::string EscenaJoc::construir_marcador() const { // Puntuació P1 (6 dígits) - mostrar zeros si inactiu std::string score_p1; diff --git a/source/game/escenes/escena_joc.hpp b/source/game/escenes/escena_joc.hpp index a265aa9..2e01053 100644 --- a/source/game/escenes/escena_joc.hpp +++ b/source/game/escenes/escena_joc.hpp @@ -56,7 +56,7 @@ class EscenaJoc { std::array vides_per_jugador_; // [0]=P1, [1]=P2 bool game_over_; // Game over state flag float game_over_timer_; // Countdown timer for auto-return (seconds) - Punt punt_spawn_; // Configurable spawn point (legacy) + // Punt punt_spawn_; // DEPRECATED: usar obtenir_punt_spawn(player_id) Punt punt_mort_; // Death position (for respawn, legacy) std::array puntuacio_per_jugador_; // [0]=P1, [1]=P2 @@ -82,7 +82,10 @@ class EscenaJoc { // [NEW] Funcions d'animació per INIT_HUD void dibuixar_marges_animat(float progress) const; // Rectangle amb creixement uniforme void dibuixar_marcador_animat(float progress); // Marcador que puja des de baix - Punt calcular_posicio_nau_init_hud(float progress) const; // Posició animada de la nau + Punt calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const; // Posició animada de la nau + + // [NEW] Función helper del sistema de animación INIT_HUD + float calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const; // [NEW] Funció helper del marcador std::string construir_marcador() const;