**Problema:**
Cuando se iniciaba con `-m demo`, `-m demo-lite` o `-m logo`, se llamaba
a `setState()` directamente, que es un método de bajo nivel que solo
cambia el estado interno SIN ejecutar las acciones de configuración.
**Resultado del bug:**
- `-m demo`: NO aleatorizaba (tema default, primer escenario)
- `-m demo-lite`: NO aleatorizaba física
- `-m logo`: NO configuraba tema, PNG_SHAPE, ni pelotas pequeñas
**Arquitectura correcta:**
- `setState()` = Método primitivo bajo nivel (solo cambia estado)
- `toggleDemoMode()` = Método alto nivel (setState + randomize)
- `toggleDemoLiteMode()` = Método alto nivel (setState + randomize)
- `enterLogoMode()` = Método alto nivel (setState + configuración completa)
**Solución implementada:**
En lugar de llamar a setState() directamente, usar los métodos de
alto nivel que ejecutan las acciones de configuración:
```cpp
if (initial_mode == AppMode::DEMO) {
state_manager_->toggleDemoMode(...); // Entra a DEMO + randomiza
}
else if (initial_mode == AppMode::DEMO_LITE) {
state_manager_->toggleDemoLiteMode(...); // Entra a DEMO_LITE + randomiza
}
else if (initial_mode == AppMode::LOGO) {
state_manager_->enterLogoMode(...); // Entra a LOGO + configura todo
}
```
**Archivos modificados:**
- source/engine.cpp (líneas 249-263):
- Reemplazado setState() por toggleDemoMode/toggleDemoLiteMode/enterLogoMode
- Agregados comentarios explicativos
**Resultado esperado:**
- ✅ `-m demo` → Aleatoriza todo como si pulsaras D
- ✅ `-m demo-lite` → Aleatoriza física como si pulsaras Shift+D
- ✅ `-m logo` → Configura tema/PNG_SHAPE/pelotas como si pulsaras K
- ✅ Comportamiento consistente entre CLI y teclas
- ✅ Arquitectura correcta: alto nivel para acciones, bajo nivel para estado
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
375 lines
21 KiB
C++
375 lines
21 KiB
C++
#pragma once
|
||
|
||
#include <SDL3/SDL_stdinc.h> // for Uint64
|
||
|
||
#include <vector> // for std::vector in DynamicThemeKeyframe/DynamicTheme
|
||
|
||
// Configuración de ventana y pantalla
|
||
constexpr char WINDOW_CAPTION[] = "ViBe3 Physics (JailDesigner 2025)";
|
||
|
||
// Resolución por defecto (usada si no se especifica en CLI)
|
||
constexpr int DEFAULT_SCREEN_WIDTH = 320; // Ancho lógico por defecto (si no hay -w)
|
||
constexpr int DEFAULT_SCREEN_HEIGHT = 240; // Alto lógico por defecto (si no hay -h)
|
||
constexpr int DEFAULT_WINDOW_ZOOM = 3; // Zoom inicial de ventana (1x = sin zoom)
|
||
|
||
// Configuración de zoom dinámico de ventana
|
||
constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240)
|
||
constexpr int WINDOW_ZOOM_MAX = 10; // Zoom máximo teórico (3200x2400)
|
||
constexpr int WINDOW_DESKTOP_MARGIN = 10; // Margen mínimo con bordes del escritorio
|
||
constexpr int WINDOW_DECORATION_HEIGHT = 30; // Altura estimada de decoraciones del SO
|
||
|
||
// Configuración de física
|
||
constexpr float GRAVITY_FORCE = 0.2f; // Fuerza de gravedad (píxeles/frame²)
|
||
|
||
// Configuración de interfaz
|
||
constexpr Uint64 TEXT_DURATION = 2000; // Duración del texto informativo (ms) - OBSOLETO, usar NOTIFICATION_DURATION
|
||
constexpr float THEME_TRANSITION_DURATION = 0.5f; // Duración de transiciones LERP entre temas (segundos)
|
||
|
||
// Configuración de notificaciones (sistema Notifier)
|
||
constexpr int TEXT_ABSOLUTE_SIZE = 12; // Tamaño fuente base en píxeles físicos (múltiplo de 12px, tamaño nativo de la fuente)
|
||
constexpr Uint64 NOTIFICATION_DURATION = 2000; // Duración default de notificaciones (ms)
|
||
constexpr Uint64 NOTIFICATION_SLIDE_TIME = 300; // Duración animación entrada (ms)
|
||
constexpr Uint64 NOTIFICATION_FADE_TIME = 200; // Duración animación salida (ms)
|
||
constexpr float NOTIFICATION_BG_ALPHA = 0.7f; // Opacidad fondo semitransparente (0.0-1.0)
|
||
constexpr int NOTIFICATION_PADDING = 10; // Padding interno del fondo (píxeles físicos)
|
||
constexpr int NOTIFICATION_TOP_MARGIN = 20; // Margen superior desde borde pantalla (píxeles físicos)
|
||
|
||
// Configuración de pérdida aleatoria en rebotes
|
||
constexpr float BASE_BOUNCE_COEFFICIENT = 0.75f; // Coeficiente base IGUAL para todas las pelotas
|
||
constexpr float BOUNCE_RANDOM_LOSS_PERCENT = 0.1f; // 0-10% pérdida adicional aleatoria en cada rebote
|
||
constexpr float LATERAL_LOSS_PERCENT = 0.02f; // ±2% pérdida lateral en rebotes
|
||
|
||
// Configuración de masa/peso individual por pelota
|
||
constexpr float GRAVITY_MASS_MIN = 0.7f; // Factor mínimo de masa (pelota ligera - 70% gravedad)
|
||
constexpr float GRAVITY_MASS_MAX = 1.3f; // Factor máximo de masa (pelota pesada - 130% gravedad)
|
||
|
||
// Configuración de velocidad lateral al cambiar gravedad (muy sutil)
|
||
constexpr float GRAVITY_CHANGE_LATERAL_MIN = 0.04f; // Velocidad lateral mínima (2.4 px/s)
|
||
constexpr float GRAVITY_CHANGE_LATERAL_MAX = 0.08f; // Velocidad lateral máxima (4.8 px/s)
|
||
|
||
// Configuración de spawn inicial de pelotas
|
||
constexpr float BALL_SPAWN_MARGIN = 0.15f; // Margen lateral para spawn (0.25 = 25% a cada lado)
|
||
|
||
// Escenarios de número de pelotas (teclas 1-8)
|
||
constexpr int BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50000};
|
||
|
||
// Estructura para representar colores RGB
|
||
struct Color {
|
||
int r, g, b; // Componentes rojo, verde, azul (0-255)
|
||
};
|
||
|
||
// Estructura de tema de colores estático
|
||
struct ThemeColors {
|
||
const char* name_en; // Nombre en inglés (para debug)
|
||
const char* name_es; // Nombre en español (para display)
|
||
int text_color_r, text_color_g, text_color_b; // Color del texto del tema
|
||
float bg_top_r, bg_top_g, bg_top_b;
|
||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||
std::vector<Color> ball_colors;
|
||
};
|
||
|
||
// Estructura para keyframe de tema dinámico
|
||
struct DynamicThemeKeyframe {
|
||
// Fondo degradado
|
||
float bg_top_r, bg_top_g, bg_top_b;
|
||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||
|
||
// Color de fondo de notificaciones
|
||
int notif_bg_r, notif_bg_g, notif_bg_b;
|
||
|
||
// Colores de pelotas en este keyframe
|
||
std::vector<Color> ball_colors;
|
||
|
||
// Duración de transición HACIA este keyframe (segundos)
|
||
// 0.0 = estado inicial (sin transición)
|
||
float duration;
|
||
};
|
||
|
||
// NOTA: La clase DynamicTheme (tema dinámico animado) está definida en themes/dynamic_theme.h
|
||
// Esta estructura de datos es solo para definir keyframes que se pasan al constructor
|
||
|
||
// Enum para dirección de gravedad
|
||
enum class GravityDirection {
|
||
DOWN, // ↓ Gravedad hacia abajo (por defecto)
|
||
UP, // ↑ Gravedad hacia arriba
|
||
LEFT, // ← Gravedad hacia la izquierda
|
||
RIGHT // → Gravedad hacia la derecha
|
||
};
|
||
|
||
// Enum para temas de colores (seleccionables con teclado numérico y Shift+Numpad)
|
||
// Todos los temas usan ahora sistema dinámico de keyframes
|
||
enum class ColorTheme {
|
||
SUNSET = 0, // Naranjas, rojos, amarillos, rosas (estático: 1 keyframe)
|
||
OCEAN = 1, // Azules, turquesas, blancos (estático: 1 keyframe)
|
||
NEON = 2, // Cian, magenta, verde lima, amarillo vibrante (estático: 1 keyframe)
|
||
FOREST = 3, // Verdes, marrones, amarillos otoño (estático: 1 keyframe)
|
||
RGB = 4, // RGB puros y subdivisiones matemáticas - fondo blanco (estático: 1 keyframe)
|
||
MONOCHROME = 5, // Fondo negro degradado, sprites blancos monocromáticos (estático: 1 keyframe)
|
||
LAVENDER = 6, // Degradado violeta-azul, pelotas amarillo dorado (estático: 1 keyframe)
|
||
CRIMSON = 7, // Fondo negro-rojo, pelotas rojas uniformes (estático: 1 keyframe)
|
||
EMERALD = 8, // Fondo negro-verde, pelotas verdes uniformes (estático: 1 keyframe)
|
||
SUNRISE = 9, // Amanecer: Noche → Alba → Día (animado: 4 keyframes, 12s ciclo)
|
||
OCEAN_WAVES = 10, // Olas oceánicas: Azul oscuro ↔ Turquesa (animado: 3 keyframes, 8s ciclo)
|
||
NEON_PULSE = 11, // Pulso neón: Negro ↔ Neón vibrante (animado: 3 keyframes, 3s ping-pong)
|
||
FIRE = 12, // Fuego vivo: Brasas → Llamas → Inferno (animado: 4 keyframes, 10s ciclo)
|
||
AURORA = 13, // Aurora boreal: Verde → Violeta → Cian (animado: 4 keyframes, 14s ciclo)
|
||
VOLCANIC = 14 // Erupción volcánica: Ceniza → Erupción → Lava (animado: 4 keyframes, 12s ciclo)
|
||
};
|
||
|
||
// Enum para tipo de figura 3D
|
||
enum class ShapeType {
|
||
NONE, // Sin figura (modo física pura)
|
||
SPHERE, // Esfera Fibonacci (antiguo RotoBall)
|
||
CUBE, // Cubo rotante
|
||
HELIX, // Espiral 3D
|
||
TORUS, // Toroide/donut
|
||
LISSAJOUS, // Malla ondeante
|
||
CYLINDER, // Cilindro rotante
|
||
ICOSAHEDRON, // Icosaedro D20
|
||
ATOM, // Átomo con órbitas
|
||
PNG_SHAPE // Forma cargada desde PNG 1-bit
|
||
};
|
||
|
||
// Enum para modo de simulación
|
||
enum class SimulationMode {
|
||
PHYSICS, // Modo física normal con gravedad
|
||
SHAPE, // Modo figura 3D (Shape polimórfico)
|
||
BOIDS // Modo enjambre (Boids - comportamiento emergente)
|
||
};
|
||
|
||
// Enum para modo de aplicación (mutuamente excluyentes)
|
||
enum class AppMode {
|
||
SANDBOX, // Control manual del usuario (modo sandbox)
|
||
DEMO, // Modo demo completo (auto-play)
|
||
DEMO_LITE, // Modo demo lite (solo física/figuras)
|
||
LOGO // Modo logo (easter egg)
|
||
};
|
||
|
||
// Enum para modo de escalado en fullscreen (F5)
|
||
enum class ScalingMode {
|
||
INTEGER, // Escalado entero con barras negras (mantiene aspecto + píxel perfecto)
|
||
LETTERBOX, // Zoom hasta llenar una dimensión (una barra desaparece)
|
||
STRETCH // Estirar para llenar pantalla completa (puede distorsionar aspecto)
|
||
};
|
||
|
||
// Configuración de RotoBall (esfera 3D rotante)
|
||
constexpr float ROTOBALL_RADIUS_FACTOR = 0.333f; // Radio como proporción de altura de pantalla (80/240 ≈ 0.333)
|
||
constexpr float ROTOBALL_ROTATION_SPEED_Y = 1.5f; // Velocidad rotación eje Y (rad/s)
|
||
constexpr float ROTOBALL_ROTATION_SPEED_X = 0.8f; // Velocidad rotación eje X (rad/s)
|
||
constexpr float ROTOBALL_TRANSITION_TIME = 1.5f; // Tiempo de transición (segundos)
|
||
constexpr int ROTOBALL_MIN_BRIGHTNESS = 50; // Brillo mínimo (fondo, 0-255)
|
||
constexpr int ROTOBALL_MAX_BRIGHTNESS = 255; // Brillo máximo (frente, 0-255)
|
||
|
||
// Física de atracción para figuras 3D (sistema de resorte)
|
||
// SHAPE: Figuras 3D normales (Q/W/E/R/T/Y/U/I/O) - Mayor pegajosidad
|
||
constexpr float SHAPE_SPRING_K = 800.0f; // Rigidez alta (pelotas más "pegadas")
|
||
constexpr float SHAPE_DAMPING_BASE = 60.0f; // Amortiguación alta (menos rebote)
|
||
constexpr float SHAPE_DAMPING_NEAR = 150.0f; // Absorción muy rápida al llegar
|
||
constexpr float SHAPE_NEAR_THRESHOLD = 8.0f; // Umbral "cerca" más amplio
|
||
constexpr float SHAPE_MAX_FORCE = 2000.0f; // Permite fuerzas más fuertes
|
||
|
||
// Configuración del Cubo (cubo 3D rotante)
|
||
constexpr float CUBE_SIZE_FACTOR = 0.25f; // Tamaño como proporción de altura (60/240 = 0.25)
|
||
constexpr float CUBE_ROTATION_SPEED_X = 0.5f; // Velocidad rotación eje X (rad/s)
|
||
constexpr float CUBE_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s)
|
||
constexpr float CUBE_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s)
|
||
|
||
// Configuración de Helix (espiral helicoidal 3D)
|
||
constexpr float HELIX_RADIUS_FACTOR = 0.25f; // Radio de la espiral (proporción de altura)
|
||
constexpr float HELIX_PITCH_FACTOR = 0.25f; // Separación vertical entre vueltas (proporción de altura)
|
||
constexpr float HELIX_NUM_TURNS = 3.0f; // Número de vueltas completas (1-5)
|
||
constexpr float HELIX_ROTATION_SPEED_Y = 1.2f; // Velocidad rotación eje Y (rad/s)
|
||
constexpr float HELIX_PHASE_SPEED = 0.5f; // Velocidad de animación vertical (rad/s)
|
||
|
||
// Configuración de Lissajous Curve 3D (curva paramétrica)
|
||
constexpr float LISSAJOUS_SIZE_FACTOR = 0.35f; // Amplitud de la curva (proporción de altura)
|
||
constexpr float LISSAJOUS_FREQ_X = 3.0f; // Frecuencia en eje X (ratio 3:2:1)
|
||
constexpr float LISSAJOUS_FREQ_Y = 2.0f; // Frecuencia en eje Y
|
||
constexpr float LISSAJOUS_FREQ_Z = 1.0f; // Frecuencia en eje Z
|
||
constexpr float LISSAJOUS_PHASE_SPEED = 1.0f; // Velocidad de animación de fase (rad/s)
|
||
constexpr float LISSAJOUS_ROTATION_SPEED_X = 0.4f; // Velocidad rotación global X (rad/s)
|
||
constexpr float LISSAJOUS_ROTATION_SPEED_Y = 0.6f; // Velocidad rotación global Y (rad/s)
|
||
|
||
// Configuración de Torus (toroide/donut 3D)
|
||
constexpr float TORUS_MAJOR_RADIUS_FACTOR = 0.25f; // Radio mayor R (centro torus a centro tubo)
|
||
constexpr float TORUS_MINOR_RADIUS_FACTOR = 0.12f; // Radio menor r (grosor del tubo)
|
||
constexpr float TORUS_ROTATION_SPEED_X = 0.6f; // Velocidad rotación eje X (rad/s)
|
||
constexpr float TORUS_ROTATION_SPEED_Y = 0.9f; // Velocidad rotación eje Y (rad/s)
|
||
constexpr float TORUS_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s)
|
||
|
||
// Configuración de Cylinder (cilindro 3D)
|
||
constexpr float CYLINDER_RADIUS_FACTOR = 0.25f; // Radio del cilindro (proporción de altura)
|
||
constexpr float CYLINDER_HEIGHT_FACTOR = 0.5f; // Altura del cilindro (proporción de altura)
|
||
constexpr float CYLINDER_ROTATION_SPEED_Y = 1.0f; // Velocidad rotación eje Y (rad/s)
|
||
|
||
// Configuración de Icosahedron (icosaedro D20)
|
||
constexpr float ICOSAHEDRON_RADIUS_FACTOR = 0.30f; // Radio de la esfera circunscrita
|
||
constexpr float ICOSAHEDRON_ROTATION_SPEED_X = 0.4f; // Velocidad rotación eje X (rad/s)
|
||
constexpr float ICOSAHEDRON_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s)
|
||
constexpr float ICOSAHEDRON_ROTATION_SPEED_Z = 0.2f; // Velocidad rotación eje Z (rad/s)
|
||
|
||
// Configuración de Atom (núcleo con órbitas electrónicas)
|
||
constexpr float ATOM_NUCLEUS_RADIUS_FACTOR = 0.08f; // Radio del núcleo central
|
||
constexpr float ATOM_ORBIT_RADIUS_FACTOR = 0.30f; // Radio de las órbitas
|
||
constexpr float ATOM_NUM_ORBITS = 3; // Número de órbitas
|
||
constexpr float ATOM_ORBIT_ROTATION_SPEED = 2.0f; // Velocidad de electrones (rad/s)
|
||
constexpr float ATOM_ROTATION_SPEED_Y = 0.5f; // Velocidad rotación global (rad/s)
|
||
|
||
// Configuración de PNG Shape (forma desde imagen PNG 1-bit)
|
||
constexpr float PNG_SIZE_FACTOR = 0.8f; // Tamaño como proporción de altura (80% pantalla)
|
||
constexpr float PNG_EXTRUSION_DEPTH_FACTOR = 0.12f; // Profundidad de extrusión (compacta)
|
||
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
|
||
// Rotación "legible" (texto de frente con volteretas ocasionales)
|
||
constexpr float PNG_IDLE_TIME_MIN = 0.5f; // Tiempo mínimo de frente (segundos) - modo MANUAL
|
||
constexpr float PNG_IDLE_TIME_MAX = 2.0f; // Tiempo máximo de frente (segundos) - modo MANUAL
|
||
constexpr float PNG_IDLE_TIME_MIN_LOGO = 2.0f; // Tiempo mínimo de frente en LOGO MODE
|
||
constexpr float PNG_IDLE_TIME_MAX_LOGO = 4.0f; // Tiempo máximo de frente en LOGO MODE
|
||
constexpr float PNG_FLIP_SPEED = 3.0f; // Velocidad voltereta (rad/s)
|
||
constexpr float PNG_FLIP_DURATION = 1.5f; // Duración voltereta (segundos)
|
||
|
||
// Control manual de escala de figuras 3D (Numpad +/-)
|
||
constexpr float SHAPE_SCALE_MIN = 0.3f; // Escala mínima (30%)
|
||
constexpr float SHAPE_SCALE_MAX = 3.0f; // Escala máxima (300%)
|
||
constexpr float SHAPE_SCALE_STEP = 0.1f; // Incremento por pulsación
|
||
constexpr float SHAPE_SCALE_DEFAULT = 1.0f; // Escala por defecto (100%)
|
||
|
||
// Configuración de Modo DEMO (auto-play completo)
|
||
constexpr float DEMO_ACTION_INTERVAL_MIN = 2.0f; // Tiempo mínimo entre acciones (segundos)
|
||
constexpr float DEMO_ACTION_INTERVAL_MAX = 6.0f; // Tiempo máximo entre acciones (segundos)
|
||
|
||
// Pesos de probabilidad DEMO MODE (valores relativos, se normalizan)
|
||
constexpr int DEMO_WEIGHT_GRAVITY_DIR = 12; // Cambiar dirección gravedad (12%)
|
||
constexpr int DEMO_WEIGHT_GRAVITY_TOGGLE = 15; // Toggle gravedad ON/OFF (15%) - ¡Ver caer pelotas!
|
||
constexpr int DEMO_WEIGHT_SHAPE = 22; // Activar figura 3D (22%) - Construir figuras
|
||
constexpr int DEMO_WEIGHT_TOGGLE_PHYSICS = 18; // Toggle física ↔ figura (18%) - ¡Destruir figuras!
|
||
constexpr int DEMO_WEIGHT_REGENERATE_SHAPE = 10; // Re-generar misma figura (10%) - Reconstruir
|
||
constexpr int DEMO_WEIGHT_THEME = 12; // Cambiar tema de colores (12%)
|
||
constexpr int DEMO_WEIGHT_SCENARIO = 2; // Cambiar número de pelotas (2%) - MUY OCASIONAL
|
||
constexpr int DEMO_WEIGHT_IMPULSE = 6; // Aplicar impulso (SPACE) (6%)
|
||
constexpr int DEMO_WEIGHT_DEPTH_ZOOM = 1; // Toggle profundidad (1%)
|
||
constexpr int DEMO_WEIGHT_SHAPE_SCALE = 1; // Cambiar escala figura (1%)
|
||
constexpr int DEMO_WEIGHT_SPRITE = 1; // Cambiar sprite (1%)
|
||
// TOTAL: 100
|
||
|
||
// Configuración de Modo DEMO LITE (solo física/figuras)
|
||
constexpr float DEMO_LITE_ACTION_INTERVAL_MIN = 1.5f; // Más rápido que demo completo
|
||
constexpr float DEMO_LITE_ACTION_INTERVAL_MAX = 4.0f;
|
||
|
||
// Pesos de probabilidad DEMO LITE (solo física/figuras, sin cambios de escenario/tema)
|
||
constexpr int DEMO_LITE_WEIGHT_GRAVITY_DIR = 25; // Cambiar dirección gravedad (25%)
|
||
constexpr int DEMO_LITE_WEIGHT_GRAVITY_TOGGLE = 20; // Toggle gravedad ON/OFF (20%)
|
||
constexpr int DEMO_LITE_WEIGHT_SHAPE = 25; // Activar figura 3D (25%)
|
||
constexpr int DEMO_LITE_WEIGHT_TOGGLE_PHYSICS = 20; // Toggle física ↔ figura (20%)
|
||
constexpr int DEMO_LITE_WEIGHT_IMPULSE = 10; // Aplicar impulso (10%)
|
||
// TOTAL: 100
|
||
|
||
// 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 float LOGO_MODE_SHAPE_SCALE = 1.2f; // Escala de figura en modo logo (120%)
|
||
constexpr float LOGO_ACTION_INTERVAL_MIN = 3.0f; // Tiempo mínimo entre alternancia SHAPE/PHYSICS (escalado con resolución)
|
||
constexpr float LOGO_ACTION_INTERVAL_MAX = 5.0f; // Tiempo máximo entre alternancia SHAPE/PHYSICS (escalado con resolución)
|
||
constexpr int LOGO_WEIGHT_TOGGLE_PHYSICS = 100; // Único peso: alternar SHAPE ↔ PHYSICS (100%)
|
||
|
||
// Sistema de convergencia para LOGO MODE (evita interrupciones prematuras en resoluciones altas)
|
||
constexpr float LOGO_CONVERGENCE_MIN = 0.75f; // 75% mínimo (permite algo de movimiento al disparar)
|
||
constexpr float LOGO_CONVERGENCE_MAX = 1.00f; // 100% máximo (completamente formado)
|
||
constexpr float LOGO_CONVERGENCE_DISTANCE = 20.0f; // Distancia (px) para considerar pelota "convergida" (más permisivo que SHAPE_NEAR)
|
||
|
||
// Probabilidad de salto a Logo Mode desde DEMO/DEMO_LITE (%)
|
||
// Relación DEMO:LOGO = 6:1 (pasa 6x más tiempo en DEMO que en LOGO)
|
||
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO = 5; // 5% probabilidad en DEMO normal (más raro)
|
||
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE = 3; // 3% probabilidad en DEMO LITE (aún más raro)
|
||
|
||
// Sistema de espera de flips en LOGO MODE (camino alternativo de decisión)
|
||
constexpr int LOGO_FLIP_WAIT_MIN = 1; // Mínimo de flips a esperar antes de cambiar a PHYSICS
|
||
constexpr int LOGO_FLIP_WAIT_MAX = 3; // Máximo de flips a esperar
|
||
constexpr float LOGO_FLIP_TRIGGER_MIN = 0.20f; // 20% mínimo de progreso de flip para trigger
|
||
constexpr float LOGO_FLIP_TRIGGER_MAX = 0.80f; // 80% máximo de progreso de flip para trigger
|
||
constexpr int LOGO_FLIP_WAIT_PROBABILITY = 50; // 50% probabilidad de elegir el camino "esperar flip"
|
||
|
||
// Configuración de AppLogo (logo periódico en pantalla)
|
||
constexpr float APPLOGO_DISPLAY_INTERVAL = 120.0f; // Intervalo entre apariciones del logo (segundos)
|
||
constexpr float APPLOGO_DISPLAY_DURATION = 30.0f; // Duración de visibilidad del logo (segundos)
|
||
constexpr float APPLOGO_ANIMATION_DURATION = 0.5f; // Duración de animación entrada/salida (segundos)
|
||
constexpr float APPLOGO_HEIGHT_PERCENT = 0.4f; // Altura del logo = 40% de la altura de pantalla
|
||
constexpr float APPLOGO_PADDING_PERCENT = 0.05f; // Padding desde esquina inferior-derecha = 10%
|
||
constexpr float APPLOGO_LOGO2_DELAY = 0.25f; // Retraso de Logo 2 respecto a Logo 1 (segundos)
|
||
|
||
// Configuración de Modo BOIDS (comportamiento de enjambre)
|
||
// TIME-BASED CONVERSION (frame-based → time-based):
|
||
// - Radios: sin cambios (píxeles)
|
||
// - Velocidades (MAX_SPEED, MIN_SPEED): ×60 (px/frame → px/s)
|
||
// - Aceleraciones puras (SEPARATION, COHESION): ×60² = ×3600 (px/frame² → px/s²)
|
||
// - Steering proporcional (ALIGNMENT): ×60 (proporcional a velocidad)
|
||
// - Límite velocidad (MAX_FORCE): ×60 (px/frame → px/s)
|
||
constexpr float BOID_SEPARATION_RADIUS = 30.0f; // Radio para evitar colisiones (píxeles)
|
||
constexpr float BOID_ALIGNMENT_RADIUS = 50.0f; // Radio para alinear velocidad con vecinos
|
||
constexpr float BOID_COHESION_RADIUS = 80.0f; // Radio para moverse hacia centro del grupo
|
||
constexpr float BOID_SEPARATION_WEIGHT = 5400.0f; // Aceleración de separación (px/s²) [era 1.5 × 3600]
|
||
constexpr float BOID_ALIGNMENT_WEIGHT = 60.0f; // Steering de alineación (proporcional) [era 1.0 × 60]
|
||
constexpr float BOID_COHESION_WEIGHT = 3.6f; // Aceleración de cohesión (px/s²) [era 0.001 × 3600]
|
||
constexpr float BOID_MAX_SPEED = 150.0f; // Velocidad máxima (px/s) [era 2.5 × 60]
|
||
constexpr float BOID_MAX_FORCE = 3.0f; // Fuerza máxima de steering (px/s) [era 0.05 × 60]
|
||
constexpr float BOID_MIN_SPEED = 18.0f; // Velocidad mínima (px/s) [era 0.3 × 60]
|
||
constexpr float BOID_BOUNDARY_MARGIN = 50.0f; // Distancia a borde para activar repulsión (píxeles)
|
||
constexpr float BOID_BOUNDARY_WEIGHT = 7200.0f; // Aceleración de repulsión de bordes (px/s²) [más fuerte que separation]
|
||
|
||
// FASE 2: Spatial Hash Grid para optimización O(n²) → O(n)
|
||
constexpr float BOID_GRID_CELL_SIZE = 100.0f; // Tamaño de celda del grid (píxeles)
|
||
// Debe ser ≥ BOID_COHESION_RADIUS para funcionar correctamente
|
||
|
||
constexpr float PI = 3.14159265358979323846f; // Constante PI
|
||
|
||
// Función auxiliar para obtener la ruta del directorio del ejecutable
|
||
#include <filesystem>
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#elif defined(__APPLE__)
|
||
#include <limits.h>
|
||
#include <mach-o/dyld.h>
|
||
#else
|
||
#include <limits.h>
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
inline std::string getExecutableDirectory() {
|
||
#ifdef _WIN32
|
||
char buffer[MAX_PATH];
|
||
GetModuleFileNameA(NULL, buffer, MAX_PATH);
|
||
std::filesystem::path exe_path(buffer);
|
||
return exe_path.parent_path().string();
|
||
#elif defined(__APPLE__)
|
||
char buffer[PATH_MAX];
|
||
uint32_t size = sizeof(buffer);
|
||
if (_NSGetExecutablePath(buffer, &size) == 0) {
|
||
std::filesystem::path exe_path(buffer);
|
||
return exe_path.parent_path().string();
|
||
}
|
||
return ".";
|
||
#else
|
||
// Linux y otros Unix
|
||
char buffer[PATH_MAX];
|
||
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
|
||
if (len != -1) {
|
||
buffer[len] = '\0';
|
||
std::filesystem::path exe_path(buffer);
|
||
return exe_path.parent_path().string();
|
||
}
|
||
return ".";
|
||
#endif
|
||
}
|
||
|
||
// Función auxiliar para obtener la ruta del directorio de recursos
|
||
inline std::string getResourcesDirectory() {
|
||
std::string exe_dir = getExecutableDirectory();
|
||
|
||
#ifdef MACOS_BUNDLE
|
||
// En macOS Bundle: ejecutable está en Contents/MacOS/, recursos en Contents/Resources/
|
||
std::filesystem::path resources_path = std::filesystem::path(exe_dir) / ".." / "Resources";
|
||
return resources_path.string();
|
||
#else
|
||
// En desarrollo o releases normales: recursos están junto al ejecutable
|
||
return exe_dir;
|
||
#endif
|
||
} |