Files
vibe3_physics/CLAUDE.md

18 KiB

Claude Code Session - ViBe3 Physics

Estado del Proyecto

Proyecto: ViBe3 Physics - Simulador de sprites con físicas avanzadas Objetivo: Implementar nuevas físicas experimentales expandiendo sobre el sistema de delta time Base: Migrado desde vibe1_delta con sistema delta time ya implementado

Progreso Actual

Completado

1. Migración y Setup Inicial

  • Renombrado vibe1_delta → vibe3_physics en todos los archivos
  • Carpeta resources → data
  • Actualizado CMakeLists.txt, .gitignore, defines.h, README.md
  • Añadido .claude/ al .gitignore
  • Sistema de compilación CMake funcionando

2. Sistema de Físicas Base (Heredado)

  • Delta time implementado - Física independiente del framerate
  • Contador FPS en tiempo real (esquina superior derecha, amarillo)
  • Control V-Sync dinámico con tecla "V" (ON/OFF)
  • Display V-Sync (esquina superior izquierda, cian)
  • Sistema de temas visuales - 4 temas (SUNSET/OCEAN/NEON/FOREST)
  • Batch rendering optimizado - Maneja hasta 100,000 sprites

3. NUEVA CARACTERÍSTICA: Gravedad Direccional 🎯

  • Enum GravityDirection (UP/DOWN/LEFT/RIGHT) en defines.h
  • Ball class actualizada para física multi-direccional
  • Detección de superficie inteligente - Adaptada a cada dirección
  • Fricción direccional - Se aplica en la superficie correcta
  • Controles de cursor - Cambio dinámico de gravedad
  • Debug display actualizado - Muestra dirección actual

4. NUEVA CARACTERÍSTICA: Coeficientes de Rebote Variables

  • Rango ampliado - De 0.60-0.89 a 0.30-0.95 (+120% variabilidad)
  • Comportamientos diversos - Desde pelotas super rebotonas a muy amortiguadas
  • Debug display - Muestra coeficiente LOSS de primera pelota
  • Física realista - Elimina sincronización entre pelotas

5. 🎯 NUEVA CARACTERÍSTICA: Modo RotoBall (Esfera 3D Rotante) 🌐

  • Fibonacci Sphere Algorithm - Distribución uniforme de puntos en esfera 3D
  • Rotación dual (X/Y) - Efecto visual dinámico estilo demoscene
  • Profundidad Z simulada - Color mod según distancia (oscuro=lejos, brillante=cerca)
  • Física de atracción con resorte - Sistema de fuerzas con conservación de momento
  • Transición física realista - Pelotas atraídas a esfera rotante con aceleración
  • Amortiguación variable - Mayor damping cerca del punto (estabilización)
  • Sin sprites adicionales - Usa SDL_SetTextureColorMod para profundidad
  • Proyección ortográfica - Coordenadas 3D → 2D en tiempo real
  • Conservación de inercia - Al salir mantienen velocidad tangencial
  • Compatible con temas - Mantiene paleta de colores activa
  • Performance optimizado - Funciona con 1-100,000 pelotas

📋 Controles Actuales

Tecla Acción
Gravedad hacia ARRIBA
Gravedad hacia ABAJO
Gravedad hacia IZQUIERDA
Gravedad hacia DERECHA
C 🌐 MODO ROTOBALL - Toggle esfera 3D rotante
V Alternar V-Sync ON/OFF
H Toggle debug display (FPS, V-Sync, física, gravedad, modo)
Num 1-5 Selección directa de tema (1-Atardecer/2-Océano/3-Neón/4-Bosque/5-RGB)
T Ciclar entre temas de colores
1-8 Cambiar número de pelotas (1 a 100,000)
ESPACIO Impulsar pelotas hacia arriba
G Alternar gravedad ON/OFF (mantiene dirección)
ESC Salir

🎯 Debug Display (Tecla H)

Cuando está activado muestra:

