feat: Animaciones de logos sincronizadas con retraso + easing en alpha
Implementa sistema de sincronización elegante entre logos con efecto de "seguimiento" y fade suavizado para eliminar desincronización visual. Cambios principales: 1. **Animación sincronizada**: Ambos logos usan la MISMA animación - Eliminadas 4 variables independientes (logo1/logo2 × entry/exit) - Una sola variable `current_animation_` compartida - Misma animación para entrada y salida (simetría) 2. **Retraso de Logo 2**: 0.25 segundos detrás de Logo 1 - Logo 1 empieza en t=0.00s - Logo 2 empieza en t=0.25s - Efecto visual de "eco" o "seguimiento" 3. **Alpha independiente con retraso**: - `logo1_alpha_` y `logo2_alpha_` separados - Logo 2 aparece/desaparece más tarde visualmente 4. **Easing en alpha** (NUEVO): - Aplicado `easeInOutQuad()` al fade de alpha - Elimina problema de "logo deformado esperando a desvanecerse" - Sincronización visual perfecta entre animación y fade - Curva suave: lento al inicio, rápido en medio, lento al final Comportamiento resultante: FADE_IN: - t=0.00s: Logo 1 empieza (alpha con easing) - t=0.25s: Logo 2 empieza (alpha con easing + retraso) - t=0.50s: Logo 1 completamente visible - t=0.75s: Logo 2 completamente visible FADE_OUT: - t=0.00s: Logo 1 empieza a desaparecer (misma animación) - t=0.25s: Logo 2 empieza a desaparecer - t=0.50s: Logo 1 completamente invisible - t=0.75s: Logo 2 completamente invisible Archivos modificados: - source/defines.h: +APPLOGO_LOGO2_DELAY - source/app_logo.h: Reestructuración de variables de animación/alpha - source/app_logo.cpp: Implementación de retraso + easing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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<int>(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<int>(eased_prog1 * 255.0f);
|
||||
logo2_alpha_ = static_cast<int>(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<int>((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<int>((1.0f - eased_prog1) * 255.0f);
|
||||
logo2_alpha_ = static_cast<int>((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<Uint8>(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<Uint8>(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)
|
||||
|
||||
Reference in New Issue
Block a user