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

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;
@@ -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_));
}

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
};