Implementar Modo Logo (easter egg) y sistema automático de cursor

MODO LOGO (Easter Egg):
- Modo especial que muestra logo JAILGAMES como "marca de agua"
- Activación manual: tecla K (perpetuo, no sale automáticamente)
- Auto-salto desde DEMO/DEMO_LITE (15%/10% probabilidad, ≥500 pelotas)
- Configuración fija: PNG_SHAPE + tiny texture + MONOCHROME + 120% escala + 5000 pelotas
- Sistema de 5 acciones variadas con probabilidades ajustadas:
  * SHAPE→PHYSICS gravedad ON (50%) - caída dramática
  * SHAPE→PHYSICS gravedad OFF (50%) - ver rotaciones sin caer
  * PHYSICS→SHAPE (60%) - reconstruir logo y mostrar rotaciones
  * PHYSICS: forzar gravedad ON (20%) - caer mientras da vueltas
  * PHYSICS: forzar gravedad OFF (20%) - flotar mientras da vueltas
- Intervalos 4-8s (aumentado para completar ciclos de rotación PNG_SHAPE)
- Textos informativos suprimidos en Logo Mode
- Corrección cambio de textura: actualiza texture_ y setTexture() en pelotas
- PNG_SHAPE idle reducido a 0.5-2s para animación más dinámica

MEJORAS FÍSICAS GLOBALES:
- Impulso automático al quitar gravedad si >50% pelotas en superficie
- Usa isOnSurface() para detectar pelotas quietas (DEMO/DEMO_LITE/LOGO)
- Evita que quitar gravedad con pelotas paradas no haga nada visible

SISTEMA AUTOMÁTICO DE CURSOR:
- Importado mouse.h/mouse.cpp desde Coffee Crisis Arcade Edition
- Auto-oculta cursor tras 3s de inactividad (namespace Mouse)
- Reaparece inmediatamente al mover ratón
- Funciona en todos los modos (ventana, fullscreen F3, real fullscreen F4)
- Eliminadas llamadas manuales SDL_ShowCursor/HideCursor
- Soluciona bug: cursor visible al iniciar con argumento -f

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-04 23:31:04 +02:00
parent f0baa51415
commit be099c198c
7 changed files with 334 additions and 64 deletions

View File

@@ -74,42 +74,42 @@
- ✅ Help text con `--help` - ✅ Help text con `--help`
- Ejemplo: `./vibe3_physics -w 1920 -h 1080 -f` - Ejemplo: `./vibe3_physics -w 1920 -h 1080 -f`
### 4. 🎯 Implementar Modo Logo (Easter Egg) ### 4. Implementar Modo Logo (Easter Egg)
**Descripción:** Modo especial que muestra el logo JAILGAMES como "marca de agua" **Descripción:** Modo especial que muestra el logo JAILGAMES como "marca de agua"
**Prioridad:** Alta (característica distintiva) **Prioridad:** Alta (característica distintiva)
**Estimación:** 2 horas **Estado:** ✅ COMPLETADO
**Detalles:** **Detalles:**
#### Configuración Modo Logo: #### Configuración Modo Logo:
- **Figura:** Solo PNG_SHAPE (logo JAILGAMES) - **Figura:** Solo PNG_SHAPE (logo JAILGAMES)
- **Textura:** Siempre "tiny" (pelota más pequeña) - **Textura:** Siempre "tiny" (pelota más pequeña)
- **Tema:** Siempre MONOCHROME (blanco puro) - **Tema:** Siempre MONOCHROME (blanco puro)
- **Escala:** 120% (figuras más grandes que normal) - **Escala:** 120% (figuras más grandes que normal)
- **Pelotas mínimas:** 500 - **Pelotas mínimas:** 500
- **Tecla manual:** K (activa/desactiva modo logo) - **Tecla manual:** K (activa/desactiva modo logo)
#### Comportamiento en Modo Logo: #### Comportamiento en Modo Logo:
- Alterna entre modo SHAPE y modo PHYSICS (como DEMO) - Alterna entre modo SHAPE y modo PHYSICS (como DEMO)
- Mantiene configuración fija (no cambia tema/textura/escala) - Mantiene configuración fija (no cambia tema/textura/escala)
- Es como un "DEMO específico del logo" - Es como un "DEMO específico del logo"
#### Integración con DEMO LITE: #### Integración con DEMO LITE:
- **Requisitos para salto automático:** - **Requisitos para salto automático:**
- Mínimo 500 pelotas - Mínimo 500 pelotas
- Tema MONOCHROME activo - Tema MONOCHROME activo
- Si se cumplen → cambia automáticamente textura a "tiny" y escala a 120% - Si se cumplen → cambia automáticamente textura a "tiny" y escala a 120%
- **Duración:** Menos tiempo que DEMO normal (es un "recordatorio") - **Duración:** Menos tiempo que DEMO normal (es un "recordatorio")
- **Después:** Vuelve a DEMO LITE normal - **Después:** Vuelve a DEMO LITE normal
#### Integración con DEMO: #### Integración con DEMO:
- **Requisitos:** Mínimo 500 pelotas - **Requisitos:** Mínimo 500 pelotas
- **Acción:** Cambia automáticamente a: MONOCHROME + tiny + escala 120% - **Acción:** Cambia automáticamente a: MONOCHROME + tiny + escala 120%
- **Duración:** Menos tiempo que acciones normales - **Duración:** Menos tiempo que acciones normales
- **Después:** Vuelve a DEMO normal - **Después:** Vuelve a DEMO normal
#### Proporción temporal sugerida: #### Proporción temporal sugerida:
- DEMO/DEMO_LITE normal: 80-90% del tiempo - DEMO/DEMO_LITE normal: 80-90% del tiempo
- Modo Logo: 10-20% del tiempo (aparición ocasional como "easter egg") - Modo Logo: 10-20% del tiempo (aparición ocasional como "easter egg")
### 5. ⏳ Mejorar Sistema de Vértices PNG_SHAPE ### 5. ⏳ Mejorar Sistema de Vértices PNG_SHAPE
**Descripción:** Con 50 pelotas no activa modo vértices correctamente **Descripción:** Con 50 pelotas no activa modo vértices correctamente

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

