Files
vibe3_physics/source/state/state_manager.cpp
Sergio Valor a9d7b66e83 Refactorizar estilo del proyecto: .h → .hpp, #pragma once, includes desde raíz
Modernizar convenciones de código C++ aplicando las siguientes directivas:

## Cambios principales

**1. Renombrar headers (.h → .hpp)**
- 36 archivos renombrados a extensión .hpp (estándar C++)
- Mantenidos como .h: stb_image.h, stb_image_resize2.h (librerías C externas)

**2. Modernizar include guards (#ifndef → #pragma once)**
- resource_manager.hpp: #ifndef RESOURCE_MANAGER_H → #pragma once
- resource_pack.hpp: #ifndef RESOURCE_PACK_H → #pragma once
- spatial_grid.hpp: #ifndef SPATIAL_GRID_H → #pragma once

**3. Sistema de includes desde raíz del proyecto**
- CMakeLists.txt: añadido include_directories(${CMAKE_SOURCE_DIR}/source)
- Eliminadas rutas relativas (../) en todos los includes
- Includes ahora usan rutas absolutas desde source/

**Antes:**
```cpp
#include "../defines.h"
#include "../text/textrenderer.h"
```

**Ahora:**
```cpp
#include "defines.hpp"
#include "text/textrenderer.hpp"
```

## Archivos afectados

- 1 archivo CMakeLists.txt modificado
- 36 archivos renombrados (.h → .hpp)
- 32 archivos .cpp actualizados (includes)
- 36 archivos .hpp actualizados (includes + guards)
- 1 archivo tools/ actualizado

**Total: 70 archivos modificados**

## Verificación

 Proyecto compila sin errores
 Todas las rutas de includes correctas
 Include guards modernizados
 Librerías externas C mantienen extensión .h

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 13:49:58 +02:00

277 lines
11 KiB
C++

#include "state_manager.hpp"
#include <cstdlib> // for rand
#include "defines.hpp" // for constantes DEMO/LOGO
#include "engine.hpp" // for Engine (callbacks)
#include "shapes/png_shape.hpp" // for PNGShape flip detection
StateManager::StateManager()
: engine_(nullptr)
, current_app_mode_(AppMode::SANDBOX)
, previous_app_mode_(AppMode::SANDBOX)
, demo_timer_(0.0f)
, demo_next_action_time_(0.0f)
, logo_convergence_threshold_(0.90f)
, logo_min_time_(3.0f)
, logo_max_time_(5.0f)
, logo_waiting_for_flip_(false)
, logo_target_flip_number_(0)
, logo_target_flip_percentage_(0.0f)
, logo_current_flip_count_(0)
, logo_entered_manually_(false)
, logo_previous_theme_(0)
, logo_previous_texture_index_(0)
, logo_previous_shape_scale_(1.0f) {
}
StateManager::~StateManager() {
}
void StateManager::initialize(Engine* engine) {
engine_ = engine;
}
void StateManager::setLogoPreviousState(int theme, size_t texture_index, float shape_scale) {
logo_previous_theme_ = theme;
logo_previous_texture_index_ = texture_index;
logo_previous_shape_scale_ = shape_scale;
}
// ===========================================================================
// ACTUALIZACIÓN DE ESTADOS - Migrado desde Engine::updateDemoMode()
// ===========================================================================
void StateManager::update(float delta_time, float shape_convergence, Shape* active_shape) {
// 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;
}
}
}
void StateManager::setState(AppMode new_mode, int current_screen_width, int current_screen_height) {
if (current_app_mode_ == new_mode) return;
if (current_app_mode_ == AppMode::LOGO && new_mode != AppMode::LOGO) {
previous_app_mode_ = new_mode;
}
if (new_mode == AppMode::LOGO) {
previous_app_mode_ = current_app_mode_;
}
current_app_mode_ = new_mode;
// 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) {
if (current_app_mode_ == AppMode::DEMO) {
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
}
}
void StateManager::toggleDemoLiteMode(int current_screen_width, int current_screen_height) {
if (current_app_mode_ == AppMode::DEMO_LITE) {
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) {
exitLogoMode(false); // Salir de LOGO manualmente
} else {
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) {
// ============================================
// 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) {
// 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() {
// 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) {
// 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) {
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_;
}
}