Implementar Modo DEMO (auto-play) con tecla D
CAMBIOS PRINCIPALES: - ✅ **Modo DEMO toggleable con tecla D** - Auto-play inteligente - ✅ **Sistema de acciones aleatorias** - Cada 3-8 segundos - ✅ **Totalmente interactivo** - Usuario puede seguir controlando - ✅ **Eliminado sistema auto-restart antiguo** - Ya no reinicia al pararse CARACTERÍSTICAS DEMO MODE: - **Acciones parametrizables** con pesos de probabilidad: * Cambiar gravedad (UP/DOWN/LEFT/RIGHT) - 15% * Activar figuras 3D (8 figuras) - 25% * Cambiar temas de colores (6 temas) - 20% * Cambiar número de pelotas (1-100K) - 15% * Impulsos (SPACE) - 10% * Toggle profundidad Z - 5% * Cambiar escala de figura - 5% * Cambiar sprite - 5% - **Display visual**: "DEMO MODE" centrado en naranja brillante - **Textos de feedback**: "DEMO MODE ON/OFF" al togglear CÓDIGO ELIMINADO: - ❌ `checkAutoRestart()` y `performRandomRestart()` (ya no necesarios) - ❌ `Ball::isStopped()` y variable `stopped_` (sin uso) - ❌ Variables `all_balls_stopped_start_time_`, `all_balls_were_stopped_` CONSTANTES CONFIGURABLES (defines.h): - `DEMO_ACTION_INTERVAL_MIN/MAX` (3-8s entre acciones) - `DEMO_WEIGHT_*` (pesos para priorizar acciones) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -166,9 +166,6 @@ void Engine::update() {
|
||||
for (auto &ball : balls_) {
|
||||
ball->update(delta_time_); // Pasar delta time a cada pelota
|
||||
}
|
||||
|
||||
// Verificar auto-reinicio cuando todas las pelotas están quietas (solo en modo física)
|
||||
checkAutoRestart();
|
||||
} else if (current_mode_ == SimulationMode::SHAPE) {
|
||||
// Modo Figura 3D: actualizar figura polimórfica
|
||||
updateShape();
|
||||
@@ -179,6 +176,9 @@ void Engine::update() {
|
||||
show_text_ = !(SDL_GetTicks() - text_init_time_ > TEXT_DURATION);
|
||||
}
|
||||
|
||||
// Actualizar Modo DEMO (auto-play)
|
||||
updateDemoMode();
|
||||
|
||||
// Actualizar transición de tema (LERP)
|
||||
if (transitioning_) {
|
||||
transition_progress_ += delta_time_ / transition_duration_;
|
||||
@@ -468,6 +468,27 @@ void Engine::handleEvents() {
|
||||
case SDLK_F5:
|
||||
toggleIntegerScaling();
|
||||
break;
|
||||
|
||||
// Toggle Modo DEMO (auto-play)
|
||||
case SDLK_D:
|
||||
demo_mode_enabled_ = !demo_mode_enabled_;
|
||||
if (demo_mode_enabled_) {
|
||||
// Al activar: inicializar timer con primer intervalo aleatorio
|
||||
demo_timer_ = 0.0f;
|
||||
float interval_range = DEMO_ACTION_INTERVAL_MAX - DEMO_ACTION_INTERVAL_MIN;
|
||||
demo_next_action_time_ = DEMO_ACTION_INTERVAL_MIN + (rand() % 1000) / 1000.0f * interval_range;
|
||||
|
||||
// Mostrar texto de activación
|
||||
text_ = "DEMO MODE ON";
|
||||
show_text_ = true;
|
||||
text_init_time_ = SDL_GetTicks();
|
||||
} else {
|
||||
// Al desactivar: mostrar texto
|
||||
text_ = "DEMO MODE OFF";
|
||||
show_text_ = true;
|
||||
text_init_time_ = SDL_GetTicks();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -608,6 +629,15 @@ void Engine::render() {
|
||||
dbg_print(8, 72, mode_text.c_str(), 0, 255, 128); // Verde claro para modo
|
||||
}
|
||||
|
||||
// Mostrar indicador "DEMO MODE" permanente cuando está activo (independiente de show_debug_)
|
||||
if (demo_mode_enabled_) {
|
||||
// Centrar texto horizontalmente
|
||||
const char* demo_text = "DEMO MODE";
|
||||
int demo_text_width = static_cast<int>(strlen(demo_text) * 8); // 8 píxeles por carácter
|
||||
int demo_x = (current_screen_width_ - demo_text_width) / 2;
|
||||
dbg_print(demo_x, 8, demo_text, 255, 128, 0); // Naranja brillante
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer_);
|
||||
}
|
||||
|
||||
@@ -1167,48 +1197,113 @@ Color Engine::getInterpolatedColor(size_t ball_index) const {
|
||||
};
|
||||
}
|
||||
|
||||
void Engine::checkAutoRestart() {
|
||||
// Verificar si TODAS las pelotas están paradas
|
||||
bool all_stopped = true;
|
||||
for (const auto &ball : balls_) {
|
||||
if (!ball->isStopped()) {
|
||||
all_stopped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Sistema de Modo DEMO (auto-play)
|
||||
void Engine::updateDemoMode() {
|
||||
if (!demo_mode_enabled_) return;
|
||||
|
||||
if (all_stopped) {
|
||||
if (!all_balls_were_stopped_) {
|
||||
// Primera vez que se detecta que todas están paradas
|
||||
all_balls_stopped_start_time_ = SDL_GetTicks();
|
||||
all_balls_were_stopped_ = true;
|
||||
} else {
|
||||
// Ya estaban paradas, verificar tiempo transcurrido
|
||||
Uint64 current_time = SDL_GetTicks();
|
||||
if (current_time - all_balls_stopped_start_time_ >= AUTO_RESTART_DELAY) {
|
||||
performRandomRestart();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Al menos una pelota se está moviendo - resetear temporizador
|
||||
all_balls_were_stopped_ = false;
|
||||
all_balls_stopped_start_time_ = 0;
|
||||
// Actualizar timer
|
||||
demo_timer_ += delta_time_;
|
||||
|
||||
// Si es hora de ejecutar acción
|
||||
if (demo_timer_ >= demo_next_action_time_) {
|
||||
performDemoAction();
|
||||
|
||||
// Resetear timer y calcular próximo intervalo aleatorio
|
||||
demo_timer_ = 0.0f;
|
||||
float interval_range = DEMO_ACTION_INTERVAL_MAX - DEMO_ACTION_INTERVAL_MIN;
|
||||
demo_next_action_time_ = DEMO_ACTION_INTERVAL_MIN + (rand() % 1000) / 1000.0f * interval_range;
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::performRandomRestart() {
|
||||
// Escenario aleatorio usando tamaño del array
|
||||
scenario_ = rand() % test_.size();
|
||||
void Engine::performDemoAction() {
|
||||
// Calcular suma total de pesos
|
||||
const int TOTAL_WEIGHT = DEMO_WEIGHT_GRAVITY + DEMO_WEIGHT_SHAPE + DEMO_WEIGHT_THEME
|
||||
+ DEMO_WEIGHT_SCENARIO + DEMO_WEIGHT_IMPULSE + DEMO_WEIGHT_DEPTH_ZOOM
|
||||
+ DEMO_WEIGHT_SHAPE_SCALE + DEMO_WEIGHT_SPRITE;
|
||||
|
||||
// Tema aleatorio usando tamaño del array de temas
|
||||
current_theme_ = static_cast<ColorTheme>(rand() % (sizeof(themes_) / sizeof(themes_[0])));
|
||||
// Generar número aleatorio entre 0 y TOTAL_WEIGHT
|
||||
int random_value = rand() % TOTAL_WEIGHT;
|
||||
|
||||
// Reinicializar pelotas con nuevo escenario y tema
|
||||
initBalls(scenario_);
|
||||
// Determinar acción según pesos acumulados
|
||||
int accumulated_weight = 0;
|
||||
|
||||
// Resetear temporizador
|
||||
all_balls_were_stopped_ = false;
|
||||
all_balls_stopped_start_time_ = 0;
|
||||
// Acción: Cambiar gravedad (15%)
|
||||
accumulated_weight += DEMO_WEIGHT_GRAVITY;
|
||||
if (random_value < accumulated_weight) {
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
changeGravityDirection(new_direction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Activar figura 3D (25%)
|
||||
accumulated_weight += DEMO_WEIGHT_SHAPE;
|
||||
if (random_value < accumulated_weight) {
|
||||
// Elegir figura aleatoria (SPHERE a ATOM = 8 figuras)
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::WAVE_GRID, ShapeType::HELIX,
|
||||
ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER,
|
||||
ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
int shape_index = rand() % 8;
|
||||
activateShape(shapes[shape_index]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Cambiar tema (20%)
|
||||
accumulated_weight += DEMO_WEIGHT_THEME;
|
||||
if (random_value < accumulated_weight) {
|
||||
ColorTheme new_theme = static_cast<ColorTheme>(rand() % 6); // 6 temas disponibles
|
||||
startThemeTransition(new_theme);
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Cambiar escenario/número de pelotas (15%)
|
||||
accumulated_weight += DEMO_WEIGHT_SCENARIO;
|
||||
if (random_value < accumulated_weight) {
|
||||
scenario_ = rand() % test_.size();
|
||||
initBalls(scenario_);
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Aplicar impulso (10%)
|
||||
accumulated_weight += DEMO_WEIGHT_IMPULSE;
|
||||
if (random_value < accumulated_weight) {
|
||||
pushBallsAwayFromGravity();
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Toggle profundidad (5%)
|
||||
accumulated_weight += DEMO_WEIGHT_DEPTH_ZOOM;
|
||||
if (random_value < accumulated_weight) {
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
depth_zoom_enabled_ = !depth_zoom_enabled_;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Cambiar escala de figura (5%)
|
||||
accumulated_weight += DEMO_WEIGHT_SHAPE_SCALE;
|
||||
if (random_value < accumulated_weight) {
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
// Aleatorio: +1, -1, o reset
|
||||
int scale_action = rand() % 3;
|
||||
if (scale_action == 0) {
|
||||
shape_scale_factor_ += SHAPE_SCALE_STEP;
|
||||
} else if (scale_action == 1) {
|
||||
shape_scale_factor_ -= SHAPE_SCALE_STEP;
|
||||
} else {
|
||||
shape_scale_factor_ = SHAPE_SCALE_DEFAULT;
|
||||
}
|
||||
clampShapeScale();
|
||||
generateShape();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Acción: Cambiar sprite (5%)
|
||||
accumulated_weight += DEMO_WEIGHT_SPRITE;
|
||||
if (random_value < accumulated_weight) {
|
||||
switchTexture();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sistema de cambio de sprites dinámico
|
||||
|
||||
Reference in New Issue
Block a user