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:
50
ROADMAP.md
50
ROADMAP.md
@@ -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 |
@@ -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 (%)
|
||||||
|
|||||||
@@ -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,22 +1413,92 @@ 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
|
||||||
bool is_lite = demo_lite_enabled_;
|
if (logo_mode_enabled_) {
|
||||||
performDemoAction(is_lite);
|
// Elegir acción aleatoria ponderada
|
||||||
|
int action = rand() % 100;
|
||||||
|
|
||||||
// Resetear timer y calcular próximo intervalo aleatorio
|
if (current_mode_ == SimulationMode::SHAPE) {
|
||||||
demo_timer_ = 0.0f;
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Usar intervalos diferentes según modo
|
// Resetear timer con intervalos de Logo Mode
|
||||||
float interval_min = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
|
demo_timer_ = 0.0f;
|
||||||
float interval_max = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
|
float interval_range = LOGO_ACTION_INTERVAL_MAX - LOGO_ACTION_INTERVAL_MIN;
|
||||||
float interval_range = interval_max - interval_min;
|
demo_next_action_time_ = LOGO_ACTION_INTERVAL_MIN + (rand() % 1000) / 1000.0f * interval_range;
|
||||||
demo_next_action_time_ = 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_;
|
||||||
|
performDemoAction(is_lite);
|
||||||
|
|
||||||
|
// Resetear timer y calcular próximo intervalo aleatorio
|
||||||
|
demo_timer_ = 0.0f;
|
||||||
|
|
||||||
|
// Usar intervalos diferentes según modo
|
||||||
|
float interval_min = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
|
||||||
|
float interval_max = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
|
||||||
|
float interval_range = interval_max - interval_min;
|
||||||
|
demo_next_action_time_ = interval_min + (rand() % 1000) / 1000.0f * interval_range;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void 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;
|
||||||
|
|||||||
@@ -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
27
source/external/mouse.cpp
vendored
Normal 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
15
source/external/mouse.h
vendored
Normal 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
|
||||||
Reference in New Issue
Block a user