FPS: 75           # Esquina superior derecha (amarillo)
VSYNC ON          # Esquina superior izquierda (cian)
GRAV 720          # Magnitud gravedad (magenta)
VY -145           # Velocidad Y primera pelota (magenta)
SURFACE YES       # En superficie (magenta)
LOSS 0.73         # Coeficiente rebote primera pelota (magenta)
GRAVITY DOWN      # Dirección actual (amarillo)
THEME SUNSET      # Tema activo (amarillo claro)
MODE PHYSICS      # Modo simulación actual (verde claro) - PHYSICS/ROTOBALL

Arquitectura Actual

vibe3_physics/
├── source/
│   ├── main.cpp           # Bucle principal + controles + debug
│   ├── ball.h/.cpp        # Clase Ball con física direccional
│   ├── defines.h          # Constantes + enum GravityDirection
│   └── external/          # Utilidades externas
│       ├── texture.h/.cpp # Gestión texturas + nearest filter
│       ├── sprite.h/.cpp  # Sistema sprites
│       ├── dbgtxt.h       # Debug text + nearest filter
│       └── stb_image.h    # Carga imágenes
├── data/                  # Recursos (antes resources/)
│   └── ball.png          # Textura pelota 10x10px
├── CMakeLists.txt        # Build system
└── CLAUDE.md            # Este archivo de seguimiento

Sistema de Gravedad Direccional

🔧 Implementación Técnica

Enum y Estados

enum class GravityDirection {
    DOWN,    // ↓ Gravedad hacia abajo (por defecto)
    UP,      // ↑ Gravedad hacia arriba
    LEFT,    // ← Gravedad hacia la izquierda
    RIGHT    // → Gravedad hacia la derecha
};

Lógica de Física por Dirección

  • DOWN: Pelotas caen hacia abajo, fricción en suelo inferior
  • UP: Pelotas "caen" hacia arriba, fricción en techo
  • LEFT: Pelotas "caen" hacia izquierda, fricción en pared izquierda
  • RIGHT: Pelotas "caen" hacia derecha, fricción en pared derecha

Cambios en Ball Class

  • on_floor_on_surface_ (más genérico)
  • gravity_direction_ (nuevo miembro)
  • setGravityDirection() (nueva función)
  • update() completamente reescrito para lógica direccional

Lecciones Aprendidas de ViBe2 Modules

Éxitos de Modularización

  • C++20 modules son viables para código propio
  • CMake + Ninja funciona bien para modules
  • Separación clara de responsabilidades mejora arquitectura

Limitaciones Encontradas

  • SDL3 + modules generan conflictos irresolubles
  • Bibliotecas externas requieren includes tradicionales
  • Enfoque híbrido (modules propios + includes externos) es más práctico

🎯 Decisión para ViBe3 Physics

  • Headers tradicionales (.h/.cpp) por compatibilidad
  • Enfoque en características antes que arquitectura
  • Organización por clases en lugar de modules inicialmente

Sistema de Coeficientes de Rebote Variables

🔧 Implementación Técnica

Problema Anterior

// Sistema ANTIGUO - Poca variabilidad
loss_ = ((rand() % 30) * 0.01f) + 0.6f;  // 0.60 - 0.89 (diferencia: 0.29)

Resultado: Pelotas con comportamientos muy similares → Sincronización visible

Solución Implementada

// Sistema NUEVO - Alta variabilidad
loss_ = ((rand() % 66) * 0.01f) + 0.30f;  // 0.30 - 0.95 (diferencia: 0.65)

🎯 Tipos de Comportamiento

Categorías de Materiales

  • 🏀 Super Rebotona (0.85-0.95): Casi no pierde energía, rebota muchas veces
  • Normal (0.65-0.85): Comportamiento estándar equilibrado
  • 🎾 Amortiguada (0.45-0.65): Pierde energía moderada, se estabiliza
  • 🏐 Muy Amortiguada (0.30-0.45): Se para rápidamente, pocas rebotes

Beneficios Conseguidos

  • +120% variabilidad en coeficientes de rebote
  • Eliminación de sincronización entre pelotas
  • Comportamientos diversos visibles inmediatamente
  • Física más realista con materiales diferentes
  • Debug display para monitoreo en tiempo real

🚀 Próximos Pasos - Físicas Avanzadas

Ideas Pendientes de Implementación

