From 01d1ebd2a3ce4660265ff6623f3bde9493ff2ebe Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 11 Oct 2025 21:19:14 +0200 Subject: [PATCH] =?UTF-8?q?Refactor=20fase=208:=20Migrar=20l=C3=B3gica=20D?= =?UTF-8?q?EMO/LOGO=20a=20StateManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- source/engine.cpp | 205 +++++++++++++++++---------------- source/engine.h | 11 ++ source/state/state_manager.cpp | 193 ++++++++++++++++++++++++++++--- source/state/state_manager.h | 30 ++--- 4 files changed, 310 insertions(+), 129 deletions(-) diff --git a/source/engine.cpp b/source/engine.cpp index ee6779c..11a83d0 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -321,8 +321,8 @@ void Engine::update() { updateShape(); } - // Actualizar Modo DEMO (auto-play) - updateDemoMode(); + // Actualizar Modo DEMO/LOGO (delegado a StateManager) + state_manager_->update(delta_time_, shape_convergence_, active_shape_.get()); // Actualizar transiciones de temas (delegado a ThemeManager) theme_manager_->update(delta_time_); @@ -477,41 +477,42 @@ void Engine::handleZoomOut() { } } -// Modos de aplicación (DEMO/LOGO) +// Modos de aplicación (DEMO/LOGO) - Delegados a StateManager void Engine::toggleDemoMode() { - if (state_manager_->getCurrentMode() == AppMode::DEMO) { - // Ya estamos en DEMO → volver a SANDBOX - setState(AppMode::SANDBOX); + AppMode prev_mode = state_manager_->getCurrentMode(); + state_manager_->toggleDemoMode(current_screen_width_, current_screen_height_); + AppMode new_mode = state_manager_->getCurrentMode(); + + // Mostrar notificación según el modo resultante + if (new_mode == AppMode::SANDBOX && prev_mode != AppMode::SANDBOX) { showNotificationForAction("MODO SANDBOX"); - } else { - // Estamos en otro modo → ir a DEMO - setState(AppMode::DEMO); - randomizeOnDemoStart(false); + } else if (new_mode == AppMode::DEMO && prev_mode != AppMode::DEMO) { showNotificationForAction("MODO DEMO"); } } void Engine::toggleDemoLiteMode() { - if (state_manager_->getCurrentMode() == AppMode::DEMO_LITE) { - // Ya estamos en DEMO_LITE → volver a SANDBOX - setState(AppMode::SANDBOX); + AppMode prev_mode = state_manager_->getCurrentMode(); + state_manager_->toggleDemoLiteMode(current_screen_width_, current_screen_height_); + AppMode new_mode = state_manager_->getCurrentMode(); + + // Mostrar notificación según el modo resultante + if (new_mode == AppMode::SANDBOX && prev_mode != AppMode::SANDBOX) { showNotificationForAction("MODO SANDBOX"); - } else { - // Estamos en otro modo → ir a DEMO_LITE - setState(AppMode::DEMO_LITE); - randomizeOnDemoStart(true); + } else if (new_mode == AppMode::DEMO_LITE && prev_mode != AppMode::DEMO_LITE) { showNotificationForAction("MODO DEMO LITE"); } } void Engine::toggleLogoMode() { - if (state_manager_->getCurrentMode() == AppMode::LOGO) { - // Ya estamos en LOGO → volver a SANDBOX - exitLogoMode(false); + AppMode prev_mode = state_manager_->getCurrentMode(); + state_manager_->toggleLogoMode(current_screen_width_, current_screen_height_, scene_manager_->getBallCount()); + AppMode new_mode = state_manager_->getCurrentMode(); + + // Mostrar notificación según el modo resultante + if (new_mode == AppMode::SANDBOX && prev_mode != AppMode::SANDBOX) { showNotificationForAction("MODO SANDBOX"); - } else { - // Estamos en otro modo → ir a LOGO - enterLogoMode(false); + } else if (new_mode == AppMode::LOGO && prev_mode != AppMode::LOGO) { showNotificationForAction("MODO LOGO"); } } @@ -949,44 +950,14 @@ void Engine::updatePhysicalWindowSize() { } // ============================================================================ -// Sistema de gestión de estados (MANUAL/DEMO/DEMO_LITE/LOGO) +// CALLBACKS PARA STATEMANAGER - FASE 8 // ============================================================================ +// NOTA: Estos métodos son callbacks temporales para que StateManager pueda +// ejecutar acciones que requieren acceso a múltiples componentes del Engine. +// TODO FASE 9: Eliminar estos callbacks moviendo la lógica completa a StateManager -void Engine::setState(AppMode new_mode) { - // Delegar a StateManager pero mantener lógica de setup en Engine temporalmente - // TODO: Mover toda esta lógica a StateManager - - // Aplicar el nuevo modo a través de StateManager - state_manager_->setState(new_mode, current_screen_width_, current_screen_height_); - - // Configurar timer de demo según el modo - if (new_mode == AppMode::DEMO || new_mode == AppMode::DEMO_LITE || new_mode == AppMode::LOGO) { - demo_timer_ = 0.0f; - 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); - } -} - -// ============================================================================ -// Sistema de Modo DEMO (auto-play) -// ============================================================================ - -void Engine::updateDemoMode() { +// Callback para ejecutar acciones de LOGO MODE +void Engine::performLogoAction(bool logo_waiting_for_flip) { // Verificar si algún modo demo está activo (DEMO, DEMO_LITE o LOGO) if (state_manager_->getCurrentMode() == AppMode::SANDBOX) return; @@ -1130,13 +1101,13 @@ void Engine::updateDemoMode() { // No salir si el usuario entró manualmente con tecla K // Probabilidad de salir: 60% en cada acción → sale rápido (relación DEMO:LOGO = 6:1) if (!logo_entered_manually_ && rand() % 100 < 60) { - exitLogoMode(true); // Volver a DEMO/DEMO_LITE + state_manager_->exitLogoMode(true); // Volver a DEMO/DEMO_LITE } } // MODO DEMO/DEMO_LITE: Acciones normales else { bool is_lite = (state_manager_->getCurrentMode() == AppMode::DEMO_LITE); - performDemoAction(is_lite); + executeDemoAction(is_lite); // Resetear timer y calcular próximo intervalo aleatorio demo_timer_ = 0.0f; @@ -1150,7 +1121,8 @@ void Engine::updateDemoMode() { } } -void Engine::performDemoAction(bool is_lite) { +// Callback para StateManager - Ejecutar acción DEMO +void Engine::executeDemoAction(bool is_lite) { // ============================================ // SALTO AUTOMÁTICO A LOGO MODE (Easter Egg) // ============================================ @@ -1161,7 +1133,7 @@ void Engine::performDemoAction(bool is_lite) { theme_manager_->getCurrentThemeIndex() == 5) { // MONOCHROME // 10% probabilidad de saltar a Logo Mode if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE) { - enterLogoMode(true); // Entrar desde DEMO + state_manager_->enterLogoMode(true, current_screen_width_, current_screen_height_, scene_manager_->getBallCount()); return; } } @@ -1170,7 +1142,7 @@ void Engine::performDemoAction(bool is_lite) { if (static_cast(scene_manager_->getBallCount()) >= LOGO_MODE_MIN_BALLS) { // 15% probabilidad de saltar a Logo Mode if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO) { - enterLogoMode(true); // Entrar desde DEMO + state_manager_->enterLogoMode(true, current_screen_width_, current_screen_height_, scene_manager_->getBallCount()); return; } } @@ -1200,7 +1172,7 @@ void Engine::performDemoAction(bool is_lite) { // Toggle gravedad ON/OFF (20%) accumulated_weight += DEMO_LITE_WEIGHT_GRAVITY_TOGGLE; if (random_value < accumulated_weight) { - toggleGravityOnOff(); + executeToggleGravityOnOff(); return; } @@ -1243,7 +1215,7 @@ void Engine::performDemoAction(bool is_lite) { // Toggle gravedad ON/OFF (8%) accumulated_weight += DEMO_WEIGHT_GRAVITY_TOGGLE; if (random_value < accumulated_weight) { - toggleGravityOnOff(); + executeToggleGravityOnOff(); return; } @@ -1334,8 +1306,8 @@ void Engine::performDemoAction(bool is_lite) { } } -// Randomizar todo al iniciar modo DEMO -void Engine::randomizeOnDemoStart(bool is_lite) { +// Callback para StateManager - Randomizar estado al iniciar DEMO +void Engine::executeRandomizeOnDemoStart(bool is_lite) { // Si venimos de LOGO con PNG_SHAPE, cambiar figura obligatoriamente // PNG_SHAPE es exclusivo del modo LOGO y no debe aparecer en DEMO/DEMO_LITE if (current_shape_type_ == ShapeType::PNG_SHAPE) { @@ -1363,7 +1335,7 @@ void Engine::randomizeOnDemoStart(bool is_lite) { GravityDirection new_direction = static_cast(rand() % 4); scene_manager_->changeGravityDirection(new_direction); if (rand() % 2 == 0) { - toggleGravityOnOff(); // 50% probabilidad de desactivar gravedad + executeToggleGravityOnOff(); // 50% probabilidad de desactivar gravedad } } else { @@ -1409,13 +1381,13 @@ void Engine::randomizeOnDemoStart(bool is_lite) { GravityDirection new_direction = static_cast(rand() % 4); scene_manager_->changeGravityDirection(new_direction); if (rand() % 3 == 0) { // 33% probabilidad de desactivar gravedad - toggleGravityOnOff(); + executeToggleGravityOnOff(); } } } -// Toggle gravedad ON/OFF para todas las pelotas -void Engine::toggleGravityOnOff() { +// Callback para StateManager - Toggle gravedad ON/OFF para todas las pelotas +void Engine::executeToggleGravityOnOff() { // Alternar entre activar/desactivar gravedad bool first_ball_gravity_enabled = (!scene_manager_->hasBalls() || scene_manager_->getFirstBall()->getGravityForce() > 0.0f); @@ -1432,7 +1404,7 @@ void Engine::toggleGravityOnOff() { // SISTEMA DE MODO LOGO (Easter Egg - "Marca de Agua") // ============================================================================ -// Entrar al Modo Logo (manual con tecla K o automático desde DEMO) +// Método antiguo mantenido para código legacy de LOGO (será eliminado en Fase 9) void Engine::enterLogoMode(bool from_demo) { // Verificar mínimo de pelotas if (static_cast(scene_manager_->getBallCount()) < LOGO_MODE_MIN_BALLS) { @@ -1490,18 +1462,64 @@ void Engine::enterLogoMode(bool from_demo) { logo_target_flip_percentage_ = 0.0f; logo_current_flip_count_ = 0; - // Guardar si entrada fue manual (tecla K) o automática (desde DEMO) - logo_entered_manually_ = !from_demo; - - // Cambiar a modo LOGO (guarda previous_app_mode_ automáticamente) - setState(AppMode::LOGO); + // La configuración de estado se maneja en StateManager } -// Salir del Modo Logo (volver a estado anterior o salir de DEMO) -void Engine::exitLogoMode(bool return_to_demo) { - if (state_manager_->getCurrentMode() != AppMode::LOGO) return; +// Callbacks para StateManager - Solo configuración visual +void Engine::executeEnterLogoMode(size_t ball_count) { + // Verificar mínimo de pelotas + if (static_cast(ball_count) < LOGO_MODE_MIN_BALLS) { + // Ajustar a 5000 pelotas automáticamente + scene_manager_->changeScenario(5); // Escenario 5000 pelotas (índice 5 en BALL_COUNT_SCENARIOS) + } - // Restaurar estado previo + // Guardar estado previo (para restaurar al salir) + logo_previous_theme_ = theme_manager_->getCurrentThemeIndex(); + logo_previous_texture_index_ = current_texture_index_; + logo_previous_shape_scale_ = shape_scale_factor_; + + // Buscar índice de textura "small" + size_t small_index = current_texture_index_; // Por defecto mantener actual + for (size_t i = 0; i < texture_names_.size(); i++) { + if (texture_names_[i] == "small") { + small_index = i; + break; + } + } + + // Aplicar configuración fija del Modo Logo + if (small_index != current_texture_index_) { + current_texture_index_ = small_index; + texture_ = textures_[current_texture_index_]; + int new_size = texture_->getWidth(); + current_ball_size_ = new_size; + scene_manager_->updateBallTexture(texture_, new_size); + } + + // Cambiar a tema aleatorio entre: MONOCHROME, LAVENDER, CRIMSON, ESMERALDA + int logo_themes[] = {5, 6, 7, 8}; // MONOCHROME, LAVENDER, CRIMSON, ESMERALDA + int random_theme = logo_themes[rand() % 4]; + theme_manager_->switchToTheme(random_theme); + + // Establecer escala a 120% + shape_scale_factor_ = LOGO_MODE_SHAPE_SCALE; + clampShapeScale(); + + // Activar PNG_SHAPE (el logo) + activateShapeInternal(ShapeType::PNG_SHAPE); + + // Configurar PNG_SHAPE en modo LOGO (flip intervals más largos) + if (active_shape_) { + PNGShape* png_shape = dynamic_cast(active_shape_.get()); + if (png_shape) { + png_shape->setLogoMode(true); + png_shape->resetFlipCount(); // Resetear contador de flips + } + } +} + +void Engine::executeExitLogoMode() { + // Restaurar estado visual previo theme_manager_->switchToTheme(logo_previous_theme_); if (logo_previous_texture_index_ != current_texture_index_ && @@ -1525,23 +1543,12 @@ void Engine::exitLogoMode(bool return_to_demo) { } } - // Resetear flag de entrada manual - logo_entered_manually_ = false; - - if (!return_to_demo) { - // Salida manual (tecla K): volver a MANUAL - setState(AppMode::SANDBOX); - } else { - // Volver al modo previo (DEMO o DEMO_LITE) - setState(previous_app_mode_); - - // Si la figura activa es PNG_SHAPE, cambiar a otra figura aleatoria - if (current_shape_type_ == ShapeType::PNG_SHAPE) { - ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, - ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, - ShapeType::ICOSAHEDRON, ShapeType::ATOM}; - activateShapeInternal(shapes[rand() % 8]); - } + // Si la figura activa es PNG_SHAPE, cambiar a otra figura aleatoria + if (current_shape_type_ == ShapeType::PNG_SHAPE) { + ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, + ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, + ShapeType::ICOSAHEDRON, ShapeType::ATOM}; + activateShapeInternal(shapes[rand() % 8]); } } diff --git a/source/engine.h b/source/engine.h index 8f26eec..0619707 100644 --- a/source/engine.h +++ b/source/engine.h @@ -70,6 +70,17 @@ class Engine { void toggleDemoLiteMode(); void toggleLogoMode(); + // === Métodos públicos para StateManager (callbacks) === + // NOTA FASE 8: StateManager necesita llamar a Engine para ejecutar acciones + // que requieren acceso a múltiples componentes (SceneManager, ThemeManager, etc.) + // TODO FASE 9: Mover lógica completa a StateManager eliminando estos callbacks + void performLogoAction(bool logo_waiting_for_flip); + void executeDemoAction(bool is_lite); + void executeRandomizeOnDemoStart(bool is_lite); + void executeToggleGravityOnOff(); + void executeEnterLogoMode(size_t ball_count); + void executeExitLogoMode(); + private: // === Componentes del sistema (Composición) === std::unique_ptr input_handler_; // Manejo de entradas SDL diff --git a/source/state/state_manager.cpp b/source/state/state_manager.cpp index f36ca35..92c4dd5 100644 --- a/source/state/state_manager.cpp +++ b/source/state/state_manager.cpp @@ -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(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_; + } } diff --git a/source/state/state_manager.h b/source/state/state_manager.h index d8ae46f..f9a66a9 100644 --- a/source/state/state_manager.h +++ b/source/state/state_manager.h @@ -124,6 +124,21 @@ class StateManager { */ void setLogoPreviousState(int theme, size_t texture_index, float shape_scale); + /** + * @brief Entra al modo LOGO (público para permitir salto automático desde DEMO) + * @param from_demo true si viene desde DEMO, false si es manual + * @param current_screen_width Ancho de pantalla + * @param current_screen_height Alto de pantalla + * @param ball_count Número de bolas + */ + void enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count); + + /** + * @brief Sale del modo LOGO (público para permitir salida manual) + * @param return_to_demo true si debe volver a DEMO/DEMO_LITE + */ + void exitLogoMode(bool return_to_demo); + private: // === Referencia al Engine (callback) === Engine* engine_; @@ -173,19 +188,4 @@ class StateManager { * @brief Toggle de gravedad ON/OFF (para DEMO) */ void toggleGravityOnOff(); - - /** - * @brief Entra al modo LOGO - * @param from_demo true si viene desde DEMO, false si es manual - * @param current_screen_width Ancho de pantalla - * @param current_screen_height Alto de pantalla - * @param ball_count Número de bolas - */ - void enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count); - - /** - * @brief Sale del modo LOGO - * @param return_to_demo true si debe volver a DEMO/DEMO_LITE - */ - void exitLogoMode(bool return_to_demo); };