From a484ce69e8da5bdcdc392eff8d1a927bc4c4f858 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 3 Oct 2025 20:41:29 +0200 Subject: [PATCH] Implementar control manual de escala para figuras 3D + actualizar README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 155 ++++++++++++++++++++++++++++++++-------------- source/defines.h | 6 ++ source/engine.cpp | 59 +++++++++++++++++- source/engine.h | 2 + 4 files changed, 174 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 0ae2b31..a5c4c72 100644 --- a/README.md +++ b/README.md @@ -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,62 +116,109 @@ 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 ``` vibe3_physics/ ├── source/ -│ ├── main.cpp # Bucle principal y logica del juego -│ ├── ball.h/cpp # Clase Ball - logica de las pelotas -│ ├── defines.h # Constantes y configuracion -│ └── external/ # Utilidades y bibliotecas externas -│ ├── sprite.h/cpp # Clase Sprite - renderizado de texturas -│ ├── texture.h/cpp # Clase Texture - gestion de imagenes -│ ├── dbgtxt.h # Sistema de debug para texto en pantalla -│ └── stb_image.h # Biblioteca para cargar imagenes +│ ├── main.cpp # Bucle principal y logica del juego +│ ├── 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 +│ ├── dbgtxt.h # Sistema de debug para texto en pantalla +│ └── stb_image.h # Biblioteca para cargar imagenes ├── data/ -│ └── ball.png # Textura de la pelota (10x10 pixeles) -├── CMakeLists.txt # Configuracion de CMake -├── Makefile # Configuracion de Make -├── CLAUDE.md # Seguimiento de desarrollo -└── .gitignore # Archivos ignorados por Git +│ └── ball.png # Textura de la pelota (10x10 pixeles) +├── CMakeLists.txt # Configuracion de CMake +├── Makefile # Configuracion de Make +├── CLAUDE.md # Seguimiento de desarrollo +└── .gitignore # Archivos ignorados por Git ``` ## 🔧 Requisitos del Sistema diff --git a/source/defines.h b/source/defines.h index 8879ff1..7e95596 100644 --- a/source/defines.h +++ b/source/defines.h @@ -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 \ No newline at end of file diff --git a/source/engine.cpp b/source/engine.cpp index f1e8366..74ab845 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -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(shape_scale_factor_ * 100.0f + 0.5f)) + "%"; + int text_width = static_cast(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(shape_scale_factor_ * 100.0f + 0.5f)) + "%"; + int text_width = static_cast(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(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(current_screen_width_), static_cast(current_screen_height_)); - // Obtener factor de escala para física - float scale_factor = active_shape_->getScaleFactor(static_cast(current_screen_height_)); + // Obtener factor de escala para física (base de figura + escala manual) + float scale_factor = active_shape_->getScaleFactor(static_cast(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(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; @@ -1080,4 +1121,18 @@ void Engine::updateShape() { z_normalized = std::max(0.0f, std::min(1.0f, z_normalized)); 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_)); } \ No newline at end of file diff --git a/source/engine.h b/source/engine.h index ee6efdf..41ba02d 100644 --- a/source/engine.h +++ b/source/engine.h @@ -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 active_shape_; // Puntero polimórfico a figura activa + float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-) // Batch rendering std::vector 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 };