Refactor fase 8: Migrar lógica DEMO/LOGO a StateManager

Implementación:
- StateManager::update() ahora maneja timers y triggers DEMO/LOGO
- Detección de flips de PNG_SHAPE migrada completamente
- Callbacks temporales en Engine para acciones complejas
- enterLogoMode() y exitLogoMode() públicos para transiciones automáticas
- Toggle methods en Engine delegados a StateManager

Callbacks implementados (temporal para Fase 9):
- Engine::performLogoAction()
- Engine::executeDemoAction()
- Engine::executeRandomizeOnDemoStart()
- Engine::executeToggleGravityOnOff()
- Engine::executeEnterLogoMode()
- Engine::executeExitLogoMode()

TODO Fase 9:
- Eliminar callbacks moviendo lógica completa a StateManager
- Limpiar duplicación de estado entre Engine y StateManager

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-11 21:19:14 +02:00
parent 83ea03fda3
commit 01d1ebd2a3
4 changed files with 310 additions and 129 deletions

View File

@@ -38,15 +38,84 @@ void StateManager::setLogoPreviousState(int theme, size_t texture_index, float s
logo_previous_shape_scale_ = shape_scale;
}
// TODO: Implementar métodos completos
// Por ahora, stubs vacíos para que compile
// ===========================================================================
// ACTUALIZACIÓN DE ESTADOS - Migrado desde Engine::updateDemoMode()
// ===========================================================================
void StateManager::update(float delta_time, float shape_convergence, Shape* active_shape) {
// Delegar a Engine temporalmente - La lógica compleja queda en Engine por ahora
// Este es un wrapper que permite refactorizar gradualmente
if (engine_) {
// Engine mantiene la implementación de updateDemoMode()
// StateManager solo coordina el estado
// Verificar si algún modo demo está activo (DEMO, DEMO_LITE o LOGO)
if (current_app_mode_ == AppMode::SANDBOX) return;
// Actualizar timer
demo_timer_ += delta_time;
// Determinar si es hora de ejecutar acción (depende del modo)
bool should_trigger = false;
if (current_app_mode_ == AppMode::LOGO) {
// LOGO MODE: Dos caminos posibles
if (logo_waiting_for_flip_) {
// CAMINO B: Esperando a que ocurran flips
// Obtener referencia a PNGShape si está activa
PNGShape* png_shape = dynamic_cast<PNGShape*>(active_shape);
if (png_shape) {
int current_flip_count = png_shape->getFlipCount();
// Detectar nuevo flip completado
if (current_flip_count > logo_current_flip_count_) {
logo_current_flip_count_ = current_flip_count;
}
// Si estamos EN o DESPUÉS del flip objetivo
// +1 porque queremos actuar DURANTE el flip N, no después de completarlo
if (logo_current_flip_count_ + 1 >= logo_target_flip_number_) {
// Monitorear progreso del flip actual
if (png_shape->isFlipping()) {
float flip_progress = png_shape->getFlipProgress();
if (flip_progress >= logo_target_flip_percentage_) {
should_trigger = true; // ¡Trigger durante el flip!
}
}
}
}
} else {
// CAMINO A: Esperar convergencia + tiempo (comportamiento original)
bool min_time_reached = demo_timer_ >= logo_min_time_;
bool max_time_reached = demo_timer_ >= logo_max_time_;
bool convergence_ok = shape_convergence >= logo_convergence_threshold_;
should_trigger = (min_time_reached && convergence_ok) || max_time_reached;
}
} else {
// DEMO/DEMO_LITE: Timer simple como antes
should_trigger = demo_timer_ >= demo_next_action_time_;
}
// Si es hora de ejecutar acción
if (should_trigger) {
// MODO LOGO: Sistema de acciones variadas con gravedad dinámica
if (current_app_mode_ == AppMode::LOGO) {
// Llamar a Engine para ejecutar acciones de LOGO
// TODO FASE 9: Mover lógica de acciones LOGO desde Engine a StateManager
if (engine_) {
engine_->performLogoAction(logo_waiting_for_flip_);
}
}
// MODO DEMO/DEMO_LITE: Acciones normales
else {
bool is_lite = (current_app_mode_ == AppMode::DEMO_LITE);
performDemoAction(is_lite);
// Resetear timer y calcular próximo intervalo aleatorio
demo_timer_ = 0.0f;
// Usar intervalos diferentes según modo
float interval_min = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
float interval_max = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
float interval_range = interval_max - interval_min;
demo_next_action_time_ = interval_min + (rand() % 1000) / 1000.0f * interval_range;
}
}
}
@@ -65,6 +134,27 @@ void StateManager::setState(AppMode new_mode, int current_screen_width, int curr
// Resetear timer al cambiar modo
demo_timer_ = 0.0f;
// Configurar timer de demo según el modo
if (new_mode == AppMode::DEMO || new_mode == AppMode::DEMO_LITE || new_mode == AppMode::LOGO) {
float min_interval, max_interval;
if (new_mode == AppMode::LOGO) {
// Escalar tiempos con resolución (720p como base)
float resolution_scale = current_screen_height / 720.0f;
logo_min_time_ = LOGO_ACTION_INTERVAL_MIN * resolution_scale;
logo_max_time_ = LOGO_ACTION_INTERVAL_MAX * resolution_scale;
min_interval = logo_min_time_;
max_interval = logo_max_time_;
} else {
bool is_lite = (new_mode == AppMode::DEMO_LITE);
min_interval = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
max_interval = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
}
demo_next_action_time_ = min_interval + (rand() % 1000) / 1000.0f * (max_interval - min_interval);
}
}
void StateManager::toggleDemoMode(int current_screen_width, int current_screen_height) {
@@ -72,6 +162,7 @@ void StateManager::toggleDemoMode(int current_screen_width, int current_screen_h
setState(AppMode::SANDBOX, current_screen_width, current_screen_height);
} else {
setState(AppMode::DEMO, current_screen_width, current_screen_height);
randomizeOnDemoStart(false); // Randomizar estado al entrar
}
}
@@ -80,34 +171,106 @@ void StateManager::toggleDemoLiteMode(int current_screen_width, int current_scre
setState(AppMode::SANDBOX, current_screen_width, current_screen_height);
} else {
setState(AppMode::DEMO_LITE, current_screen_width, current_screen_height);
randomizeOnDemoStart(true); // Randomizar estado al entrar
}
}
void StateManager::toggleLogoMode(int current_screen_width, int current_screen_height, size_t ball_count) {
if (current_app_mode_ == AppMode::LOGO) {
setState(AppMode::SANDBOX, current_screen_width, current_screen_height);
exitLogoMode(false); // Salir de LOGO manualmente
} else {
setState(AppMode::LOGO, current_screen_width, current_screen_height);
logo_entered_manually_ = true;
enterLogoMode(false, current_screen_width, current_screen_height, ball_count); // Entrar manualmente
}
}
// ===========================================================================
// ACCIONES DE DEMO - Migrado desde Engine::performDemoAction()
// ===========================================================================
void StateManager::performDemoAction(bool is_lite) {
// TODO: Migrar performDemoAction()
// ============================================
// SALTO AUTOMÁTICO A LOGO MODE (Easter Egg)
// ============================================
// Obtener información necesaria desde Engine via callbacks
// (En el futuro, se podría pasar como parámetros al método)
if (!engine_) return;
// TODO FASE 9: Eliminar callbacks a Engine y pasar parámetros necesarios
// Por ahora, delegar las acciones DEMO completas a Engine
// ya que necesitan acceso a múltiples componentes (SceneManager, ThemeManager, etc.)
engine_->executeDemoAction(is_lite);
}
// ===========================================================================
// RANDOMIZACIÓN AL INICIAR DEMO - Migrado desde Engine::randomizeOnDemoStart()
// ===========================================================================
void StateManager::randomizeOnDemoStart(bool is_lite) {
// TODO: Migrar randomizeOnDemoStart()
// Delegar a Engine para randomización completa
// TODO FASE 9: Implementar lógica completa aquí
if (engine_) {
engine_->executeRandomizeOnDemoStart(is_lite);
}
}
// ===========================================================================
// TOGGLE GRAVEDAD (para DEMO) - Migrado desde Engine::toggleGravityOnOff()
// ===========================================================================
void StateManager::toggleGravityOnOff() {
// TODO: Migrar toggleGravityOnOff()
// Delegar a Engine temporalmente
if (engine_) {
engine_->executeToggleGravityOnOff();
}
}
// ===========================================================================
// ENTRAR AL MODO LOGO - Migrado desde Engine::enterLogoMode()
// ===========================================================================
void StateManager::enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count) {
// TODO: Migrar enterLogoMode()
// Guardar si entrada fue manual (tecla K) o automática (desde DEMO)
logo_entered_manually_ = !from_demo;
// Resetear variables de espera de flips
logo_waiting_for_flip_ = false;
logo_target_flip_number_ = 0;
logo_target_flip_percentage_ = 0.0f;
logo_current_flip_count_ = 0;
// Cambiar a modo LOGO (guarda previous_app_mode_ automáticamente)
setState(AppMode::LOGO, current_screen_width, current_screen_height);
// Delegar configuración visual a Engine
// TODO FASE 9: Mover configuración completa aquí
if (engine_) {
engine_->executeEnterLogoMode(ball_count);
}
}
// ===========================================================================
// SALIR DEL MODO LOGO - Migrado desde Engine::exitLogoMode()
// ===========================================================================
void StateManager::exitLogoMode(bool return_to_demo) {
// TODO: Migrar exitLogoMode()
if (current_app_mode_ != AppMode::LOGO) return;
// Resetear flag de entrada manual
logo_entered_manually_ = false;
// Delegar restauración visual a Engine
// TODO FASE 9: Mover lógica completa aquí
if (engine_) {
engine_->executeExitLogoMode();
}
if (!return_to_demo) {
// Salida manual (tecla K): volver a SANDBOX
setState(AppMode::SANDBOX, 0, 0);
} else {
// Volver al modo previo (DEMO o DEMO_LITE)
current_app_mode_ = previous_app_mode_;
}
}