1. Colisiones Entre Partículas

  • Detección de colisión ball-to-ball
  • Física de rebotes entre pelotas
  • Conservación de momentum

2. Materiales y Propiedades

  • Diferentes coeficientes de rebote por pelota
  • Fricción variable por material
  • Densidad y masa como propiedades

3. Fuerzas Externas

  • Viento - Fuerza horizontal constante
  • Campos magnéticos - Atracción/repulsión a puntos
  • Turbulencia - Fuerzas aleatorias localizadas

4. Interactividad Avanzada

  • Click para aplicar fuerzas puntuales
  • Arrastrar para crear campos de fuerza
  • Herramientas de "pincel" de física

5. Visualización Avanzada

  • Trails - Estelas de movimiento
  • Heatmaps - Visualización de velocidad/energía
  • Vectores de fuerza - Visualizar gravedad y fuerzas

6. Optimizaciones

  • Spatial partitioning para colisiones
  • Level-of-detail para muchas partículas
  • GPU compute shaders para física masiva

🎮 Controles Futuros Sugeridos

Mouse Click:     Aplicar fuerza puntual
Mouse Drag:      Crear campo de fuerza
Mouse Wheel:     Ajustar intensidad
R:               Reset todas las pelotas
P:               Pausa/Resume física
M:               Modo materiales
W:               Toggle viento

🌐 Implementación Técnica: Modo RotoBall

Algoritmo Fibonacci Sphere

Distribución uniforme de puntos en una esfera usando la secuencia de Fibonacci:

const float golden_ratio = (1.0f + sqrtf(5.0f)) / 2.0f;
const float angle_increment = PI * 2.0f * golden_ratio;

for (int i = 0; i < num_points; i++) {
    float t = static_cast<float>(i) / static_cast<float>(num_points);
    float phi = acosf(1.0f - 2.0f * t);      // Latitud: 0 a π
    float theta = angle_increment * i;        // Longitud: 0 a 2π * golden_ratio

    // Coordenadas esféricas → cartesianas
    float x = cosf(theta) * sinf(phi) * radius;
    float y = sinf(theta) * sinf(phi) * radius;
    float z = cosf(phi) * radius;
}

Ventajas:

  • Distribución uniforme sin clustering en polos
  • O(1) cálculo por punto (no requiere iteraciones)
  • Visualmente perfecto para demoscene effects

Rotación 3D (Matrices de Rotación)

// Rotación en eje Y (horizontal)
float cos_y = cosf(angle_y);
float sin_y = sinf(angle_y);
float x_rot = x * cos_y - z * sin_y;
float z_rot = x * sin_y + z * cos_y;

// Rotación en eje X (vertical)
float cos_x = cosf(angle_x);
float sin_x = sinf(angle_x);
float y_rot = y * cos_x - z_rot * sin_x;
float z_final = y * sin_x + z_rot * cos_x;

Velocidades:

  • Eje Y: 1.5 rad/s (rotación principal horizontal)
  • Eje X: 0.8 rad/s (rotación secundaria vertical)
  • Ratio Y/X ≈ 2:1 para efecto visual dinámico

Proyección 3D → 2D

Proyección Ortográfica:

float screen_x = center_x + x_rotated;
float screen_y = center_y + y_rotated;

Profundidad Z (Color Modulation):

// Normalizar Z de [-radius, +radius] a [0, 1]
float z_normalized = (z_final + radius) / (2.0f * radius);

// Mapear a rango de brillo [MIN_BRIGHTNESS, MAX_BRIGHTNESS]
float brightness_factor = (MIN + z_normalized * (MAX - MIN)) / 255.0f;

// Aplicar a color RGB
int r_mod = color.r * brightness_factor;
int g_mod = color.g * brightness_factor;
int b_mod = color.b * brightness_factor;

Efecto visual:

  • Z cerca (+radius): Brillo máximo (255) → Color original
  • Z lejos (-radius): Brillo mínimo (50) → Color oscuro
  • Simula profundidad sin sprites adicionales

Transición Suave (Interpolación)

// Progress de 0.0 a 1.0 en ROTOBALL_TRANSITION_TIME (1.5s)
transition_progress += delta_time / ROTOBALL_TRANSITION_TIME;

