refactor(bloques2-5): auditoria de codi - limpieza i arquitectura
Bloque 2: eliminar codi mort comentat (shape_manager, engine)
Bloque 3: Engine shape methods com thin wrappers a ShapeManager;
eliminar estat duplicat de shapes en Engine
Bloque 4: encapsular getBallsMutable() amb helpers a SceneManager
(enableShapeAttractionAll, resetDepthScalesAll)
Bloque 5: StateManager Phase 9 - tota la logica DEMO/LOGO
implementada directament amb refs a SceneManager,
ThemeManager i ShapeManager; eliminar callbacks a Engine.
Acoplament Engine<->StateManager passa a unidireccional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,21 @@
|
||||
#include "state_manager.hpp"
|
||||
|
||||
#include <cstdlib> // for rand
|
||||
#include <algorithm> // for std::min
|
||||
#include <cstdlib> // for rand
|
||||
#include <vector> // for std::vector
|
||||
|
||||
#include "defines.hpp" // for constantes DEMO/LOGO
|
||||
#include "engine.hpp" // for Engine (callbacks)
|
||||
#include "shapes/png_shape.hpp" // for PNGShape flip detection
|
||||
#include "defines.hpp" // for constantes DEMO/LOGO
|
||||
#include "engine.hpp" // for Engine (enter/exitShapeMode, texture)
|
||||
#include "scene/scene_manager.hpp" // for SceneManager
|
||||
#include "shapes_mgr/shape_manager.hpp" // for ShapeManager
|
||||
#include "shapes/png_shape.hpp" // for PNGShape flip detection
|
||||
#include "theme_manager.hpp" // for ThemeManager
|
||||
|
||||
StateManager::StateManager()
|
||||
: engine_(nullptr)
|
||||
, scene_mgr_(nullptr)
|
||||
, theme_mgr_(nullptr)
|
||||
, shape_mgr_(nullptr)
|
||||
, current_app_mode_(AppMode::SANDBOX)
|
||||
, previous_app_mode_(AppMode::SANDBOX)
|
||||
, demo_timer_(0.0f)
|
||||
@@ -28,8 +36,11 @@ StateManager::StateManager()
|
||||
StateManager::~StateManager() {
|
||||
}
|
||||
|
||||
void StateManager::initialize(Engine* engine) {
|
||||
void StateManager::initialize(Engine* engine, SceneManager* scene_mgr, ThemeManager* theme_mgr, ShapeManager* shape_mgr) {
|
||||
engine_ = engine;
|
||||
scene_mgr_ = scene_mgr;
|
||||
theme_mgr_ = theme_mgr;
|
||||
shape_mgr_ = shape_mgr;
|
||||
}
|
||||
|
||||
void StateManager::setLogoPreviousState(int theme, size_t texture_index, float shape_scale) {
|
||||
@@ -39,48 +50,39 @@ void StateManager::setLogoPreviousState(int theme, size_t texture_index, float s
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// ACTUALIZACIÓN DE ESTADOS - Migrado desde Engine::updateDemoMode()
|
||||
// ACTUALIZACIÓN DE ESTADOS
|
||||
// ===========================================================================
|
||||
|
||||
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!
|
||||
should_trigger = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CAMINO A: Esperar convergencia + tiempo (comportamiento original)
|
||||
// CAMINO A: Esperar convergencia + tiempo
|
||||
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_;
|
||||
@@ -88,34 +90,98 @@ void StateManager::update(float delta_time, float shape_convergence, Shape* acti
|
||||
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_);
|
||||
if (!should_trigger) return;
|
||||
|
||||
if (current_app_mode_ == AppMode::LOGO) {
|
||||
// LOGO MODE: Sistema de acciones variadas con gravedad dinámica
|
||||
int action = rand() % 100;
|
||||
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
// Logo quieto (formado) → Decidir camino a seguir
|
||||
if (logo_waiting_for_flip_) {
|
||||
// Ya estábamos esperando flips → hacer el cambio SHAPE → PHYSICS
|
||||
if (action < 50) {
|
||||
engine_->exitShapeMode(true); // Con gravedad ON
|
||||
} else {
|
||||
engine_->exitShapeMode(false); // Con gravedad OFF
|
||||
}
|
||||
|
||||
logo_waiting_for_flip_ = false;
|
||||
logo_current_flip_count_ = 0;
|
||||
|
||||
demo_timer_ = 0.0f;
|
||||
float interval_range = logo_max_time_ - logo_min_time_;
|
||||
demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
|
||||
} else if (rand() % 100 < LOGO_FLIP_WAIT_PROBABILITY) {
|
||||
// CAMINO B (50%): Esperar flips
|
||||
logo_waiting_for_flip_ = true;
|
||||
logo_target_flip_number_ = LOGO_FLIP_WAIT_MIN + rand() % (LOGO_FLIP_WAIT_MAX - LOGO_FLIP_WAIT_MIN + 1);
|
||||
logo_target_flip_percentage_ = LOGO_FLIP_TRIGGER_MIN + (rand() % 1000) / 1000.0f * (LOGO_FLIP_TRIGGER_MAX - LOGO_FLIP_TRIGGER_MIN);
|
||||
logo_current_flip_count_ = 0;
|
||||
|
||||
PNGShape* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
|
||||
if (png_shape) {
|
||||
png_shape->resetFlipCount();
|
||||
}
|
||||
// No hacer nada más — esperar a que ocurran los flips
|
||||
} else {
|
||||
// CAMINO A (50%): Cambio inmediato
|
||||
if (action < 50) {
|
||||
engine_->exitShapeMode(true); // SHAPE → PHYSICS con gravedad ON
|
||||
} else {
|
||||
engine_->exitShapeMode(false); // SHAPE → PHYSICS con gravedad OFF
|
||||
}
|
||||
|
||||
logo_waiting_for_flip_ = false;
|
||||
logo_current_flip_count_ = 0;
|
||||
|
||||
demo_timer_ = 0.0f;
|
||||
float interval_range = logo_max_time_ - logo_min_time_;
|
||||
demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
|
||||
}
|
||||
} else {
|
||||
// Logo animado (PHYSICS) → 4 opciones
|
||||
if (action < 50) {
|
||||
// 50%: PHYSICS → SHAPE (reconstruir logo)
|
||||
engine_->exitShapeMode(false); // toggleShapeMode: PHYSICS → SHAPE con last_type
|
||||
|
||||
logo_waiting_for_flip_ = false;
|
||||
logo_current_flip_count_ = 0;
|
||||
} else if (action < 68) {
|
||||
// 18%: Forzar gravedad ON
|
||||
scene_mgr_->forceBallsGravityOn();
|
||||
} else if (action < 84) {
|
||||
// 16%: Forzar gravedad OFF
|
||||
scene_mgr_->forceBallsGravityOff();
|
||||
} else {
|
||||
// 16%: Cambiar dirección de gravedad
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_mgr_->changeGravityDirection(new_direction);
|
||||
scene_mgr_->forceBallsGravityOn();
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
float interval_range = logo_max_time_ - logo_min_time_;
|
||||
demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
|
||||
}
|
||||
|
||||
// Salir automáticamente si la entrada fue automática (desde DEMO)
|
||||
if (!logo_entered_manually_ && rand() % 100 < 60) {
|
||||
exitLogoMode(true); // Volver a DEMO/DEMO_LITE
|
||||
}
|
||||
} else {
|
||||
// DEMO/DEMO_LITE: Acciones normales
|
||||
bool is_lite = (current_app_mode_ == AppMode::DEMO_LITE);
|
||||
performDemoAction(is_lite);
|
||||
|
||||
demo_timer_ = 0.0f;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,15 +198,12 @@ void StateManager::setState(AppMode new_mode, int current_screen_width, int curr
|
||||
|
||||
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;
|
||||
@@ -162,7 +225,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
|
||||
randomizeOnDemoStart(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,70 +234,319 @@ 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
|
||||
randomizeOnDemoStart(true);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
exitLogoMode(false);
|
||||
} else {
|
||||
enterLogoMode(false, current_screen_width, current_screen_height, ball_count); // Entrar manualmente
|
||||
enterLogoMode(false, current_screen_width, current_screen_height, ball_count);
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// ACCIONES DE DEMO - Migrado desde Engine::performDemoAction()
|
||||
// ACCIONES DE DEMO
|
||||
// ===========================================================================
|
||||
|
||||
void StateManager::performDemoAction(bool is_lite) {
|
||||
if (!engine_ || !scene_mgr_ || !theme_mgr_ || !shape_mgr_) return;
|
||||
|
||||
// ============================================
|
||||
// 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;
|
||||
if (is_lite) {
|
||||
if (static_cast<int>(scene_mgr_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX] &&
|
||||
theme_mgr_->getCurrentThemeIndex() == 5) { // MONOCHROME
|
||||
if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE) {
|
||||
enterLogoMode(true, 0, 0, scene_mgr_->getBallCount());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (static_cast<int>(scene_mgr_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX]) {
|
||||
if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO) {
|
||||
enterLogoMode(true, 0, 0, scene_mgr_->getBallCount());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO FASE 9: Eliminar callbacks a Engine y pasar parámetros necesarios
|
||||
// ============================================
|
||||
// ACCIONES NORMALES DE DEMO/DEMO_LITE
|
||||
// ============================================
|
||||
|
||||
// Por ahora, delegar las acciones DEMO completas a Engine
|
||||
// ya que necesitan acceso a múltiples componentes (SceneManager, ThemeManager, etc.)
|
||||
engine_->executeDemoAction(is_lite);
|
||||
int TOTAL_WEIGHT;
|
||||
int random_value;
|
||||
int accumulated_weight = 0;
|
||||
|
||||
if (is_lite) {
|
||||
TOTAL_WEIGHT = DEMO_LITE_WEIGHT_GRAVITY_DIR + DEMO_LITE_WEIGHT_GRAVITY_TOGGLE + DEMO_LITE_WEIGHT_SHAPE + DEMO_LITE_WEIGHT_TOGGLE_PHYSICS + DEMO_LITE_WEIGHT_IMPULSE;
|
||||
random_value = rand() % TOTAL_WEIGHT;
|
||||
|
||||
// Cambiar dirección gravedad (25%)
|
||||
accumulated_weight += DEMO_LITE_WEIGHT_GRAVITY_DIR;
|
||||
if (random_value < accumulated_weight) {
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_mgr_->changeGravityDirection(new_direction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle gravedad ON/OFF (20%)
|
||||
accumulated_weight += DEMO_LITE_WEIGHT_GRAVITY_TOGGLE;
|
||||
if (random_value < accumulated_weight) {
|
||||
toggleGravityOnOff();
|
||||
return;
|
||||
}
|
||||
|
||||
// Activar figura 3D (25%) - PNG_SHAPE excluido
|
||||
accumulated_weight += DEMO_LITE_WEIGHT_SHAPE;
|
||||
if (random_value < accumulated_weight) {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
engine_->enterShapeMode(shapes[rand() % 8]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle física ↔ figura (20%)
|
||||
accumulated_weight += DEMO_LITE_WEIGHT_TOGGLE_PHYSICS;
|
||||
if (random_value < accumulated_weight) {
|
||||
engine_->exitShapeMode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Aplicar impulso (10%)
|
||||
accumulated_weight += DEMO_LITE_WEIGHT_IMPULSE;
|
||||
if (random_value < accumulated_weight) {
|
||||
scene_mgr_->pushBallsAwayFromGravity();
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
TOTAL_WEIGHT = DEMO_WEIGHT_GRAVITY_DIR + DEMO_WEIGHT_GRAVITY_TOGGLE + DEMO_WEIGHT_SHAPE + DEMO_WEIGHT_TOGGLE_PHYSICS + DEMO_WEIGHT_REGENERATE_SHAPE + DEMO_WEIGHT_THEME + DEMO_WEIGHT_SCENARIO + DEMO_WEIGHT_IMPULSE + DEMO_WEIGHT_DEPTH_ZOOM + DEMO_WEIGHT_SHAPE_SCALE + DEMO_WEIGHT_SPRITE;
|
||||
random_value = rand() % TOTAL_WEIGHT;
|
||||
|
||||
// Cambiar dirección gravedad (10%)
|
||||
accumulated_weight += DEMO_WEIGHT_GRAVITY_DIR;
|
||||
if (random_value < accumulated_weight) {
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_mgr_->changeGravityDirection(new_direction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle gravedad ON/OFF (8%)
|
||||
accumulated_weight += DEMO_WEIGHT_GRAVITY_TOGGLE;
|
||||
if (random_value < accumulated_weight) {
|
||||
toggleGravityOnOff();
|
||||
return;
|
||||
}
|
||||
|
||||
// Activar figura 3D (20%) - PNG_SHAPE excluido
|
||||
accumulated_weight += DEMO_WEIGHT_SHAPE;
|
||||
if (random_value < accumulated_weight) {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
engine_->enterShapeMode(shapes[rand() % 8]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle física ↔ figura (12%)
|
||||
accumulated_weight += DEMO_WEIGHT_TOGGLE_PHYSICS;
|
||||
if (random_value < accumulated_weight) {
|
||||
engine_->exitShapeMode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-generar misma figura (8%)
|
||||
accumulated_weight += DEMO_WEIGHT_REGENERATE_SHAPE;
|
||||
if (random_value < accumulated_weight) {
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
shape_mgr_->generateShape();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Cambiar tema (15%)
|
||||
accumulated_weight += DEMO_WEIGHT_THEME;
|
||||
if (random_value < accumulated_weight) {
|
||||
theme_mgr_->switchToTheme(rand() % 15);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cambiar escenario (10%)
|
||||
accumulated_weight += DEMO_WEIGHT_SCENARIO;
|
||||
if (random_value < accumulated_weight) {
|
||||
int auto_max = std::min(engine_->getMaxAutoScenario(), DEMO_AUTO_MAX_SCENARIO);
|
||||
std::vector<int> candidates;
|
||||
for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i)
|
||||
candidates.push_back(i);
|
||||
if (engine_->isCustomScenarioEnabled() && engine_->isCustomAutoAvailable())
|
||||
candidates.push_back(CUSTOM_SCENARIO_IDX);
|
||||
int new_scenario = candidates[rand() % candidates.size()];
|
||||
SimulationMode current_sim_mode = shape_mgr_->getCurrentMode();
|
||||
scene_mgr_->changeScenario(new_scenario, current_sim_mode);
|
||||
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
shape_mgr_->generateShape();
|
||||
scene_mgr_->enableShapeAttractionAll(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Aplicar impulso (10%)
|
||||
accumulated_weight += DEMO_WEIGHT_IMPULSE;
|
||||
if (random_value < accumulated_weight) {
|
||||
scene_mgr_->pushBallsAwayFromGravity();
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle profundidad (3%)
|
||||
accumulated_weight += DEMO_WEIGHT_DEPTH_ZOOM;
|
||||
if (random_value < accumulated_weight) {
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
shape_mgr_->setDepthZoomEnabled(!shape_mgr_->isDepthZoomEnabled());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Cambiar escala de figura (2%)
|
||||
accumulated_weight += DEMO_WEIGHT_SHAPE_SCALE;
|
||||
if (random_value < accumulated_weight) {
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
int scale_action = rand() % 3;
|
||||
if (scale_action == 0) {
|
||||
shape_mgr_->setShapeScaleFactor(shape_mgr_->getShapeScaleFactor() + SHAPE_SCALE_STEP);
|
||||
} else if (scale_action == 1) {
|
||||
shape_mgr_->setShapeScaleFactor(shape_mgr_->getShapeScaleFactor() - SHAPE_SCALE_STEP);
|
||||
} else {
|
||||
shape_mgr_->setShapeScaleFactor(SHAPE_SCALE_DEFAULT);
|
||||
}
|
||||
shape_mgr_->generateShape();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Cambiar sprite (2%)
|
||||
accumulated_weight += DEMO_WEIGHT_SPRITE;
|
||||
if (random_value < accumulated_weight) {
|
||||
engine_->switchTextureSilent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// RANDOMIZACIÓN AL INICIAR DEMO - Migrado desde Engine::randomizeOnDemoStart()
|
||||
// RANDOMIZACIÓN AL INICIAR DEMO
|
||||
// ===========================================================================
|
||||
|
||||
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);
|
||||
if (!engine_ || !scene_mgr_ || !theme_mgr_ || !shape_mgr_) return;
|
||||
|
||||
// Si venimos de LOGO con PNG_SHAPE, cambiar figura obligatoriamente
|
||||
if (shape_mgr_->getCurrentShapeType() == ShapeType::PNG_SHAPE) {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX,
|
||||
ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER,
|
||||
ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
engine_->enterShapeMode(shapes[rand() % 8]);
|
||||
}
|
||||
|
||||
if (is_lite) {
|
||||
// DEMO LITE: Solo randomizar física/figura + gravedad
|
||||
if (rand() % 2 == 0) {
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
engine_->exitShapeMode(false);
|
||||
}
|
||||
} else {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
engine_->enterShapeMode(shapes[rand() % 8]);
|
||||
}
|
||||
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_mgr_->changeGravityDirection(new_direction);
|
||||
if (rand() % 2 == 0) {
|
||||
toggleGravityOnOff();
|
||||
}
|
||||
|
||||
} else {
|
||||
// DEMO COMPLETO: Randomizar TODO
|
||||
|
||||
// 1. Física o Figura
|
||||
if (rand() % 2 == 0) {
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
engine_->exitShapeMode(false);
|
||||
}
|
||||
} else {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
ShapeType selected_shape = shapes[rand() % 8];
|
||||
|
||||
// Randomizar profundidad y escala ANTES de activar la figura
|
||||
if (rand() % 2 == 0) {
|
||||
shape_mgr_->setDepthZoomEnabled(!shape_mgr_->isDepthZoomEnabled());
|
||||
}
|
||||
shape_mgr_->setShapeScaleFactor(0.5f + (rand() % 1500) / 1000.0f);
|
||||
|
||||
engine_->enterShapeMode(selected_shape);
|
||||
}
|
||||
|
||||
// 2. Escenario
|
||||
int auto_max = std::min(engine_->getMaxAutoScenario(), DEMO_AUTO_MAX_SCENARIO);
|
||||
std::vector<int> candidates;
|
||||
for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i)
|
||||
candidates.push_back(i);
|
||||
if (engine_->isCustomScenarioEnabled() && engine_->isCustomAutoAvailable())
|
||||
candidates.push_back(CUSTOM_SCENARIO_IDX);
|
||||
int new_scenario = candidates[rand() % candidates.size()];
|
||||
SimulationMode current_sim_mode = shape_mgr_->getCurrentMode();
|
||||
scene_mgr_->changeScenario(new_scenario, current_sim_mode);
|
||||
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
shape_mgr_->generateShape();
|
||||
scene_mgr_->enableShapeAttractionAll(true);
|
||||
}
|
||||
|
||||
// 3. Tema
|
||||
theme_mgr_->switchToTheme(rand() % 15);
|
||||
|
||||
// 4. Sprite
|
||||
if (rand() % 2 == 0) {
|
||||
engine_->switchTextureSilent();
|
||||
}
|
||||
|
||||
// 5. Gravedad
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_mgr_->changeGravityDirection(new_direction);
|
||||
if (rand() % 3 == 0) {
|
||||
toggleGravityOnOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// TOGGLE GRAVEDAD (para DEMO) - Migrado desde Engine::toggleGravityOnOff()
|
||||
// TOGGLE GRAVEDAD (para DEMO)
|
||||
// ===========================================================================
|
||||
|
||||
void StateManager::toggleGravityOnOff() {
|
||||
// Delegar a Engine temporalmente
|
||||
if (engine_) {
|
||||
engine_->executeToggleGravityOnOff();
|
||||
if (!scene_mgr_) return;
|
||||
|
||||
bool gravity_enabled = scene_mgr_->hasBalls() &&
|
||||
(scene_mgr_->getFirstBall()->getGravityForce() > 0.0f);
|
||||
|
||||
if (gravity_enabled) {
|
||||
scene_mgr_->forceBallsGravityOff();
|
||||
} else {
|
||||
scene_mgr_->forceBallsGravityOn();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// ENTRAR AL MODO LOGO - Migrado desde Engine::enterLogoMode()
|
||||
// ENTRAR AL MODO LOGO
|
||||
// ===========================================================================
|
||||
|
||||
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)
|
||||
if (!engine_ || !scene_mgr_ || !theme_mgr_ || !shape_mgr_) return;
|
||||
|
||||
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;
|
||||
@@ -243,34 +555,91 @@ void StateManager::enterLogoMode(bool from_demo, int current_screen_width, int c
|
||||
// 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);
|
||||
// Verificar mínimo de pelotas
|
||||
if (scene_mgr_->getCurrentScenario() < LOGO_MIN_SCENARIO_IDX) {
|
||||
scene_mgr_->changeScenario(LOGO_MIN_SCENARIO_IDX, shape_mgr_->getCurrentMode());
|
||||
}
|
||||
|
||||
// Guardar estado previo (para restaurar al salir)
|
||||
logo_previous_theme_ = theme_mgr_->getCurrentThemeIndex();
|
||||
logo_previous_texture_index_ = engine_->getCurrentTextureIndex();
|
||||
logo_previous_shape_scale_ = shape_mgr_->getShapeScaleFactor();
|
||||
|
||||
// Aplicar textura "small" si existe — buscar por nombre iterando índices
|
||||
if (engine_->getCurrentTextureName() != "small") {
|
||||
size_t original_idx = logo_previous_texture_index_;
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < 20; ++i) {
|
||||
engine_->setTextureByIndex(i);
|
||||
if (engine_->getCurrentTextureName() == "small") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (engine_->getCurrentTextureName().empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
engine_->setTextureByIndex(original_idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Cambiar a tema aleatorio entre: MONOCHROME, LAVENDER, CRIMSON, ESMERALDA
|
||||
int logo_themes[] = {5, 6, 7, 8};
|
||||
theme_mgr_->switchToTheme(logo_themes[rand() % 4]);
|
||||
|
||||
// Establecer escala a 120%
|
||||
shape_mgr_->setShapeScaleFactor(LOGO_MODE_SHAPE_SCALE);
|
||||
|
||||
// Activar PNG_SHAPE (el logo)
|
||||
engine_->enterShapeMode(ShapeType::PNG_SHAPE);
|
||||
|
||||
// Configurar PNG_SHAPE en modo LOGO
|
||||
PNGShape* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
|
||||
if (png_shape) {
|
||||
png_shape->setLogoMode(true);
|
||||
png_shape->resetFlipCount();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// SALIR DEL MODO LOGO - Migrado desde Engine::exitLogoMode()
|
||||
// SALIR DEL MODO LOGO
|
||||
// ===========================================================================
|
||||
|
||||
void StateManager::exitLogoMode(bool return_to_demo) {
|
||||
if (current_app_mode_ != AppMode::LOGO) return;
|
||||
if (!engine_ || !scene_mgr_ || !theme_mgr_ || !shape_mgr_) 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();
|
||||
// Restaurar estado visual previo
|
||||
theme_mgr_->switchToTheme(logo_previous_theme_);
|
||||
engine_->setTextureByIndex(logo_previous_texture_index_);
|
||||
shape_mgr_->setShapeScaleFactor(logo_previous_shape_scale_);
|
||||
shape_mgr_->generateShape();
|
||||
|
||||
// Activar atracción física si estamos en modo SHAPE
|
||||
if (shape_mgr_->isShapeModeActive()) {
|
||||
scene_mgr_->enableShapeAttractionAll(true);
|
||||
}
|
||||
|
||||
// Desactivar modo LOGO en PNG_SHAPE
|
||||
PNGShape* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
|
||||
if (png_shape) {
|
||||
png_shape->setLogoMode(false);
|
||||
}
|
||||
|
||||
// Si la figura activa es PNG_SHAPE, cambiar a otra figura aleatoria
|
||||
if (shape_mgr_->getCurrentShapeType() == ShapeType::PNG_SHAPE) {
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX,
|
||||
ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER,
|
||||
ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
engine_->enterShapeMode(shapes[rand() % 8]);
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user