After

Width:  |  Height:  |  Size: 169 B

View File

@@ -165,8 +165,8 @@ constexpr float PNG_EXTRUSION_DEPTH_FACTOR = 0.12f; // Profundidad de extrusió
constexpr int PNG_NUM_EXTRUSION_LAYERS = 15; // Capas de extrusión (más capas = más pegajosidad) constexpr int PNG_NUM_EXTRUSION_LAYERS = 15; // Capas de extrusión (más capas = más pegajosidad)
constexpr bool PNG_USE_EDGES_ONLY = false; // true = solo bordes, false = relleno completo constexpr bool PNG_USE_EDGES_ONLY = false; // true = solo bordes, false = relleno completo
// Rotación "legible" (texto de frente con volteretas ocasionales) // Rotación "legible" (texto de frente con volteretas ocasionales)
constexpr float PNG_IDLE_TIME_MIN = 3.0f; // Tiempo mínimo de frente (segundos) constexpr float PNG_IDLE_TIME_MIN = 0.5f; // Tiempo mínimo de frente (segundos) - reducido para Logo Mode
constexpr float PNG_IDLE_TIME_MAX = 8.0f; // Tiempo máximo de frente (segundos) constexpr float PNG_IDLE_TIME_MAX = 2.0f; // Tiempo máximo de frente (segundos) - reducido para Logo Mode
constexpr float PNG_FLIP_SPEED = 3.0f; // Velocidad voltereta (rad/s) constexpr float PNG_FLIP_SPEED = 3.0f; // Velocidad voltereta (rad/s)
constexpr float PNG_FLIP_DURATION = 1.5f; // Duración voltereta (segundos) constexpr float PNG_FLIP_DURATION = 1.5f; // Duración voltereta (segundos)
@@ -209,8 +209,8 @@ constexpr int DEMO_LITE_WEIGHT_IMPULSE = 10; // Aplicar impulso (10%)
// Configuración de Modo LOGO (easter egg - "marca de agua") // Configuración de Modo LOGO (easter egg - "marca de agua")
constexpr int LOGO_MODE_MIN_BALLS = 500; // Mínimo de pelotas para activar modo logo constexpr int LOGO_MODE_MIN_BALLS = 500; // Mínimo de pelotas para activar modo logo
constexpr float LOGO_MODE_SHAPE_SCALE = 1.2f; // Escala de figura en modo logo (120%) constexpr float LOGO_MODE_SHAPE_SCALE = 1.2f; // Escala de figura en modo logo (120%)
constexpr float LOGO_ACTION_INTERVAL_MIN = 2.0f; // Tiempo mínimo entre alternancia SHAPE/PHYSICS constexpr float LOGO_ACTION_INTERVAL_MIN = 4.0f; // Tiempo mínimo entre alternancia SHAPE/PHYSICS (más tiempo para ver rotaciones)
constexpr float LOGO_ACTION_INTERVAL_MAX = 5.0f; // Tiempo máximo entre alternancia SHAPE/PHYSICS constexpr float LOGO_ACTION_INTERVAL_MAX = 8.0f; // Tiempo máximo entre alternancia SHAPE/PHYSICS
constexpr int LOGO_WEIGHT_TOGGLE_PHYSICS = 100; // Único peso: alternar SHAPE ↔ PHYSICS (100%) constexpr int LOGO_WEIGHT_TOGGLE_PHYSICS = 100; // Único peso: alternar SHAPE ↔ PHYSICS (100%)
// Probabilidad de salto a Logo Mode desde DEMO/DEMO_LITE (%) // Probabilidad de salto a Logo Mode desde DEMO/DEMO_LITE (%)