// Lerp desde posición actual a posición de esfera
float lerp_x = current_x + (target_sphere_x - current_x) * progress;
float lerp_y = current_y + (target_sphere_y - current_y) * progress;

Características:

  • Independiente del framerate (usa delta_time)
  • Suave y orgánico
  • Sin pop visual

Performance

  • Batch rendering: Una sola llamada SDL_RenderGeometry para todos los puntos
  • Recalculación: Fibonacci sphere recalculada cada frame (O(n) predecible)
  • Sin malloc: Usa datos ya almacenados en Ball objects
  • Color mod: CPU-side, sin overhead GPU adicional

Rendimiento medido:

  • 100 pelotas: >300 FPS
  • 1,000 pelotas: >200 FPS
  • 10,000 pelotas: >100 FPS
  • 100,000 pelotas: >60 FPS (mismo que modo física)

🔬 Sistema de Física con Atracción (Spring Force)

Mejora Implementada: Transición Física Realista

Problema anterior: Interpolación lineal artificial (lerp) sin física real Solución: Sistema de resorte (Hooke's Law) con conservación de momento

Ecuaciones Implementadas

Fuerza de Resorte (Ley de Hooke)

F_spring = k * (target - position)
  • k = 300.0: Constante de rigidez del resorte (N/m)
  • Mayor k = atracción más fuerte

Fuerza de Amortiguación (Damping)

F_damping = c * velocity
F_total = F_spring - F_damping
  • c_base = 15.0: Amortiguación lejos del punto
  • c_near = 50.0: Amortiguación cerca (estabilización)
  • Evita oscilaciones infinitas

Aplicación de Fuerzas

acceleration = F_total / mass  // Asumiendo mass = 1
velocity += acceleration * deltaTime
position += velocity * deltaTime

Comportamiento Físico

Al activar RotoBall (tecla C):

  1. Esfera comienza a rotar inmediatamente
  2. Cada pelota mantiene su velocidad actual (vx, vy)
  3. Se aplica fuerza de atracción hacia punto móvil en esfera
  4. Las pelotas se aceleran hacia sus destinos
  5. Amortiguación las estabiliza al llegar

Durante RotoBall:

  • Punto destino rota constantemente (actualización cada frame)
  • Fuerza se recalcula hacia posición rotada
  • Pelotas "persiguen" su punto mientras este se mueve
  • Efecto: Convergencia con ligera oscilación orbital

Al desactivar RotoBall (tecla C):

  1. Atracción se desactiva (enableRotoBallAttraction(false))
  2. Pelotas conservan velocidad tangencial actual
  3. Gravedad vuelve a aplicarse
  4. Transición suave a física normal

Constantes Físicas Ajustables

// En defines.h (VALORES ACTUALES - Amortiguamiento crítico)
ROTOBALL_SPRING_K = 300.0f;        // Rigidez resorte
ROTOBALL_DAMPING_BASE = 35.0f;     // Amortiguación lejos (crítico ≈ 2*√k*m)
ROTOBALL_DAMPING_NEAR = 80.0f;     // Amortiguación cerca (absorción rápida)
ROTOBALL_NEAR_THRESHOLD = 5.0f;    // Distancia "cerca" (px)
ROTOBALL_MAX_FORCE = 1000.0f;      // Límite fuerza (seguridad)

Changelog de Ajustes:

  • v1: DAMPING_BASE=15.0, NEAR=50.0 → Oscilación visible (subdamped)
  • v2: DAMPING_BASE=35.0, NEAR=80.0Absorción rápida sin oscilación

Ajustes Recomendados

Si siguen oscilando (poco probable):

ROTOBALL_DAMPING_BASE = 50.0f;   // Amortiguamiento super crítico
ROTOBALL_DAMPING_NEAR = 100.0f;  // Absorción instantánea

Si llegan muy lento:

ROTOBALL_SPRING_K = 400.0f;      // Más fuerza
ROTOBALL_DAMPING_BASE = 40.0f;   // Compensar con más damping

Si quieres más "rebote" visual:

ROTOBALL_DAMPING_BASE = 25.0f;   // Menos amortiguación
ROTOBALL_DAMPING_NEAR = 60.0f;   // Ligera oscilación

Ventajas del Sistema

Física realista: Conservación de momento angular Transición orgánica: Aceleración natural, no artificial Inercia preservada: Al salir conservan velocidad Estabilización automática: Damping evita oscilaciones infinitas Performance: O(1) por pelota, muy eficiente


🎨 Z-Sorting (Painter's Algorithm)

Problema de Renderizado 3D

Antes del Z-sorting:

  • Pelotas renderizadas en orden fijo del vector: Ball[0] → Ball[1] → ... → Ball[N]
  • Orden aleatorio respecto a profundidad Z
  • Problema: Pelotas oscuras (fondo) pintadas sobre claras (frente)
  • Resultado: Inversión de profundidad visual incorrecta

Después del Z-sorting:

  • Pelotas ordenadas por depth_brightness antes de renderizar
  • Painter's Algorithm: Fondo primero, frente último
  • Pelotas oscuras (Z bajo) renderizadas primero
  • Pelotas claras (Z alto) renderizadas último (encima)
  • Resultado: Oclusión 3D correcta

Implementación (engine.cpp::render())

if (current_mode_ == SimulationMode::ROTOBALL) {
    // 1. Crear vector de índices
    std::vector<size_t> render_order;
    for (size_t i = 0; i < balls_.size(); i++) {
        render_order.push_back(i);
    }

    // 2. Ordenar por depth_brightness (menor primero = fondo primero)
    std::sort(render_order.begin(), render_order.end(),
        [this](size_t a, size_t b) {
            return balls_[a]->getDepthBrightness() < balls_[b]->getDepthBrightness();
        });

    // 3. Renderizar en orden de profundidad
    for (size_t idx : render_order) {
        // Renderizar balls_[idx]...
    }
}

Complejidad y Performance

Operación Complejidad Tiempo (estimado)
Crear índices O(n) ~0.001ms (1K pelotas)
std::sort O(n log n) ~0.01ms (1K pelotas)
Renderizar O(n) ~variable
Total O(n log n) ~0.15ms (10K pelotas)

Impacto en FPS:

  • 100 pelotas: Imperceptible (<0.001ms)
  • 1,000 pelotas: Imperceptible (~0.01ms)
  • 10,000 pelotas: Leve (~0.15ms, ~1-2 FPS)
  • 100,000 pelotas: Moderado (~2ms, ~10-15 FPS)

Optimizaciones Aplicadas

Solo en modo RotoBall: Modo física no tiene overhead Vector de índices: balls_ no se modifica (física estable) Reserve() usado: Evita realocaciones Lambda eficiente: Acceso directo sin copias

Resultado Visual

Profundidad correcta: Fondo detrás, frente delante Oclusión apropiada: Pelotas claras cubren oscuras Efecto 3D realista: Percepción de profundidad correcta Sin artefactos visuales: Ordenamiento estable cada frame

Métricas del Proyecto

Logros Actuales

  • Compilación exitosa con CMake
  • Commit inicial creado (dec8d43)
  • 17 archivos versionados
  • 9,767 líneas de código
  • Física direccional 100% funcional
  • Coeficientes variables implementados

🎯 Objetivos Cumplidos

  • Migración limpia desde vibe1_delta
  • Sistema de gravedad direccional implementado
  • Coeficientes de rebote variables (+120% diversidad)
  • Modo RotoBall (esfera 3D rotante) implementado
  • Fibonacci sphere algorithm funcionando
  • Profundidad Z con color modulation
  • Debug display completo y funcional
  • Controles intuitivos con teclas de cursor
  • Eliminación de sincronización entre pelotas

Comandos Útiles

Compilación

mkdir -p build && cd build && cmake .. && cmake --build .

Ejecución

./vibe3_physics.exe    # Windows
./vibe3_physics        # Linux/macOS

Git

git status             # Ver cambios
git add .              # Añadir archivos
git commit -m "..."    # Crear commit

Archivo de seguimiento para sesiones Claude Code - ViBe3 Physics Actualizado: Implementación de gravedad direccional completada