diff --git a/source/app_logo.cpp b/source/app_logo.cpp index 34a029e..958c1ba 100644 --- a/source/app_logo.cpp +++ b/source/app_logo.cpp @@ -197,7 +197,8 @@ void AppLogo::update(float delta_time, AppMode current_mode) { if (current_mode == AppMode::SANDBOX) { state_ = AppLogoState::HIDDEN; timer_ = 0.0f; - current_alpha_ = 0; + logo1_alpha_ = 0; + logo2_alpha_ = 0; return; } @@ -210,22 +211,27 @@ void AppLogo::update(float delta_time, AppMode current_mode) { if (timer_ >= APPLOGO_DISPLAY_INTERVAL) { state_ = AppLogoState::FADE_IN; timer_ = 0.0f; - current_alpha_ = 0; - // Elegir animaciones de entrada aleatorias (independientes para cada logo) - logo1_entry_animation_ = getRandomAnimation(); - logo2_entry_animation_ = getRandomAnimation(); + logo1_alpha_ = 0; + logo2_alpha_ = 0; + // Elegir UNA animación aleatoria (misma para ambos logos, misma entrada y salida) + current_animation_ = getRandomAnimation(); } break; case AppLogoState::FADE_IN: - // Fade in: alpha de 0 a 255, animaciones independientes para logo1 y logo2 + // Fade in: alpha de 0 a 255, con Logo 2 retrasado 0.25s { - float fade_progress = timer_ / APPLOGO_FADE_DURATION; - if (fade_progress >= 1.0f) { - // Fade in completado + // Calcular progreso de cada logo (Logo 2 con retraso) + float fade_progress_logo1 = timer_ / APPLOGO_FADE_DURATION; + float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_FADE_DURATION); + + // Verificar si fade in completado (cuando logo2 también termina) + if (fade_progress_logo2 >= 1.0f) { + // Fade in completado para ambos logos state_ = AppLogoState::VISIBLE; timer_ = 0.0f; - current_alpha_ = 255; + logo1_alpha_ = 255; + logo2_alpha_ = 255; // Resetear variables de ambos logos logo1_scale_ = 1.0f; logo1_squash_y_ = 1.0f; @@ -236,59 +242,24 @@ void AppLogo::update(float delta_time, AppMode current_mode) { logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; } else { - // Interpolar alpha linealmente (0 → 255) - compartido - current_alpha_ = static_cast(fade_progress * 255.0f); + // Interpolar alpha con retraso + easing para suavidad + float eased_prog1 = easeInOutQuad(std::min(1.0f, fade_progress_logo1)); + float eased_prog2 = easeInOutQuad(std::min(1.0f, fade_progress_logo2)); + logo1_alpha_ = static_cast(eased_prog1 * 255.0f); + logo2_alpha_ = static_cast(eased_prog2 * 255.0f); // ================================================================ - // Aplicar animación de LOGO1 según logo1_entry_animation_ + // Aplicar MISMA animación (current_animation_) a ambos logos + // con sus respectivos progresos // ================================================================ - switch (logo1_entry_animation_) { + switch (current_animation_) { case AppLogoAnimationType::ZOOM_ONLY: - logo1_scale_ = 1.2f - (fade_progress * 0.2f); + logo1_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo1) * 0.2f); logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; - break; - case AppLogoAnimationType::ELASTIC_STICK: - { - float elastic_t = easeOutElastic(fade_progress); - logo1_scale_ = 1.2f - (elastic_t * 0.2f); - float squash_t = easeOutBack(fade_progress); - logo1_squash_y_ = 0.6f + (squash_t * 0.4f); - logo1_stretch_x_ = 1.0f + (1.0f - logo1_squash_y_) * 0.5f; - logo1_rotation_ = 0.0f; - } - break; - - case AppLogoAnimationType::ROTATE_SPIRAL: - { - float ease_t = easeInOutQuad(fade_progress); - logo1_scale_ = 0.3f + (ease_t * 0.7f); - logo1_rotation_ = (1.0f - fade_progress) * 6.28f; - logo1_squash_y_ = 1.0f; - logo1_stretch_x_ = 1.0f; - } - break; - - case AppLogoAnimationType::BOUNCE_SQUASH: - { - float bounce_t = easeOutBounce(fade_progress); - logo1_scale_ = 1.0f; - float squash_amount = (1.0f - bounce_t) * 0.3f; - logo1_squash_y_ = 1.0f - squash_amount; - logo1_stretch_x_ = 1.0f + squash_amount * 0.5f; - logo1_rotation_ = 0.0f; - } - break; - } - - // ================================================================ - // Aplicar animación de LOGO2 según logo2_entry_animation_ - // ================================================================ - switch (logo2_entry_animation_) { - case AppLogoAnimationType::ZOOM_ONLY: - logo2_scale_ = 1.2f - (fade_progress * 0.2f); + logo2_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo2) * 0.2f); logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; @@ -296,10 +267,19 @@ void AppLogo::update(float delta_time, AppMode current_mode) { case AppLogoAnimationType::ELASTIC_STICK: { - float elastic_t = easeOutElastic(fade_progress); - logo2_scale_ = 1.2f - (elastic_t * 0.2f); - float squash_t = easeOutBack(fade_progress); - logo2_squash_y_ = 0.6f + (squash_t * 0.4f); + float prog1 = std::min(1.0f, fade_progress_logo1); + float elastic_t1 = easeOutElastic(prog1); + logo1_scale_ = 1.2f - (elastic_t1 * 0.2f); + float squash_t1 = easeOutBack(prog1); + logo1_squash_y_ = 0.6f + (squash_t1 * 0.4f); + logo1_stretch_x_ = 1.0f + (1.0f - logo1_squash_y_) * 0.5f; + logo1_rotation_ = 0.0f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + float elastic_t2 = easeOutElastic(prog2); + logo2_scale_ = 1.2f - (elastic_t2 * 0.2f); + float squash_t2 = easeOutBack(prog2); + logo2_squash_y_ = 0.6f + (squash_t2 * 0.4f); logo2_stretch_x_ = 1.0f + (1.0f - logo2_squash_y_) * 0.5f; logo2_rotation_ = 0.0f; } @@ -307,9 +287,17 @@ void AppLogo::update(float delta_time, AppMode current_mode) { case AppLogoAnimationType::ROTATE_SPIRAL: { - float ease_t = easeInOutQuad(fade_progress); - logo2_scale_ = 0.3f + (ease_t * 0.7f); - logo2_rotation_ = (1.0f - fade_progress) * 6.28f; + float prog1 = std::min(1.0f, fade_progress_logo1); + float ease_t1 = easeInOutQuad(prog1); + logo1_scale_ = 0.3f + (ease_t1 * 0.7f); + logo1_rotation_ = (1.0f - prog1) * 6.28f; + logo1_squash_y_ = 1.0f; + logo1_stretch_x_ = 1.0f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + float ease_t2 = easeInOutQuad(prog2); + logo2_scale_ = 0.3f + (ease_t2 * 0.7f); + logo2_rotation_ = (1.0f - prog2) * 6.28f; logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; } @@ -317,11 +305,20 @@ void AppLogo::update(float delta_time, AppMode current_mode) { case AppLogoAnimationType::BOUNCE_SQUASH: { - float bounce_t = easeOutBounce(fade_progress); + float prog1 = std::min(1.0f, fade_progress_logo1); + float bounce_t1 = easeOutBounce(prog1); + logo1_scale_ = 1.0f; + float squash_amount1 = (1.0f - bounce_t1) * 0.3f; + logo1_squash_y_ = 1.0f - squash_amount1; + logo1_stretch_x_ = 1.0f + squash_amount1 * 0.5f; + logo1_rotation_ = 0.0f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + float bounce_t2 = easeOutBounce(prog2); logo2_scale_ = 1.0f; - float squash_amount = (1.0f - bounce_t) * 0.3f; - logo2_squash_y_ = 1.0f - squash_amount; - logo2_stretch_x_ = 1.0f + squash_amount * 0.5f; + float squash_amount2 = (1.0f - bounce_t2) * 0.3f; + logo2_squash_y_ = 1.0f - squash_amount2; + logo2_stretch_x_ = 1.0f + squash_amount2 * 0.5f; logo2_rotation_ = 0.0f; } break; @@ -335,22 +332,26 @@ void AppLogo::update(float delta_time, AppMode current_mode) { if (timer_ >= APPLOGO_DISPLAY_DURATION) { state_ = AppLogoState::FADE_OUT; timer_ = 0.0f; - current_alpha_ = 255; - // Elegir animaciones de salida aleatorias (independientes para cada logo) - logo1_exit_animation_ = getRandomAnimation(); - logo2_exit_animation_ = getRandomAnimation(); + logo1_alpha_ = 255; + logo2_alpha_ = 255; + // NO elegir nueva animación - reutilizar current_animation_ (simetría entrada/salida) } break; case AppLogoState::FADE_OUT: - // Fade out: alpha de 255 a 0, animaciones independientes para logo1 y logo2 + // Fade out: alpha de 255 a 0, con Logo 2 retrasado 0.25s (misma animación que entrada) { - float fade_progress = timer_ / APPLOGO_FADE_DURATION; - if (fade_progress >= 1.0f) { + // Calcular progreso de cada logo (Logo 2 con retraso) + float fade_progress_logo1 = timer_ / APPLOGO_FADE_DURATION; + float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_FADE_DURATION); + + // Verificar si fade out completado (cuando logo2 también termina) + if (fade_progress_logo2 >= 1.0f) { // Fade out completado, volver a HIDDEN state_ = AppLogoState::HIDDEN; timer_ = 0.0f; - current_alpha_ = 0; + logo1_alpha_ = 0; + logo2_alpha_ = 0; // Resetear variables de ambos logos logo1_scale_ = 1.0f; logo1_squash_y_ = 1.0f; @@ -361,77 +362,57 @@ void AppLogo::update(float delta_time, AppMode current_mode) { logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; } else { - // Interpolar alpha linealmente (255 → 0) - compartido - current_alpha_ = static_cast((1.0f - fade_progress) * 255.0f); + // Interpolar alpha con retraso + easing para suavidad (255 → 0) + float eased_prog1 = easeInOutQuad(std::min(1.0f, fade_progress_logo1)); + float eased_prog2 = easeInOutQuad(std::min(1.0f, fade_progress_logo2)); + logo1_alpha_ = static_cast((1.0f - eased_prog1) * 255.0f); + logo2_alpha_ = static_cast((1.0f - eased_prog2) * 255.0f); // ================================================================ - // Aplicar animación de LOGO1 según logo1_exit_animation_ + // Aplicar MISMA animación (current_animation_) de forma invertida // ================================================================ - switch (logo1_exit_animation_) { + switch (current_animation_) { case AppLogoAnimationType::ZOOM_ONLY: - logo1_scale_ = 1.0f + (fade_progress * 0.2f); + logo1_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo1) * 0.2f); logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; - break; - case AppLogoAnimationType::ELASTIC_STICK: - logo1_scale_ = 1.0f + (fade_progress * fade_progress * 0.2f); - logo1_squash_y_ = 1.0f + (fade_progress * 0.3f); - logo1_stretch_x_ = 1.0f - (fade_progress * 0.2f); - logo1_rotation_ = fade_progress * 0.1f; - break; - - case AppLogoAnimationType::ROTATE_SPIRAL: - { - float ease_t = easeInOutQuad(fade_progress); - logo1_scale_ = 1.0f - (ease_t * 0.7f); - logo1_rotation_ = fade_progress * 6.28f; - logo1_squash_y_ = 1.0f; - logo1_stretch_x_ = 1.0f; - } - break; - - case AppLogoAnimationType::BOUNCE_SQUASH: - { - if (fade_progress < 0.2f) { - float squash_t = fade_progress / 0.2f; - logo1_squash_y_ = 1.0f - (squash_t * 0.3f); - logo1_stretch_x_ = 1.0f + (squash_t * 0.2f); - } else { - float jump_t = (fade_progress - 0.2f) / 0.8f; - logo1_squash_y_ = 0.7f + (jump_t * 0.5f); - logo1_stretch_x_ = 1.2f - (jump_t * 0.2f); - } - logo1_scale_ = 1.0f + (fade_progress * 0.3f); - logo1_rotation_ = 0.0f; - } - break; - } - - // ================================================================ - // Aplicar animación de LOGO2 según logo2_exit_animation_ - // ================================================================ - switch (logo2_exit_animation_) { - case AppLogoAnimationType::ZOOM_ONLY: - logo2_scale_ = 1.0f + (fade_progress * 0.2f); + logo2_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo2) * 0.2f); logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; break; case AppLogoAnimationType::ELASTIC_STICK: - logo2_scale_ = 1.0f + (fade_progress * fade_progress * 0.2f); - logo2_squash_y_ = 1.0f + (fade_progress * 0.3f); - logo2_stretch_x_ = 1.0f - (fade_progress * 0.2f); - logo2_rotation_ = fade_progress * 0.1f; + { + float prog1 = std::min(1.0f, fade_progress_logo1); + logo1_scale_ = 1.0f + (prog1 * prog1 * 0.2f); + logo1_squash_y_ = 1.0f + (prog1 * 0.3f); + logo1_stretch_x_ = 1.0f - (prog1 * 0.2f); + logo1_rotation_ = prog1 * 0.1f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + logo2_scale_ = 1.0f + (prog2 * prog2 * 0.2f); + logo2_squash_y_ = 1.0f + (prog2 * 0.3f); + logo2_stretch_x_ = 1.0f - (prog2 * 0.2f); + logo2_rotation_ = prog2 * 0.1f; + } break; case AppLogoAnimationType::ROTATE_SPIRAL: { - float ease_t = easeInOutQuad(fade_progress); - logo2_scale_ = 1.0f - (ease_t * 0.7f); - logo2_rotation_ = fade_progress * 6.28f; + float prog1 = std::min(1.0f, fade_progress_logo1); + float ease_t1 = easeInOutQuad(prog1); + logo1_scale_ = 1.0f - (ease_t1 * 0.7f); + logo1_rotation_ = prog1 * 6.28f; + logo1_squash_y_ = 1.0f; + logo1_stretch_x_ = 1.0f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + float ease_t2 = easeInOutQuad(prog2); + logo2_scale_ = 1.0f - (ease_t2 * 0.7f); + logo2_rotation_ = prog2 * 6.28f; logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; } @@ -439,16 +420,30 @@ void AppLogo::update(float delta_time, AppMode current_mode) { case AppLogoAnimationType::BOUNCE_SQUASH: { - if (fade_progress < 0.2f) { - float squash_t = fade_progress / 0.2f; + float prog1 = std::min(1.0f, fade_progress_logo1); + if (prog1 < 0.2f) { + float squash_t = prog1 / 0.2f; + logo1_squash_y_ = 1.0f - (squash_t * 0.3f); + logo1_stretch_x_ = 1.0f + (squash_t * 0.2f); + } else { + float jump_t = (prog1 - 0.2f) / 0.8f; + logo1_squash_y_ = 0.7f + (jump_t * 0.5f); + logo1_stretch_x_ = 1.2f - (jump_t * 0.2f); + } + logo1_scale_ = 1.0f + (prog1 * 0.3f); + logo1_rotation_ = 0.0f; + + float prog2 = std::min(1.0f, fade_progress_logo2); + if (prog2 < 0.2f) { + float squash_t = prog2 / 0.2f; logo2_squash_y_ = 1.0f - (squash_t * 0.3f); logo2_stretch_x_ = 1.0f + (squash_t * 0.2f); } else { - float jump_t = (fade_progress - 0.2f) / 0.8f; + float jump_t = (prog2 - 0.2f) / 0.8f; logo2_squash_y_ = 0.7f + (jump_t * 0.5f); logo2_stretch_x_ = 1.2f - (jump_t * 0.2f); } - logo2_scale_ = 1.0f + (fade_progress * 0.3f); + logo2_scale_ = 1.0f + (prog2 * 0.3f); logo2_rotation_ = 0.0f; } break; @@ -610,8 +605,9 @@ void AppLogo::renderWithGeometry(int logo_index) { return; // Índice inválido } - // Aplicar alpha a la textura - SDL_SetTextureAlphaMod(texture, static_cast(current_alpha_)); + // Aplicar alpha específico de cada logo (con retraso para logo2) + int alpha = (logo_index == 1) ? logo1_alpha_ : logo2_alpha_; + SDL_SetTextureAlphaMod(texture, static_cast(alpha)); // Calcular tamaño con escala y deformaciones aplicadas // (base_width y base_height ya están pre-escalados al tamaño correcto de pantalla) diff --git a/source/app_logo.h b/source/app_logo.h index 632e6df..e19e8b9 100644 --- a/source/app_logo.h +++ b/source/app_logo.h @@ -72,13 +72,13 @@ class AppLogo { // ==================================================================== AppLogoState state_ = AppLogoState::HIDDEN; // Estado actual de la máquina de estados float timer_ = 0.0f; // Contador de tiempo para estado actual - int current_alpha_ = 0; // Alpha actual (0-255) - // Animaciones INDEPENDIENTES para cada logo - AppLogoAnimationType logo1_entry_animation_ = AppLogoAnimationType::ZOOM_ONLY; - AppLogoAnimationType logo1_exit_animation_ = AppLogoAnimationType::ZOOM_ONLY; - AppLogoAnimationType logo2_entry_animation_ = AppLogoAnimationType::ZOOM_ONLY; - AppLogoAnimationType logo2_exit_animation_ = AppLogoAnimationType::ZOOM_ONLY; + // Alpha INDEPENDIENTE para cada logo (Logo 2 con retraso) + int logo1_alpha_ = 0; // Alpha de Logo 1 (0-255) + int logo2_alpha_ = 0; // Alpha de Logo 2 (0-255, con retraso) + + // Animación COMPARTIDA (misma para ambos logos, misma entrada y salida) + AppLogoAnimationType current_animation_ = AppLogoAnimationType::ZOOM_ONLY; // Variables de deformación INDEPENDIENTES para logo1 float logo1_scale_ = 1.0f; // Escala actual de logo1 (1.0 = 100%) diff --git a/source/defines.h b/source/defines.h index 8c71740..d46a234 100644 --- a/source/defines.h +++ b/source/defines.h @@ -294,6 +294,7 @@ constexpr float APPLOGO_DISPLAY_DURATION = 5.0f; // Duración de visibilidad constexpr float APPLOGO_FADE_DURATION = 0.5f; // Duración del fade in/out (segundos) constexpr float APPLOGO_HEIGHT_PERCENT = 0.4f; // Altura del logo = 40% de la altura de pantalla constexpr float APPLOGO_PADDING_PERCENT = 0.1f; // Padding desde esquina inferior-derecha = 10% +constexpr float APPLOGO_LOGO2_DELAY = 0.25f; // Retraso de Logo 2 respecto a Logo 1 (segundos) // Configuración de Modo BOIDS (comportamiento de enjambre) // TIME-BASED CONVERSION (frame-based → time-based):