View File

@@ -23,6 +23,7 @@
#include "ball.h" // for Ball #include "ball.h" // for Ball
#include "external/dbgtxt.h" // for dbg_init, dbg_print #include "external/dbgtxt.h" // for dbg_init, dbg_print
#include "external/mouse.h" // for Mouse namespace
#include "external/texture.h" // for Texture #include "external/texture.h" // for Texture
#include "shapes/atom_shape.h" // for AtomShape #include "shapes/atom_shape.h" // for AtomShape
#include "shapes/cube_shape.h" // for CubeShape #include "shapes/cube_shape.h" // for CubeShape
@@ -242,6 +243,9 @@ void Engine::calculateDeltaTime() {
} }
void Engine::update() { void Engine::update() {
// Actualizar visibilidad del cursor (auto-ocultar tras inactividad)
Mouse::updateCursorVisibility();
// Calcular FPS // Calcular FPS
fps_frame_count_++; fps_frame_count_++;
Uint64 current_time = SDL_GetTicks(); Uint64 current_time = SDL_GetTicks();
@@ -295,6 +299,9 @@ void Engine::update() {
void Engine::handleEvents() { void Engine::handleEvents() {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
// Procesar eventos de ratón (auto-ocultar cursor)
Mouse::handleEvent(event);
// Salir del bucle si se detecta una petición de cierre // Salir del bucle si se detecta una petición de cierre
if (event.type == SDL_EVENT_QUIT) { if (event.type == SDL_EVENT_QUIT) {
should_exit_ = true; should_exit_ = true;
@@ -623,6 +630,20 @@ void Engine::handleEvents() {
text_init_time_ = SDL_GetTicks(); text_init_time_ = SDL_GetTicks();
} }
break; break;
// Toggle Modo LOGO (easter egg - marca de agua)
case SDLK_K:
toggleLogoMode();
// Mostrar texto informativo
if (logo_mode_enabled_) {
text_ = "LOGO MODE ON";
} else {
text_ = "LOGO MODE OFF";
}
text_pos_ = (current_screen_width_ - static_cast<int>(text_.length() * 8)) / 2;
show_text_ = true;
text_init_time_ = SDL_GetTicks();
break;
} }
} }
} }
@@ -759,6 +780,21 @@ void Engine::render() {
mode_text = "MODE SHAPE"; mode_text = "MODE SHAPE";
} }
dbg_print(8, 72, mode_text.c_str(), 0, 255, 128); // Verde claro para modo dbg_print(8, 72, mode_text.c_str(), 0, 255, 128); // Verde claro para modo
// Debug: Mostrar modo DEMO/LOGO activo (siempre visible cuando debug está ON)
if (logo_mode_enabled_) {
int logo_text_width = 9 * 8; // "LOGO MODE" = 9 caracteres × 8 píxeles
int logo_x = (current_screen_width_ - logo_text_width) / 2;
dbg_print(logo_x, 80, "LOGO MODE", 255, 128, 0); // Naranja para Logo Mode
} else if (demo_mode_enabled_) {
int demo_text_width = 9 * 8; // "DEMO MODE" = 9 caracteres × 8 píxeles
int demo_x = (current_screen_width_ - demo_text_width) / 2;
dbg_print(demo_x, 80, "DEMO MODE", 255, 165, 0); // Naranja para DEMO
} else if (demo_lite_enabled_) {
int lite_text_width = 14 * 8; // "DEMO LITE MODE" = 14 caracteres × 8 píxeles
int lite_x = (current_screen_width_ - lite_text_width) / 2;
dbg_print(lite_x, 80, "DEMO LITE MODE", 255, 200, 0); // Amarillo-naranja para DEMO LITE
}
} }
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
@@ -860,6 +896,21 @@ void Engine::forceBallsGravityOn() {
} }
void Engine::forceBallsGravityOff() { void Engine::forceBallsGravityOff() {
// Contar cuántas pelotas están en superficie (suelo/techo/pared)
int balls_on_surface = 0;
for (const auto& ball : balls_) {
if (ball->isOnSurface()) {
balls_on_surface++;
}
}
// Si la mayoría (>50%) están en superficie, aplicar impulso para que se vea el efecto
float surface_ratio = static_cast<float>(balls_on_surface) / static_cast<float>(balls_.size());
if (surface_ratio > 0.5f) {
pushBallsAwayFromGravity(); // Dar impulso contrario a gravedad
}
// Desactivar gravedad
for (auto& ball : balls_) { for (auto& ball : balls_) {
ball->forceGravityOff(); ball->forceGravityOff();
} }
@@ -889,13 +940,6 @@ void Engine::toggleFullscreen() {
fullscreen_enabled_ = !fullscreen_enabled_; fullscreen_enabled_ = !fullscreen_enabled_;
SDL_SetWindowFullscreen(window_, fullscreen_enabled_); SDL_SetWindowFullscreen(window_, fullscreen_enabled_);
// Ocultar/mostrar cursor según modo fullscreen
if (fullscreen_enabled_) {
SDL_HideCursor();
} else {
SDL_ShowCursor();
}
} }
void Engine::toggleRealFullscreen() { void Engine::toggleRealFullscreen() {
@@ -930,9 +974,6 @@ void Engine::toggleRealFullscreen() {
} }
SDL_free(displays); SDL_free(displays);
} }
// Ocultar cursor en real fullscreen
SDL_HideCursor();
} else { } else {
// Volver a resolución base (configurada por CLI o default) // Volver a resolución base (configurada por CLI o default)
current_screen_width_ = base_screen_width_; current_screen_width_ = base_screen_width_;
@@ -947,9 +988,6 @@ void Engine::toggleRealFullscreen() {
// Reinicar la escena con resolución original // Reinicar la escena con resolución original
initBalls(scenario_); initBalls(scenario_);
// Mostrar cursor al salir de real fullscreen
SDL_ShowCursor();
} }
} }
@@ -1366,8 +1404,8 @@ Color Engine::getInterpolatedColor(size_t ball_index) const {
// Sistema de Modo DEMO (auto-play) // Sistema de Modo DEMO (auto-play)
void Engine::updateDemoMode() { void Engine::updateDemoMode() {
// Verificar si algún modo está activo // Verificar si algún modo está activo (DEMO, DEMO LITE o LOGO)
bool is_demo_active = demo_mode_enabled_ || demo_lite_enabled_; bool is_demo_active = demo_mode_enabled_ || demo_lite_enabled_ || logo_mode_enabled_;
if (!is_demo_active) return; if (!is_demo_active) return;
// Actualizar timer // Actualizar timer
@@ -1375,7 +1413,47 @@ void Engine::updateDemoMode() {
// Si es hora de ejecutar acción // Si es hora de ejecutar acción
if (demo_timer_ >= demo_next_action_time_) { if (demo_timer_ >= demo_next_action_time_) {
// Ejecutar acción según modo activo // MODO LOGO: Sistema de acciones variadas con gravedad dinámica
if (logo_mode_enabled_) {
// Elegir acción aleatoria ponderada
int action = rand() % 100;
if (current_mode_ == SimulationMode::SHAPE) {
// Logo quieto (formado) → 2 opciones posibles
if (action < 50) {
// 50%: SHAPE → PHYSICS con gravedad ON (caída dramática)
toggleShapeMode(true);
} else {
// 50%: SHAPE → PHYSICS con gravedad OFF (dar vueltas sin caer)
toggleShapeMode(false);
}
} else {
// Logo animado (PHYSICS) → 3 opciones posibles
if (action < 60) {
// 60%: PHYSICS → SHAPE (reconstruir logo y ver rotaciones)
toggleShapeMode(false);
} else if (action < 80) {
// 20%: Forzar gravedad ON (empezar a caer mientras da vueltas)
forceBallsGravityOn();
} else {
// 20%: Forzar gravedad OFF (flotar mientras da vueltas)
forceBallsGravityOff();
}
}
// Resetear timer con intervalos de Logo Mode
demo_timer_ = 0.0f;
float interval_range = LOGO_ACTION_INTERVAL_MAX - LOGO_ACTION_INTERVAL_MIN;
demo_next_action_time_ = LOGO_ACTION_INTERVAL_MIN + (rand() % 1000) / 1000.0f * interval_range;
// Solo salir automáticamente si NO es modo manual (tecla K)
// Probabilidad de salir: 25% en cada acción → promedio 4 acciones antes de salir
if (!logo_mode_is_manual_ && rand() % 100 < 25) {
exitLogoMode(true); // Volver a DEMO/DEMO_LITE
}
}
// MODO DEMO/DEMO_LITE: Acciones normales
else {
bool is_lite = demo_lite_enabled_; bool is_lite = demo_lite_enabled_;
performDemoAction(is_lite); performDemoAction(is_lite);
@@ -1389,8 +1467,38 @@ void Engine::updateDemoMode() {
demo_next_action_time_ = interval_min + (rand() % 1000) / 1000.0f * interval_range; demo_next_action_time_ = interval_min + (rand() % 1000) / 1000.0f * interval_range;
} }
} }
}
void Engine::performDemoAction(bool is_lite) { void Engine::performDemoAction(bool is_lite) {
// ============================================
// SALTO AUTOMÁTICO A LOGO MODE (Easter Egg)
// ============================================
if (is_lite) {
// DEMO LITE: Verificar condiciones para salto a Logo Mode
if (static_cast<int>(balls_.size()) >= LOGO_MODE_MIN_BALLS &&
current_theme_ == ColorTheme::MONOCHROME) {
// 10% probabilidad de saltar a Logo Mode
if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE) {
enterLogoMode(true); // Entrar desde DEMO
return;
}
}
} else {
// DEMO COMPLETO: Verificar condiciones para salto a Logo Mode
if (static_cast<int>(balls_.size()) >= LOGO_MODE_MIN_BALLS) {
// 15% probabilidad de saltar a Logo Mode
if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO) {
enterLogoMode(true); // Entrar desde DEMO
return;
}
}
}
// ============================================
// ACCIONES NORMALES DE DEMO/DEMO_LITE
// ============================================
int TOTAL_WEIGHT; int TOTAL_WEIGHT;
int random_value; int random_value;
int accumulated_weight = 0; int accumulated_weight = 0;
@@ -1415,11 +1523,11 @@ void Engine::performDemoAction(bool is_lite) {
return; return;
} }
// Activar figura 3D (25%) // Activar figura 3D (25%) - PNG_SHAPE excluido (reservado para Logo Mode)
accumulated_weight += DEMO_LITE_WEIGHT_SHAPE; accumulated_weight += DEMO_LITE_WEIGHT_SHAPE;
if (random_value < accumulated_weight) { if (random_value < accumulated_weight) {
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::WAVE_GRID, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM, ShapeType::PNG_SHAPE}; ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::WAVE_GRID, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
int shape_index = rand() % 9; int shape_index = rand() % 8;
activateShape(shapes[shape_index]); activateShape(shapes[shape_index]);
return; return;
} }
@@ -1458,11 +1566,11 @@ void Engine::performDemoAction(bool is_lite) {
return; return;
} }
// Activar figura 3D (20%) // Activar figura 3D (20%) - PNG_SHAPE excluido (reservado para Logo Mode)
accumulated_weight += DEMO_WEIGHT_SHAPE; accumulated_weight += DEMO_WEIGHT_SHAPE;
if (random_value < accumulated_weight) { if (random_value < accumulated_weight) {
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::WAVE_GRID, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM, ShapeType::PNG_SHAPE}; ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::WAVE_GRID, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
int shape_index = rand() % 9; int shape_index = rand() % 8;
activateShape(shapes[shape_index]); activateShape(shapes[shape_index]);
return; return;
} }
@@ -1629,6 +1737,125 @@ 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)
void Engine::enterLogoMode(bool from_demo) {
// Verificar mínimo de pelotas
if (static_cast<int>(balls_.size()) < LOGO_MODE_MIN_BALLS) {
// Ajustar a 5000 pelotas automáticamente
scenario_ = 5; // Escenario 5000 pelotas (índice 5 en BALL_COUNT_SCENARIOS)
initBalls(scenario_);
}
// Guardar estado previo (para restaurar al salir)
logo_previous_theme_ = current_theme_;
logo_previous_texture_index_ = current_texture_index_;
logo_previous_shape_scale_ = shape_scale_factor_;
// Buscar índice de textura "tiny"
size_t tiny_index = current_texture_index_; // Por defecto mantener actual
for (size_t i = 0; i < texture_names_.size(); i++) {
if (texture_names_[i] == "tiny") {
tiny_index = i;
break;
}
}
// Aplicar configuración fija del Modo Logo
if (tiny_index != current_texture_index_) {
current_texture_index_ = tiny_index;
int old_size = current_ball_size_;
current_ball_size_ = textures_[current_texture_index_]->getWidth();
updateBallSizes(old_size, current_ball_size_);
// Actualizar textura global y en cada pelota
texture_ = textures_[current_texture_index_];
for (auto& ball : balls_) {
ball->setTexture(texture_);
}
}
// Cambiar a tema MONOCHROME
startThemeTransition(ColorTheme::MONOCHROME);
// Establecer escala a 120%
shape_scale_factor_ = LOGO_MODE_SHAPE_SCALE;
clampShapeScale();
// Activar PNG_SHAPE (el logo)
activateShape(ShapeType::PNG_SHAPE);
// Activar modo logo
logo_mode_enabled_ = true;
// Marcar si es activación manual (tecla K) o automática (desde DEMO)
logo_mode_is_manual_ = !from_demo;
// Configurar timer para alternancia SHAPE/PHYSICS
demo_timer_ = 0.0f;
demo_next_action_time_ = LOGO_ACTION_INTERVAL_MIN +
(rand() % 1000) / 1000.0f * (LOGO_ACTION_INTERVAL_MAX - LOGO_ACTION_INTERVAL_MIN);
std::cout << "[LOGO MODE] Activado" << (from_demo ? " (desde DEMO)" : " (manual)") << "\n";
}
// Salir del Modo Logo (volver a estado anterior o salir de DEMO)
void Engine::exitLogoMode(bool return_to_demo) {
if (!logo_mode_enabled_) return;
// Restaurar estado previo
startThemeTransition(logo_previous_theme_);
if (logo_previous_texture_index_ != current_texture_index_ &&
logo_previous_texture_index_ < textures_.size()) {
current_texture_index_ = logo_previous_texture_index_;
int old_size = current_ball_size_;
current_ball_size_ = textures_[current_texture_index_]->getWidth();
updateBallSizes(old_size, current_ball_size_);
// Actualizar textura global y en cada pelota
texture_ = textures_[current_texture_index_];
for (auto& ball : balls_) {
ball->setTexture(texture_);
}
}
shape_scale_factor_ = logo_previous_shape_scale_;
clampShapeScale();
generateShape();
// Desactivar modo logo
logo_mode_enabled_ = false;
logo_mode_is_manual_ = false; // Resetear flag manual
if (!return_to_demo) {
// Salida manual (tecla K): desactivar todos los modos DEMO
demo_mode_enabled_ = false;
demo_lite_enabled_ = false;
} else {
// Volver a DEMO: reconfigurar timer
demo_timer_ = 0.0f;
demo_next_action_time_ = (demo_lite_enabled_ ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN) +
(rand() % 1000) / 1000.0f *
((demo_lite_enabled_ ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX) -
(demo_lite_enabled_ ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN));
}
std::cout << "[LOGO MODE] Desactivado" << (return_to_demo ? " (volviendo a DEMO)" : " (salida manual)") << "\n";
}
// Toggle manual del Modo Logo (tecla K)
void Engine::toggleLogoMode() {
if (logo_mode_enabled_) {
exitLogoMode(false); // Salir y desactivar DEMO
} else {
enterLogoMode(false); // Entrar manualmente
}
}
// Sistema de cambio de sprites dinámico // Sistema de cambio de sprites dinámico
void Engine::updateBallSizes(int old_size, int new_size) { void Engine::updateBallSizes(int old_size, int new_size) {
float delta_size = static_cast<float>(new_size - old_size); float delta_size = static_cast<float>(new_size - old_size);
@@ -1728,8 +1955,8 @@ void Engine::toggleShapeMode(bool force_gravity_on_exit) {
forceBallsGravityOn(); forceBallsGravityOn();
} }
// Mostrar texto informativo (solo si NO estamos en modo demo) // Mostrar texto informativo (solo si NO estamos en modo demo o logo)
if (!demo_mode_enabled_ && !demo_lite_enabled_) { if (!demo_mode_enabled_ && !demo_lite_enabled_ && !logo_mode_enabled_) {
text_ = "MODO FISICA"; text_ = "MODO FISICA";
int text_width = static_cast<int>(text_.length() * 8); int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2; text_pos_ = (current_screen_width_ - text_width) / 2;
@@ -1793,8 +2020,8 @@ void Engine::activateShape(ShapeType type) {
ball->enableRotoBallAttraction(true); ball->enableRotoBallAttraction(true);
} }
// Mostrar texto informativo con nombre de figura (solo si NO estamos en modo demo) // Mostrar texto informativo con nombre de figura (solo si NO estamos en modo demo o logo)
if (active_shape_ && !demo_mode_enabled_ && !demo_lite_enabled_) { if (active_shape_ && !demo_mode_enabled_ && !demo_lite_enabled_ && !logo_mode_enabled_) {
text_ = std::string("MODO ") + active_shape_->getName(); text_ = std::string("MODO ") + active_shape_->getName();
int text_width = static_cast<int>(text_.length() * 8); int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2; text_pos_ = (current_screen_width_ - text_width) / 2;

View File

@@ -103,6 +103,7 @@ class Engine {
bool demo_mode_enabled_ = false; // ¿Está activo el modo demo completo? bool demo_mode_enabled_ = false; // ¿Está activo el modo demo completo?
bool demo_lite_enabled_ = false; // ¿Está activo el modo demo lite? bool demo_lite_enabled_ = false; // ¿Está activo el modo demo lite?
bool logo_mode_enabled_ = false; // ¿Está activo el modo logo (easter egg)? bool logo_mode_enabled_ = false; // ¿Está activo el modo logo (easter egg)?
bool logo_mode_is_manual_ = false; // ¿Logo Mode activado manualmente (tecla K)?
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)

27
source/external/mouse.cpp vendored Normal file
View File

@@ -0,0 +1,27 @@
#include "mouse.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_HideCursor, SDL_ShowCursor
namespace Mouse {
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
bool cursor_visible = true; // Estado del cursor
void handleEvent(const SDL_Event &event) {
if (event.type == SDL_EVENT_MOUSE_MOTION) {
last_mouse_move_time = SDL_GetTicks();
if (!cursor_visible) {
SDL_ShowCursor();
cursor_visible = true;
}
}
}
void updateCursorVisibility() {
Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
SDL_HideCursor();
cursor_visible = false;
}
}
} // namespace Mouse

15
source/external/mouse.h vendored Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <SDL3/SDL.h> // Para Uint32, SDL_Event
// --- Namespace Mouse: gestión del ratón ---
namespace Mouse {
// --- Variables de estado del cursor ---
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor tras inactividad
extern Uint32 last_mouse_move_time; // Última vez (en ms) que el ratón se movió
extern bool cursor_visible; // Indica si el cursor está visible
// --- Funciones ---
void handleEvent(const SDL_Event &event); // Procesa eventos de ratón (movimiento, clic, etc.)
void updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad
} // namespace Mouse