Implementar control manual de escala para figuras 3D + actualizar README

NUEVAS CARACTERÍSTICAS:
- Control de escala dinámico con Numpad +/-/* (30%-300%)
- Protección automática contra clipping según resolución
- Texto informativo muestra porcentaje de escala
- Fix: Redondeo correcto en display de escala (79% → 80%)

CAMBIOS EN README:
- Actualizar tabla de controles (C→F, T→B, añadir Q/W/E/R/T/Y/U/I)
- Documentar sistema polimórfico de figuras 3D
- Añadir sección "Controles de Figuras 3D" con Numpad +/-/*
- Actualizar debug display (8 líneas ahora)
- Expandir sección "Modo RotoBall" → "Sistema de Figuras 3D"
- Documentar Esfera y Cubo implementados
- Listar 6 figuras futuras (Wave/Helix/Torus/Cylinder/Icosahedron/Atom)
- Actualizar estructura del proyecto (añadir source/shapes/)
- Añadir parámetros de escala manual a sección técnica

IMPLEMENTACIÓN TÉCNICA:
- defines.h: Constantes SHAPE_SCALE_MIN/MAX/STEP/DEFAULT
- engine.h: Variable shape_scale_factor_, método clampShapeScale()
- engine.cpp: Handlers Numpad +/-/*, multiplicar scale_factor en updateShape()
- clampShapeScale(): Límite dinámico según tamaño de pantalla (90% máximo)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-03 20:41:29 +02:00
parent a7ec764ebc
commit a484ce69e8
4 changed files with 174 additions and 48 deletions

131
README.md
View File

@@ -43,19 +43,34 @@ El nombre refleja su proposito: **ViBe** (vibe-coding experimental) + **Physics*
| `KP_3` | **Tema NEON (colores vibrantes)** |
| `KP_4` | **Tema BOSQUE (verdes naturales)** |
| `KP_5` | **Tema RGB (fondo blanco, colores matematicos)** |
| `T` | **Ciclar entre todos los temas** |
| `B` | **Ciclar entre todos los temas** |
### Controles de Simulacion
| Tecla | Accion |
|-------|--------|
| `1-8` | Cambiar numero de pelotas (1, 10, 100, 500, 1K, 10K, 50K, 100K) |
| `ESPACIO` | Impulsar todas las pelotas hacia arriba |
| `↑` | **Gravedad hacia ARRIBA** |
| `↓` | **Gravedad hacia ABAJO** |
| `←` | **Gravedad hacia IZQUIERDA** |
| `→` | **Gravedad hacia DERECHA** |
| `G` | **Alternar gravedad ON/OFF (mantiene direccion)** |
| `C` | **🎯 MODO ROTOBALL - Alternar esfera 3D rotante (demoscene effect)** |
| `↑` | **Gravedad hacia ARRIBA (sale de figura con gravedad)** |
| `↓` | **Gravedad hacia ABAJO (sale de figura con gravedad)** |
| `←` | **Gravedad hacia IZQUIERDA (sale de figura con gravedad)** |
| `→` | **Gravedad hacia DERECHA (sale de figura con gravedad)** |
| `G` | **Alternar gravedad ON/OFF / Sale de figura SIN gravedad** |
### Controles de Figuras 3D
| Tecla | Accion |
|-------|--------|
| `F` | **Toggle entre modo FISICA ↔ última FIGURA 3D** |
| `Q` | **Activar figura ESFERA (Fibonacci Sphere)** |
| `W` | **Activar figura WAVE GRID (pendiente)** |
| `E` | **Activar figura HELIX (pendiente)** |
| `R` | **Activar figura TORUS (pendiente)** |
| `T` | **Activar figura CUBO (rotación triple XYZ)** |
| `Y` | **Activar figura CYLINDER (pendiente)** |
| `U` | **Activar figura ICOSAHEDRON (pendiente)** |
| `I` | **Activar figura ATOM (pendiente)** |
| `KP_+` | **Aumentar escala de figura (+10%)** |
| `KP_-` | **Reducir escala de figura (-10%)** |
| `KP_*` | **Reset escala de figura a 100%** |
## 📊 Informacion en Pantalla
@@ -68,9 +83,10 @@ Cuando se activa el debug display con la tecla `H`:
- **Esquina superior izquierda**: Estado V-Sync (VSYNC ON/OFF) en **cian**
- **Esquina superior derecha**: Contador FPS en tiempo real en **amarillo**
- **Lineas 3-5**: Valores fisica primera pelota (GRAV, VY, FLOOR) en **magenta**
- **Linea 6**: Tema activo (THEME SUNSET/OCEAN/NEON/FOREST/RGB) en **amarillo claro**
- **Linea 7**: Modo de simulación (MODE PHYSICS/ROTOBALL) en **verde claro**
- **Lineas 3-5**: Valores fisica primera pelota (GRAV, VY, SURFACE, LOSS) en **magenta**
- **Linea 6**: Dirección de gravedad actual (GRAVITY UP/DOWN/LEFT/RIGHT) en **amarillo**
- **Linea 7**: Tema activo (THEME SUNSET/OCEAN/NEON/FOREST/RGB) en **amarillo claro**
- **Linea 8**: Modo de simulación (MODE PHYSICS/SPHERE/CUBE/etc.) en **verde claro**
## 🎨 Sistema de Temas de Colores
@@ -89,7 +105,7 @@ Cuando se activa el debug display con la tecla `H`:
### Controles de Temas
- **Seleccion directa**: Usa `KP_1`, `KP_2`, `KP_3`, `KP_4` o `KP_5` para cambiar inmediatamente al tema deseado
- **Ciclado secuencial**: Presiona `T` para avanzar al siguiente tema en orden
- **Ciclado secuencial**: Presiona `B` para avanzar al siguiente tema en orden
- **Indicador visual**: El nombre del tema aparece temporalmente en el centro de la pantalla con colores tematicos
- **Regeneracion automatica**: Las pelotas adoptan automaticamente la nueva paleta de colores al cambiar tema
@@ -100,42 +116,84 @@ Cuando se activa el debug display con la tecla `H`:
- **Rendimiento optimizado**: El cambio de tema solo regenera los colores, manteniendo la fisica
- **Compatibilidad completa**: Funciona con todos los escenarios (1 a 100,000 pelotas)
## 🎯 Modo RotoBall - Esfera 3D Rotante
## 🎯 Sistema de Figuras 3D - Efectos Demoscene
**Modo RotoBall** es un efecto demoscene que convierte las pelotas en una esfera 3D rotante proyectada en 2D.
**ViBe3 Physics** incluye un sistema polimórfico de figuras 3D que convierte las pelotas en formas geométricas rotantes proyectadas en 2D.
### Características del Modo RotoBall
### Figuras Implementadas
- **Algoritmo Fibonacci Sphere**: Distribución uniforme de puntos en la superficie de una esfera 3D
- **Rotación dual**: Rotación simultánea en ejes X e Y para efecto visual dinámico
- **Profundidad Z simulada**: Color modulado según profundidad (puntos lejanos más oscuros, cercanos más brillantes)
- **Transición suave**: Interpolación de 1.5 segundos desde física normal a esfera 3D
#### 🌐 ESFERA (Tecla Q)
- **Algoritmo**: Fibonacci Sphere - distribución uniforme de puntos
- **Rotación**: Dual (ejes X e Y)
- **Efecto**: Esfera rotante clásica estilo demoscene
#### 🎲 CUBO (Tecla T)
- **Distribución inteligente**:
- 1-8 pelotas: Solo vértices (8 puntos)
- 9-26 pelotas: Vértices + centros de caras + aristas (26 puntos)
- 27+ pelotas: Grid volumétrico 3D uniforme
- **Rotación**: Triple (ejes X, Y y Z simultáneos)
- **Efecto**: Cubo Rubik rotante
#### 🔮 Figuras Futuras (Pendientes)
- **W - WAVE GRID**: Malla ondeante 3D
- **E - HELIX**: Espiral helicoidal
- **R - TORUS**: Donut/toroide
- **Y - CYLINDER**: Cilindro rotante
- **U - ICOSAHEDRON**: Poliedro D20
- **I - ATOM**: Núcleo con órbitas electrónicas
### Características Técnicas
- **Física de atracción**: Sistema spring-damper (Hooke's Law) para transición suave
- **Profundidad Z simulada**: Color modulado según distancia (oscuro=fondo, brillante=frente)
- **Z-sorting**: Painter's Algorithm para oclusión correcta
- **Escala dinámica**: Control manual con Numpad +/- (30% - 300%)
- **Protección de clipping**: Escala limitada automáticamente según resolución
- **Sin sprites adicionales**: Usa `SDL_SetTextureColorMod` para simular profundidad
### Parámetros Técnicos (ajustables en defines.h)
### Parámetros Físicos (defines.h)
```cpp
ROTOBALL_RADIUS = 80.0f; // Radio de la esfera (píxeles)
ROTOBALL_ROTATION_SPEED_Y = 1.5f; // Velocidad rotación eje Y (rad/s)
ROTOBALL_ROTATION_SPEED_X = 0.8f; // Velocidad rotación eje X (rad/s)
ROTOBALL_TRANSITION_TIME = 1.5f; // Tiempo de transición (segundos)
ROTOBALL_MIN_BRIGHTNESS = 50; // Brillo mínimo fondo (0-255)
ROTOBALL_MAX_BRIGHTNESS = 255; // Brillo máximo frente (0-255)
// Física compartida entre todas las figuras
ROTOBALL_SPRING_K = 300.0f; // Rigidez del resorte (N/m)
ROTOBALL_DAMPING_BASE = 35.0f; // Amortiguación crítica
ROTOBALL_DAMPING_NEAR = 80.0f; // Absorción cerca del punto
// Esfera
ROTOBALL_RADIUS_FACTOR = 0.333f; // 33% de altura de pantalla
ROTOBALL_ROTATION_SPEED_Y = 1.5f; // rad/s (eje Y)
ROTOBALL_ROTATION_SPEED_X = 0.8f; // rad/s (eje X)
// Cubo
CUBE_SIZE_FACTOR = 0.25f; // 25% de altura de pantalla
CUBE_ROTATION_SPEED_X = 0.5f; // rad/s
CUBE_ROTATION_SPEED_Y = 0.7f; // rad/s
CUBE_ROTATION_SPEED_Z = 0.3f; // rad/s
// Control manual de escala
SHAPE_SCALE_MIN = 0.3f; // Mínimo 30%
SHAPE_SCALE_MAX = 3.0f; // Máximo 300%
SHAPE_SCALE_STEP = 0.1f; // Incremento 10%
```
### Cómo Funciona
1. **Generación**: Fibonacci sphere distribuye puntos uniformemente en esfera 3D
1. **Generación**: Algoritmo específico distribuye puntos en forma 3D
2. **Rotación**: Matrices de rotación 3D aplicadas en tiempo real
3. **Proyección**: Coordenadas 3D proyectadas a 2D (ortográfica)
4. **Profundidad**: Componente Z normalizada controla brillo del color
5. **Renderizado**: Batch rendering con color modulado por profundidad
3. **Escala**: Factor manual multiplicado a coordenadas y física
4. **Proyección**: Coordenadas 3D → 2D (ortográfica)
5. **Z-sorting**: Ordenar pelotas por profundidad (fondo primero)
6. **Profundidad**: Componente Z controla brillo del color
7. **Renderizado**: Batch rendering con color modulado
### Activación
### Uso
- **Tecla C**: Alternar entre modo física y modo RotoBall
- **Compatible**: Funciona con cualquier número de pelotas (1-100,000)
- **Temas**: Mantiene la paleta de colores del tema activo
- **Activación**: Presiona Q/W/E/R/T/Y/U/I para figura específica, o F para toggle
- **Escala**: Usa Numpad +/- para ajustar tamaño, * para reset
- **Salir**: G (sin gravedad), cursores (con gravedad), F (toggle), o 1-8 (cambiar escenario)
- **Compatible**: Funciona con 1-100,000 pelotas
- **Temas**: Mantiene paleta de colores activa
## 🏗️ Estructura del Proyecto
@@ -143,8 +201,13 @@ ROTOBALL_MAX_BRIGHTNESS = 255; // Brillo máximo frente (0-255)
vibe3_physics/
├── source/
│ ├── main.cpp # Bucle principal y logica del juego
│ ├── ball.h/cpp # Clase Ball - logica de las pelotas
│ ├── engine.h/cpp # Motor principal con loop y rendering
│ ├── ball.h/cpp # Clase Ball - fisica de pelotas
│ ├── defines.h # Constantes y configuracion
│ ├── shapes/ # Sistema polimorfico de figuras 3D
│ │ ├── shape.h # Interfaz abstracta Shape
│ │ ├── sphere_shape.h/cpp # Fibonacci Sphere
│ │ └── cube_shape.h/cpp # Cubo rotante triple
│ └── external/ # Utilidades y bibliotecas externas
│ ├── sprite.h/cpp # Clase Sprite - renderizado de texturas
│ ├── texture.h/cpp # Clase Texture - gestion de imagenes

View File

@@ -100,4 +100,10 @@ constexpr float CUBE_ROTATION_SPEED_X = 0.5f; // Velocidad rotación eje X
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)
// 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%)
constexpr float PI = 3.14159265358979323846f; // Constante PI

View File

@@ -310,6 +310,42 @@ void Engine::handleEvents() {
initBalls(scenario_);
break;
// Control de escala de figura (solo en modo SHAPE)
case SDLK_KP_PLUS:
if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ += SHAPE_SCALE_STEP;
clampShapeScale();
text_ = "SCALE " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%";
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
}
break;
case SDLK_KP_MINUS:
if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ -= SHAPE_SCALE_STEP;
clampShapeScale();
text_ = "SCALE " + std::to_string(static_cast<int>(shape_scale_factor_ * 100.0f + 0.5f)) + "%";
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
}
break;
case SDLK_KP_MULTIPLY:
if (current_mode_ == SimulationMode::SHAPE) {
shape_scale_factor_ = SHAPE_SCALE_DEFAULT;
text_ = "SCALE RESET (100%)";
int text_width = static_cast<int>(text_.length() * 8);
text_pos_ = (current_screen_width_ - text_width) / 2;
text_init_time_ = SDL_GetTicks();
show_text_ = true;
}
break;
case SDLK_1:
scenario_ = 0;
initBalls(scenario_);
@@ -1052,8 +1088,8 @@ void Engine::updateShape() {
// Actualizar animación de la figura
active_shape_->update(delta_time_, static_cast<float>(current_screen_width_), static_cast<float>(current_screen_height_));
// Obtener factor de escala para física
float scale_factor = active_shape_->getScaleFactor(static_cast<float>(current_screen_height_));
// Obtener factor de escala para física (base de figura + escala manual)
float scale_factor = active_shape_->getScaleFactor(static_cast<float>(current_screen_height_)) * shape_scale_factor_;
// Centro de la pantalla
float center_x = current_screen_width_ / 2.0f;
@@ -1065,6 +1101,11 @@ void Engine::updateShape() {
float x_3d, y_3d, z_3d;
active_shape_->getPoint3D(static_cast<int>(i), x_3d, y_3d, z_3d);
// Aplicar escala manual a las coordenadas 3D
x_3d *= shape_scale_factor_;
y_3d *= shape_scale_factor_;
z_3d *= shape_scale_factor_;
// Proyección 2D ortográfica (punto objetivo móvil)
float target_x = center_x + x_3d;
float target_y = center_y + y_3d;
@@ -1081,3 +1122,17 @@ void Engine::updateShape() {
balls_[i]->setDepthBrightness(z_normalized);
}
}
// Limitar escala de figura para evitar que se salga de pantalla
void Engine::clampShapeScale() {
// Calcular tamaño máximo permitido según resolución actual
// La figura más grande (esfera/cubo) usa ~33% de altura por defecto
// Permitir hasta que la figura ocupe 90% de la dimensión más pequeña
float max_dimension = std::min(current_screen_width_, current_screen_height_);
float base_size_factor = 0.333f; // ROTOBALL_RADIUS_FACTOR o similar
float max_scale_for_screen = (max_dimension * 0.9f) / (max_dimension * base_size_factor);
// Limitar entre SHAPE_SCALE_MIN y el mínimo de (SHAPE_SCALE_MAX, max_scale_for_screen)
float max_allowed = std::min(SHAPE_SCALE_MAX, max_scale_for_screen);
shape_scale_factor_ = std::max(SHAPE_SCALE_MIN, std::min(max_allowed, shape_scale_factor_));
}

View File

@@ -86,6 +86,7 @@ private:
ShapeType current_shape_type_ = ShapeType::SPHERE; // Tipo de figura actual
ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F
std::unique_ptr<Shape> active_shape_; // Puntero polimórfico a figura activa
float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-)
// Batch rendering
std::vector<SDL_Vertex> batch_vertices_;
@@ -129,4 +130,5 @@ private:
void activateShape(ShapeType type); // Activar figura específica (teclas Q/W/E/R/Y/U/I)
void updateShape(); // Actualizar figura activa
void generateShape(); // Generar puntos de figura activa
void clampShapeScale(); // Limitar escala para evitar clipping
};