Refactor: Sistema de modos y notificaciones mejorado

Cambios principales:
- Renombrado AppMode::MANUAL → AppMode::SANDBOX (nomenclatura más clara)
- Notificaciones ahora funcionan en TODAS las transiciones de modo
- Lógica de teclas D/L/K simplificada: toggle exclusivo modo ↔ SANDBOX
- Mensajes simplificados: "MODO DEMO", "MODO SANDBOX", etc. (sin ON/OFF)
- Eliminado check restrictivo en showNotificationForAction()

Comportamiento nuevo:
- Tecla D: Toggle DEMO ↔ SANDBOX
- Tecla L: Toggle DEMO_LITE ↔ SANDBOX
- Tecla K: Toggle LOGO ↔ SANDBOX
- Cada tecla activa su modo o vuelve a SANDBOX si ya está activo
- Notificaciones visibles tanto al activar como desactivar modos

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-10 07:44:57 +02:00
parent 0d1608712b
commit 10a4234d49
2 changed files with 115 additions and 149 deletions

View File

@@ -329,8 +329,12 @@ void Engine::handleEvents() {
// Si estamos en modo figura, salir a modo física SIN GRAVEDAD // Si estamos en modo figura, salir a modo física SIN GRAVEDAD
if (current_mode_ == SimulationMode::SHAPE) { if (current_mode_ == SimulationMode::SHAPE) {
toggleShapeMode(false); // Desactivar figura sin forzar gravedad ON toggleShapeMode(false); // Desactivar figura sin forzar gravedad ON
showNotificationForAction("Gravity Off");
} else { } else {
switchBallsGravity(); // Toggle normal en modo física switchBallsGravity(); // Toggle normal en modo física
// Determinar estado actual de gravedad (gravity_force_ != 0.0f significa ON)
bool gravity_on = balls_.empty() ? true : (balls_[0]->getGravityForce() != 0.0f);
showNotificationForAction(gravity_on ? "Gravity On" : "Gravity Off");
} }
break; break;
@@ -343,6 +347,7 @@ void Engine::handleEvents() {
enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF
} }
changeGravityDirection(GravityDirection::UP); changeGravityDirection(GravityDirection::UP);
showNotificationForAction("Gravity Up");
break; break;
case SDLK_DOWN: case SDLK_DOWN:
@@ -353,6 +358,7 @@ void Engine::handleEvents() {
enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF
} }
changeGravityDirection(GravityDirection::DOWN); changeGravityDirection(GravityDirection::DOWN);
showNotificationForAction("Gravity Down");
break; break;
case SDLK_LEFT: case SDLK_LEFT:
@@ -363,6 +369,7 @@ void Engine::handleEvents() {
enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF
} }
changeGravityDirection(GravityDirection::LEFT); changeGravityDirection(GravityDirection::LEFT);
showNotificationForAction("Gravity Left");
break; break;
case SDLK_RIGHT: case SDLK_RIGHT:
@@ -373,6 +380,7 @@ void Engine::handleEvents() {
enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF
} }
changeGravityDirection(GravityDirection::RIGHT); changeGravityDirection(GravityDirection::RIGHT);
showNotificationForAction("Gravity Right");
break; break;
case SDLK_V: case SDLK_V:
@@ -386,43 +394,60 @@ void Engine::handleEvents() {
// Toggle Física ↔ Última Figura (antes era C) // Toggle Física ↔ Última Figura (antes era C)
case SDLK_F: case SDLK_F:
toggleShapeMode(); toggleShapeMode();
// Mostrar notificación según el modo actual después del toggle
if (current_mode_ == SimulationMode::PHYSICS) {
showNotificationForAction("Physics Mode");
} else {
// Mostrar nombre de la figura actual
const char* shape_names[] = {"Sphere", "Lissajous", "Helix", "Torus", "Cube", "Cylinder", "Icosahedron", "Atom", "PNG Shape"};
showNotificationForAction(shape_names[static_cast<int>(current_shape_type_)]);
}
break; break;
// Selección directa de figuras 3D // Selección directa de figuras 3D
case SDLK_Q: case SDLK_Q:
activateShape(ShapeType::SPHERE); activateShape(ShapeType::SPHERE);
showNotificationForAction("Sphere");
break; break;
case SDLK_W: case SDLK_W:
activateShape(ShapeType::LISSAJOUS); activateShape(ShapeType::LISSAJOUS);
showNotificationForAction("Lissajous");
break; break;
case SDLK_E: case SDLK_E:
activateShape(ShapeType::HELIX); activateShape(ShapeType::HELIX);
showNotificationForAction("Helix");
break; break;
case SDLK_R: case SDLK_R:
activateShape(ShapeType::TORUS); activateShape(ShapeType::TORUS);
showNotificationForAction("Torus");
break; break;
case SDLK_T: case SDLK_T:
activateShape(ShapeType::CUBE); activateShape(ShapeType::CUBE);
showNotificationForAction("Cube");
break; break;
case SDLK_Y: case SDLK_Y:
activateShape(ShapeType::CYLINDER); activateShape(ShapeType::CYLINDER);
showNotificationForAction("Cylinder");
break; break;
case SDLK_U: case SDLK_U:
activateShape(ShapeType::ICOSAHEDRON); activateShape(ShapeType::ICOSAHEDRON);
showNotificationForAction("Icosahedron");
break; break;
case SDLK_I: case SDLK_I:
activateShape(ShapeType::ATOM); activateShape(ShapeType::ATOM);
showNotificationForAction("Atom");
break; break;
case SDLK_O: case SDLK_O:
activateShape(ShapeType::PNG_SHAPE); activateShape(ShapeType::PNG_SHAPE);
showNotificationForAction("PNG Shape");
break; break;
// Ciclar temas de color (movido de T a B) // Ciclar temas de color (movido de T a B)
@@ -438,13 +463,8 @@ void Engine::handleEvents() {
theme_manager_->cycleTheme(); theme_manager_->cycleTheme();
} }
// Mostrar nombre del tema (solo si NO estamos en modo demo) // Mostrar notificación con el nombre del tema
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -454,12 +474,7 @@ void Engine::handleEvents() {
{ {
int theme_index = (theme_page_ == 0) ? 0 : 10; int theme_index = (theme_page_ == 0) ? 0 : 10;
theme_manager_->switchToTheme(theme_index); theme_manager_->switchToTheme(theme_index);
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -468,12 +483,7 @@ void Engine::handleEvents() {
{ {
int theme_index = (theme_page_ == 0) ? 1 : 11; int theme_index = (theme_page_ == 0) ? 1 : 11;
theme_manager_->switchToTheme(theme_index); theme_manager_->switchToTheme(theme_index);
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -482,12 +492,7 @@ void Engine::handleEvents() {
{ {
int theme_index = (theme_page_ == 0) ? 2 : 12; int theme_index = (theme_page_ == 0) ? 2 : 12;
theme_manager_->switchToTheme(theme_index); theme_manager_->switchToTheme(theme_index);
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -496,12 +501,7 @@ void Engine::handleEvents() {
{ {
int theme_index = (theme_page_ == 0) ? 3 : 13; int theme_index = (theme_page_ == 0) ? 3 : 13;
theme_manager_->switchToTheme(theme_index); theme_manager_->switchToTheme(theme_index);
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -510,12 +510,7 @@ void Engine::handleEvents() {
{ {
int theme_index = (theme_page_ == 0) ? 4 : 14; int theme_index = (theme_page_ == 0) ? 4 : 14;
theme_manager_->switchToTheme(theme_index); theme_manager_->switchToTheme(theme_index);
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -523,12 +518,7 @@ void Engine::handleEvents() {
// Solo página 0: MONOCHROME (5) // Solo página 0: MONOCHROME (5)
if (theme_page_ == 0) { if (theme_page_ == 0) {
theme_manager_->switchToTheme(5); // MONOCHROME theme_manager_->switchToTheme(5); // MONOCHROME
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -536,12 +526,7 @@ void Engine::handleEvents() {
// Solo página 0: LAVENDER (6) // Solo página 0: LAVENDER (6)
if (theme_page_ == 0) { if (theme_page_ == 0) {
theme_manager_->switchToTheme(6); // LAVENDER theme_manager_->switchToTheme(6); // LAVENDER
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -549,12 +534,7 @@ void Engine::handleEvents() {
// Solo página 0: CRIMSON (7) // Solo página 0: CRIMSON (7)
if (theme_page_ == 0) { if (theme_page_ == 0) {
theme_manager_->switchToTheme(7); // CRIMSON theme_manager_->switchToTheme(7); // CRIMSON
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -562,12 +542,7 @@ void Engine::handleEvents() {
// Solo página 0: EMERALD (8) // Solo página 0: EMERALD (8)
if (theme_page_ == 0) { if (theme_page_ == 0) {
theme_manager_->switchToTheme(8); // EMERALD theme_manager_->switchToTheme(8); // EMERALD
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -575,12 +550,7 @@ void Engine::handleEvents() {
// Solo página 0: SUNRISE (9) // Solo página 0: SUNRISE (9)
if (theme_page_ == 0) { if (theme_page_ == 0) {
theme_manager_->switchToTheme(9); // SUNRISE theme_manager_->switchToTheme(9); // SUNRISE
if (current_app_mode_ == AppMode::MANUAL) { showNotificationForAction(theme_manager_->getCurrentThemeNameES());
text_ = theme_manager_->getCurrentThemeNameES();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
} }
break; break;
@@ -588,14 +558,7 @@ void Engine::handleEvents() {
case SDLK_KP_ENTER: case SDLK_KP_ENTER:
// Alternar entre página 0 y página 1 // Alternar entre página 0 y página 1
theme_page_ = (theme_page_ == 0) ? 1 : 0; theme_page_ = (theme_page_ == 0) ? 1 : 0;
showNotificationForAction((theme_page_ == 0) ? "Página 1" : "Página 2");
// Mostrar feedback visual (solo si NO estamos en modo demo)
if (current_app_mode_ == AppMode::MANUAL) {
text_ = (theme_page_ == 0) ? "Página 1" : "Página 2";
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
}
break; break;
// Cambio de sprite/textura dinámico // Cambio de sprite/textura dinámico
@@ -608,11 +571,7 @@ void Engine::handleEvents() {
if (current_mode_ == SimulationMode::SHAPE) { if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ += SHAPE_SCALE_STEP; shape_scale_factor_ += SHAPE_SCALE_STEP;
clampShapeScale(); clampShapeScale();
text_ = "Escala " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%"; showNotificationForAction("Escala " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%");
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
} }
break; break;
@@ -620,74 +579,70 @@ void Engine::handleEvents() {
if (current_mode_ == SimulationMode::SHAPE) { if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ -= SHAPE_SCALE_STEP; shape_scale_factor_ -= SHAPE_SCALE_STEP;
clampShapeScale(); clampShapeScale();
text_ = "Escala " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%"; showNotificationForAction("Escala " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%");
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
} }
break; break;
case SDLK_KP_MULTIPLY: case SDLK_KP_MULTIPLY:
if (current_mode_ == SimulationMode::SHAPE) { if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ = SHAPE_SCALE_DEFAULT; shape_scale_factor_ = SHAPE_SCALE_DEFAULT;
text_ = "Escala reiniciada (100%)"; showNotificationForAction("Escala 100%");
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
} }
break; break;
case SDLK_KP_DIVIDE: case SDLK_KP_DIVIDE:
if (current_mode_ == SimulationMode::SHAPE) { if (current_mode_ == SimulationMode::SHAPE) {
depth_zoom_enabled_ = !depth_zoom_enabled_; depth_zoom_enabled_ = !depth_zoom_enabled_;
text_ = depth_zoom_enabled_ ? "Zoom profundidad: On" : "Zoom profundidad: Off"; showNotificationForAction(depth_zoom_enabled_ ? "Depth Zoom On" : "Depth Zoom Off");
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
} }
break; break;
case SDLK_1: case SDLK_1:
scenario_ = 0; scenario_ = 0;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("10 Pelotas");
break; break;
case SDLK_2: case SDLK_2:
scenario_ = 1; scenario_ = 1;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("50 Pelotas");
break; break;
case SDLK_3: case SDLK_3:
scenario_ = 2; scenario_ = 2;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("100 Pelotas");
break; break;
case SDLK_4: case SDLK_4:
scenario_ = 3; scenario_ = 3;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("500 Pelotas");
break; break;
case SDLK_5: case SDLK_5:
scenario_ = 4; scenario_ = 4;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("1,000 Pelotas");
break; break;
case SDLK_6: case SDLK_6:
scenario_ = 5; scenario_ = 5;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("5,000 Pelotas");
break; break;
case SDLK_7: case SDLK_7:
scenario_ = 6; scenario_ = 6;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("10,000 Pelotas");
break; break;
case SDLK_8: case SDLK_8:
scenario_ = 7; scenario_ = 7;
initBalls(scenario_); initBalls(scenario_);
showNotificationForAction("50,000 Pelotas");
break; break;
// Controles de zoom dinámico (solo si no estamos en fullscreen) // Controles de zoom dinámico (solo si no estamos en fullscreen)
@@ -724,22 +679,16 @@ void Engine::handleEvents() {
if (event.key.mod & SDL_KMOD_SHIFT) { if (event.key.mod & SDL_KMOD_SHIFT) {
theme_manager_->pauseDynamic(); theme_manager_->pauseDynamic();
} else { } else {
// D sin Shift = Toggle modo DEMO // D sin Shift = Toggle DEMO ↔ SANDBOX
if (current_app_mode_ == AppMode::DEMO) { if (current_app_mode_ == AppMode::DEMO) {
// Desactivar DEMO → MANUAL // Ya estamos en DEMO → volver a SANDBOX
setState(AppMode::MANUAL); setState(AppMode::SANDBOX);
text_ = "Modo Demo: Off"; showNotificationForAction("MODO SANDBOX");
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
} else { } else {
// Activar DEMO (desde cualquier otro modo) // Estamos en otro modo → ir a DEMO
setState(AppMode::DEMO); setState(AppMode::DEMO);
randomizeOnDemoStart(false); randomizeOnDemoStart(false);
text_ = "Modo Demo: On"; showNotificationForAction("MODO DEMO");
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
} }
} }
break; break;
@@ -747,35 +696,28 @@ void Engine::handleEvents() {
// Toggle Modo DEMO LITE (solo física/figuras) // Toggle Modo DEMO LITE (solo física/figuras)
case SDLK_L: case SDLK_L:
if (current_app_mode_ == AppMode::DEMO_LITE) { if (current_app_mode_ == AppMode::DEMO_LITE) {
// Desactivar DEMO_LITE → MANUAL // Ya estamos en DEMO_LITE → volver a SANDBOX
setState(AppMode::MANUAL); setState(AppMode::SANDBOX);
text_ = "Modo Demo Lite: Off"; showNotificationForAction("MODO SANDBOX");
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
} else { } else {
// Activar DEMO_LITE (desde cualquier otro modo) // Estamos en otro modo → ir a DEMO_LITE
setState(AppMode::DEMO_LITE); setState(AppMode::DEMO_LITE);
randomizeOnDemoStart(true); randomizeOnDemoStart(true);
text_ = "Modo Demo Lite: On"; showNotificationForAction("MODO DEMO LITE");
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
} }
break; break;
// Toggle Modo LOGO (easter egg - marca de agua) // Toggle Modo LOGO (easter egg - marca de agua)
case SDLK_K: case SDLK_K:
toggleLogoMode();
// Mostrar texto informativo
if (current_app_mode_ == AppMode::LOGO) { if (current_app_mode_ == AppMode::LOGO) {
text_ = "Modo Logo: On"; // Ya estamos en LOGO → volver a SANDBOX
exitLogoMode(false);
showNotificationForAction("MODO SANDBOX");
} else { } else {
text_ = "Modo Logo: Off"; // Estamos en otro modo → ir a LOGO
enterLogoMode(false);
showNotificationForAction("MODO LOGO");
} }
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
break; break;
} }
} }
@@ -1039,12 +981,12 @@ void Engine::initBalls(int value) {
float mass_factor = GRAVITY_MASS_MIN + (rand() % 1000) / 1000.0f * (GRAVITY_MASS_MAX - GRAVITY_MASS_MIN); float mass_factor = GRAVITY_MASS_MIN + (rand() % 1000) / 1000.0f * (GRAVITY_MASS_MAX - GRAVITY_MASS_MIN);
balls_.emplace_back(std::make_unique<Ball>(X, VX, VY, COLOR, texture_, current_screen_width_, current_screen_height_, current_ball_size_, current_gravity_, mass_factor)); balls_.emplace_back(std::make_unique<Ball>(X, VX, VY, COLOR, texture_, current_screen_width_, current_screen_height_, current_ball_size_, current_gravity_, mass_factor));
} }
setText(); // Actualiza el texto // NOTA: setText() removido - las notificaciones ahora se llaman manualmente desde cada tecla
} }
void Engine::setText() { void Engine::setText() {
// Suprimir textos durante modos demo // Suprimir textos durante modos demo
if (current_app_mode_ != AppMode::MANUAL) return; if (current_app_mode_ != AppMode::SANDBOX) return;
// Generar texto de número de pelotas // Generar texto de número de pelotas
int num_balls = BALL_COUNT_SCENARIOS[scenario_]; int num_balls = BALL_COUNT_SCENARIOS[scenario_];
@@ -1091,6 +1033,34 @@ void Engine::setText() {
text_init_time_ = SDL_GetTicks(); text_init_time_ = SDL_GetTicks();
} }
void Engine::showNotificationForAction(const std::string& text) {
// IMPORTANTE: Esta función solo se llama desde handlers de teclado (acciones manuales)
// NUNCA se llama desde código automático (DEMO/LOGO), por lo tanto siempre mostramos notificación
// Obtener color del tema actual para el texto
int text_r, text_g, text_b;
theme_manager_->getCurrentThemeTextColor(text_r, text_g, text_b);
SDL_Color notification_color = {
static_cast<Uint8>(text_r),
static_cast<Uint8>(text_g),
static_cast<Uint8>(text_b),
255
};
// Obtener color de fondo de la notificación desde el tema
int bg_r, bg_g, bg_b;
theme_manager_->getCurrentNotificationBackgroundColor(bg_r, bg_g, bg_b);
SDL_Color notification_bg_color = {
static_cast<Uint8>(bg_r),
static_cast<Uint8>(bg_g),
static_cast<Uint8>(bg_b),
255
};
// Mostrar notificación
notifier_.show(text, NOTIFICATION_DURATION, notification_color, notification_bg_color);
}
void Engine::pushBallsAwayFromGravity() { void Engine::pushBallsAwayFromGravity() {
for (auto& ball : balls_) { for (auto& ball : balls_) {
const int SIGNO = ((rand() % 2) * 2) - 1; const int SIGNO = ((rand() % 2) * 2) - 1;
@@ -1552,7 +1522,7 @@ void Engine::setState(AppMode new_mode) {
void Engine::updateDemoMode() { void Engine::updateDemoMode() {
// Verificar si algún modo demo está activo (DEMO, DEMO_LITE o LOGO) // Verificar si algún modo demo está activo (DEMO, DEMO_LITE o LOGO)
if (current_app_mode_ == AppMode::MANUAL) return; if (current_app_mode_ == AppMode::SANDBOX) return;
// Actualizar timer // Actualizar timer
demo_timer_ += delta_time_; demo_timer_ += delta_time_;
@@ -1692,7 +1662,7 @@ void Engine::updateDemoMode() {
// Solo salir automáticamente si NO llegamos desde MANUAL // Solo salir automáticamente si NO llegamos desde MANUAL
// Probabilidad de salir: 60% en cada acción → sale rápido (relación DEMO:LOGO = 6:1) // Probabilidad de salir: 60% en cada acción → sale rápido (relación DEMO:LOGO = 6:1)
if (previous_app_mode_ != AppMode::MANUAL && rand() % 100 < 60) { if (previous_app_mode_ != AppMode::SANDBOX && rand() % 100 < 60) {
exitLogoMode(true); // Volver a DEMO/DEMO_LITE exitLogoMode(true); // Volver a DEMO/DEMO_LITE
} }
} }
@@ -1891,7 +1861,7 @@ void Engine::performDemoAction(bool is_lite) {
// Cambiar sprite (2%) // Cambiar sprite (2%)
accumulated_weight += DEMO_WEIGHT_SPRITE; accumulated_weight += DEMO_WEIGHT_SPRITE;
if (random_value < accumulated_weight) { if (random_value < accumulated_weight) {
switchTexture(); switchTexture(false); // Suprimir notificación en modo automático
return; return;
} }
} }
@@ -1934,7 +1904,7 @@ void Engine::randomizeOnDemoStart(bool is_lite) {
// 3. Sprite // 3. Sprite
if (rand() % 2 == 0) { if (rand() % 2 == 0) {
switchTexture(); switchTexture(false); // Suprimir notificación al activar modo DEMO
} }
// 4. Física o Figura // 4. Física o Figura
@@ -2087,7 +2057,7 @@ void Engine::exitLogoMode(bool return_to_demo) {
if (!return_to_demo) { if (!return_to_demo) {
// Salida manual (tecla K): volver a MANUAL // Salida manual (tecla K): volver a MANUAL
setState(AppMode::MANUAL); setState(AppMode::SANDBOX);
} else { } else {
// Volver al modo previo (DEMO o DEMO_LITE) // Volver al modo previo (DEMO o DEMO_LITE)
setState(previous_app_mode_); setState(previous_app_mode_);
@@ -2147,7 +2117,7 @@ void Engine::updateBallSizes(int old_size, int new_size) {
} }
} }
void Engine::switchTexture() { void Engine::switchTexture(bool show_notification) {
if (textures_.empty()) return; if (textures_.empty()) return;
// Guardar tamaño antiguo // Guardar tamaño antiguo
@@ -2169,16 +2139,11 @@ void Engine::switchTexture() {
// Ajustar posiciones según el cambio de tamaño // Ajustar posiciones según el cambio de tamaño
updateBallSizes(old_size, new_size); updateBallSizes(old_size, new_size);
// Mostrar texto informativo (solo si NO estamos en modo demo) // Mostrar notificación con el nombre de la textura (solo si se solicita)
if (current_app_mode_ == AppMode::MANUAL) { if (show_notification) {
// Obtener nombre de textura (uppercase)
std::string texture_name = texture_names_[current_texture_index_]; std::string texture_name = texture_names_[current_texture_index_];
std::transform(texture_name.begin(), texture_name.end(), texture_name.begin(), ::toupper); std::transform(texture_name.begin(), texture_name.end(), texture_name.begin(), ::toupper);
showNotificationForAction("Sprite: " + texture_name);
text_ = "Sprite: " + texture_name;
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
} }
} }
@@ -2220,7 +2185,7 @@ void Engine::toggleShapeMode(bool force_gravity_on_exit) {
} }
// Mostrar texto informativo (solo si NO estamos en modo demo o logo) // Mostrar texto informativo (solo si NO estamos en modo demo o logo)
if (current_app_mode_ == AppMode::MANUAL) { if (current_app_mode_ == AppMode::SANDBOX) {
text_ = "Modo Física"; text_ = "Modo Física";
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2; text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
text_init_time_ = SDL_GetTicks(); text_init_time_ = SDL_GetTicks();
@@ -2284,7 +2249,7 @@ void Engine::activateShape(ShapeType type) {
} }
// Mostrar texto informativo con nombre de figura (solo si NO estamos en modo demo o logo) // Mostrar texto informativo con nombre de figura (solo si NO estamos en modo demo o logo)
if (active_shape_ && current_app_mode_ == AppMode::MANUAL) { if (active_shape_ && current_app_mode_ == AppMode::SANDBOX) {
text_ = std::string("Modo ") + active_shape_->getName(); text_ = std::string("Modo ") + active_shape_->getName();
text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2; text_pos_ = (current_screen_width_ - text_renderer_.getTextWidth(text_.c_str())) / 2;
text_init_time_ = SDL_GetTicks(); text_init_time_ = SDL_GetTicks();

View File

@@ -20,7 +20,7 @@
// Modos de aplicación mutuamente excluyentes // Modos de aplicación mutuamente excluyentes
enum class AppMode { enum class AppMode {
MANUAL, // Control manual del usuario SANDBOX, // Control manual del usuario (modo sandbox)
DEMO, // Modo demo completo (auto-play) DEMO, // Modo demo completo (auto-play)
DEMO_LITE, // Modo demo lite (solo física/figuras) DEMO_LITE, // Modo demo lite (solo física/figuras)
LOGO // Modo logo (easter egg) LOGO // Modo logo (easter egg)
@@ -103,8 +103,8 @@ class Engine {
bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado
// Sistema de Modo DEMO (auto-play) // Sistema de Modo DEMO (auto-play)
AppMode current_app_mode_ = AppMode::MANUAL; // Modo actual (mutuamente excluyente) AppMode current_app_mode_ = AppMode::SANDBOX; // Modo actual (mutuamente excluyente)
AppMode previous_app_mode_ = AppMode::MANUAL; // Modo previo antes de entrar a LOGO AppMode previous_app_mode_ = AppMode::SANDBOX; // Modo previo antes de entrar a LOGO
float demo_timer_ = 0.0f; // Contador de tiempo para próxima acción float demo_timer_ = 0.0f; // Contador de tiempo para próxima acción
float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos) float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos)
@@ -142,7 +142,8 @@ class Engine {
// Métodos auxiliares // Métodos auxiliares
void initBalls(int value); void initBalls(int value);
void setText(); void setText(); // DEPRECATED - usar showNotificationForAction() en su lugar
void showNotificationForAction(const std::string& text); // Mostrar notificación solo en modo MANUAL
void pushBallsAwayFromGravity(); void pushBallsAwayFromGravity();
void switchBallsGravity(); void switchBallsGravity();
void enableBallsGravityIfDisabled(); void enableBallsGravityIfDisabled();
@@ -170,8 +171,8 @@ class Engine {
void exitLogoMode(bool return_to_demo = false); // Salir del modo logo void exitLogoMode(bool return_to_demo = false); // Salir del modo logo
// Sistema de cambio de sprites dinámico // Sistema de cambio de sprites dinámico
void switchTexture(); // Cambia a siguiente textura disponible void switchTexture(bool show_notification = true); // Cambia a siguiente textura disponible
void updateBallSizes(int old_size, int new_size); // Ajusta posiciones al cambiar tamaño void updateBallSizes(int old_size, int new_size); // Ajusta posiciones al cambiar tamaño
// Sistema de zoom dinámico // Sistema de zoom dinámico
int calculateMaxWindowZoom() const; int calculateMaxWindowZoom() const;