From dcd05e502f2c835a2baedd211d7b913377630030 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 4 Oct 2025 08:08:00 +0200 Subject: [PATCH] =?UTF-8?q?Implementar=20cambio=20de=20sprite=20din=C3=A1m?= =?UTF-8?q?ico=20con=20hot-swap=20(Tecla=20N)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sistema de múltiples texturas: - Carga ball.png (10x10) y ball_small.png (6x6) al inicio - Variable current_ball_size_ obtiene tamaño desde texture->getWidth() - Eliminar constante BALL_SIZE hardcoded Cambio de tamaño con ajuste de posiciones: - updateBallSizes() ajusta pos según gravedad y superficie - DOWN: mueve Y hacia abajo si crece - UP: mueve Y hacia arriba si crece - LEFT/RIGHT: mueve X correspondiente - Solo ajusta pelotas en superficie (isOnSurface()) Ball class actualizada: - Constructor recibe ball_size como parámetro - updateSize(new_size): actualiza hitbox y sprite - setTexture(texture): cambia textura del sprite - setPosition() usa setRotoBallScreenPosition() Sprite class: - Añadido setTexture() inline para hot-swap Tecla N: - Cicla entre texturas disponibles - Actualiza todas las pelotas sin reiniciar física - Texto informativo "SPRITE: NORMAL" / "SPRITE: SMALL" Fix bug initBalls(): - Ahora usa current_ball_size_ en constructor - Pelotas nuevas tienen tamaño correcto según textura activa 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- source/ball.cpp | 26 +++++++++-- source/ball.h | 6 ++- source/defines.h | 2 +- source/engine.cpp | 99 ++++++++++++++++++++++++++++++++++++++-- source/engine.h | 9 +++- source/external/sprite.h | 3 ++ 6 files changed, 133 insertions(+), 12 deletions(-) diff --git a/source/ball.cpp b/source/ball.cpp index 21874a1..9de7ec6 100644 --- a/source/ball.cpp +++ b/source/ball.cpp @@ -4,7 +4,7 @@ #include // for fabs -#include "defines.h" // for BALL_SIZE, Color, SCREEN_HEIGHT, GRAVITY_FORCE +#include "defines.h" // for Color, SCREEN_HEIGHT, GRAVITY_FORCE class Texture; // Función auxiliar para generar pérdida aleatoria en rebotes @@ -22,15 +22,15 @@ float generateLateralLoss() { } // Constructor -Ball::Ball(float x, float vx, float vy, Color color, std::shared_ptr texture, int screen_width, int screen_height, GravityDirection gravity_dir, float mass_factor) +Ball::Ball(float x, float vx, float vy, Color color, std::shared_ptr texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir, float mass_factor) : sprite_(std::make_unique(texture)), - pos_({x, 0.0f, BALL_SIZE, BALL_SIZE}) { + pos_({x, 0.0f, static_cast(ball_size), static_cast(ball_size)}) { // Convertir velocidades de píxeles/frame a píxeles/segundo (multiplicar por 60) vx_ = vx * 60.0f; vy_ = vy * 60.0f; sprite_->setPos({pos_.x, pos_.y}); - sprite_->setSize(BALL_SIZE, BALL_SIZE); - sprite_->setClip({0, 0, BALL_SIZE, BALL_SIZE}); + sprite_->setSize(ball_size, ball_size); + sprite_->setClip({0.0f, 0.0f, static_cast(ball_size), static_cast(ball_size)}); color_ = color; // Convertir gravedad de píxeles/frame² a píxeles/segundo² (multiplicar por 60²) gravity_force_ = GRAVITY_FORCE * 60.0f * 60.0f; @@ -378,4 +378,20 @@ void Ball::applyRotoBallForce(float target_x, float target_y, float sphere_radiu // Actualizar sprite para renderizado sprite_->setPos({pos_.x, pos_.y}); +} + +// Sistema de cambio de sprite dinámico +void Ball::updateSize(int new_size) { + // Actualizar tamaño del hitbox + pos_.w = static_cast(new_size); + pos_.h = static_cast(new_size); + + // Actualizar sprite + sprite_->setSize(new_size, new_size); + sprite_->setClip({0.0f, 0.0f, static_cast(new_size), static_cast(new_size)}); +} + +void Ball::setTexture(std::shared_ptr texture) { + // Actualizar textura del sprite + sprite_->setTexture(texture); } \ No newline at end of file diff --git a/source/ball.h b/source/ball.h index 522b53e..8a77ab1 100644 --- a/source/ball.h +++ b/source/ball.h @@ -32,7 +32,7 @@ class Ball { public: // Constructor - Ball(float x, float vx, float vy, Color color, std::shared_ptr texture, int screen_width, int screen_height, GravityDirection gravity_dir = GravityDirection::DOWN, float mass_factor = 1.0f); + Ball(float x, float vx, float vy, Color color, std::shared_ptr texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir = GravityDirection::DOWN, float mass_factor = 1.0f); // Destructor ~Ball() = default; @@ -78,6 +78,10 @@ class Ball { Color getColor() const { return color_; } void setColor(const Color& color) { color_ = color; } + // Sistema de cambio de sprite dinámico + void updateSize(int new_size); // Actualizar tamaño de hitbox + void setTexture(std::shared_ptr texture); // Cambiar textura del sprite + // Funciones para modo RotoBall void setRotoBallPosition3D(float x, float y, float z); void setRotoBallTarget2D(float x, float y); diff --git a/source/defines.h b/source/defines.h index 6d71104..583f2aa 100644 --- a/source/defines.h +++ b/source/defines.h @@ -8,7 +8,7 @@ constexpr char WINDOW_CAPTION[] = "vibe3_physics"; constexpr int SCREEN_WIDTH = 320; // Ancho de la pantalla lógica (píxeles) constexpr int SCREEN_HEIGHT = 240; // Alto de la pantalla lógica (píxeles) constexpr int WINDOW_ZOOM = 3; // Zoom inicial de la ventana -constexpr int BALL_SIZE = 10; // Tamaño de las pelotas (píxeles) +// BALL_SIZE eliminado: ahora se obtiene dinámicamente desde texture_->getWidth() // Configuración de zoom dinámico de ventana constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240) diff --git a/source/engine.cpp b/source/engine.cpp index 3128d0b..5a93f79 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -80,10 +80,22 @@ bool Engine::initialize() { // Inicializar otros componentes si SDL se inicializó correctamente if (success) { - // Construir ruta absoluta a la imagen + // Cargar todas las texturas disponibles std::string exe_dir = getExecutableDirectory(); - std::string texture_path = exe_dir + "/data/ball.png"; - texture_ = std::make_shared(renderer_, texture_path); + + // Textura 0: ball.png (10x10) + std::string texture_path_normal = exe_dir + "/data/ball.png"; + textures_.push_back(std::make_shared(renderer_, texture_path_normal)); + + // Textura 1: ball_small.png (6x6) + std::string texture_path_small = exe_dir + "/data/ball_small.png"; + textures_.push_back(std::make_shared(renderer_, texture_path_small)); + + // Establecer textura inicial (índice 0) + current_texture_index_ = 0; + texture_ = textures_[current_texture_index_]; + current_ball_size_ = texture_->getWidth(); // Obtener tamaño dinámicamente + srand(static_cast(time(nullptr))); dbg_init(renderer_); initializeThemes(); @@ -337,6 +349,11 @@ void Engine::handleEvents() { startThemeTransition(ColorTheme::MONOCHROME); break; + // Cambio de sprite/textura dinámico + case SDLK_N: + switchTexture(); + break; + // Control de escala de figura (solo en modo SHAPE) case SDLK_KP_PLUS: if (current_mode_ == SimulationMode::SHAPE) { @@ -609,7 +626,7 @@ void Engine::initBalls(int value) { const Color COLOR = theme.ball_colors[color_index]; // Generar factor de masa aleatorio (0.7 = ligera, 1.3 = pesada) float mass_factor = GRAVITY_MASS_MIN + (rand() % 1000) / 1000.0f * (GRAVITY_MASS_MAX - GRAVITY_MASS_MIN); - balls_.emplace_back(std::make_unique(X, VX, VY, COLOR, texture_, current_screen_width_, current_screen_height_, current_gravity_, mass_factor)); + balls_.emplace_back(std::make_unique(X, VX, VY, COLOR, texture_, current_screen_width_, current_screen_height_, current_ball_size_, current_gravity_, mass_factor)); } setText(); // Actualiza el texto } @@ -1113,6 +1130,80 @@ void Engine::performRandomRestart() { all_balls_stopped_start_time_ = 0; } +// Sistema de cambio de sprites dinámico +void Engine::updateBallSizes(int old_size, int new_size) { + float delta_size = static_cast(new_size - old_size); + + for (auto& ball : balls_) { + SDL_FRect pos = ball->getPosition(); + + // Solo ajustar posición si la pelota está en superficie + if (ball->isOnSurface()) { + GravityDirection grav_dir = ball->getGravityDirection(); + + switch (grav_dir) { + case GravityDirection::DOWN: + // Superficie inferior: ajustar Y hacia abajo si crece + pos.y += delta_size; + break; + + case GravityDirection::UP: + // Superficie superior: ajustar Y hacia arriba si crece + pos.y -= delta_size; + break; + + case GravityDirection::LEFT: + // Superficie izquierda: ajustar X hacia izquierda si crece + pos.x -= delta_size; + break; + + case GravityDirection::RIGHT: + // Superficie derecha: ajustar X hacia derecha si crece + pos.x += delta_size; + break; + } + } + + // Actualizar tamaño del hitbox + ball->updateSize(new_size); + + // Si ajustamos posición, aplicarla ahora + if (ball->isOnSurface()) { + ball->setRotoBallScreenPosition(pos.x, pos.y); + } + } +} + +void Engine::switchTexture() { + if (textures_.empty()) return; + + // Guardar tamaño antiguo + int old_size = current_ball_size_; + + // Cambiar a siguiente textura (ciclar) + current_texture_index_ = (current_texture_index_ + 1) % textures_.size(); + texture_ = textures_[current_texture_index_]; + + // Obtener nuevo tamaño de la textura + int new_size = texture_->getWidth(); + current_ball_size_ = new_size; + + // Actualizar texturas y tamaños de todas las pelotas + for (auto& ball : balls_) { + ball->setTexture(texture_); + } + + // Ajustar posiciones según el cambio de tamaño + updateBallSizes(old_size, new_size); + + // Mostrar texto informativo + std::string texture_name = (current_texture_index_ == 0) ? "NORMAL" : "SMALL"; + text_ = "SPRITE: " + texture_name; + text_pos_ = (current_screen_width_ - static_cast(text_.length() * 8)) / 2; + show_text_ = true; + text_init_time_ = SDL_GetTicks(); +} + // Sistema de Figuras 3D - Alternar entre modo física y última figura (Toggle con tecla F) void Engine::toggleShapeMode(bool force_gravity_on_exit) { if (current_mode_ == SimulationMode::PHYSICS) { diff --git a/source/engine.h b/source/engine.h index 5a0beb9..2bb2ace 100644 --- a/source/engine.h +++ b/source/engine.h @@ -26,7 +26,10 @@ private: // Recursos SDL SDL_Window* window_ = nullptr; SDL_Renderer* renderer_ = nullptr; - std::shared_ptr texture_ = nullptr; + std::shared_ptr texture_ = nullptr; // Textura activa actual + std::vector> textures_; // Todas las texturas disponibles + size_t current_texture_index_ = 0; // Índice de textura activa + int current_ball_size_ = 10; // Tamaño actual de pelotas (dinámico, se actualiza desde texture) // Estado del simulador std::vector> balls_; @@ -128,6 +131,10 @@ private: Color getInterpolatedColor(size_t ball_index) const; // Obtener color interpolado durante transición void startThemeTransition(ColorTheme new_theme); + // Sistema de cambio de sprites dinámico + void switchTexture(); // Cambia a siguiente textura disponible + void updateBallSizes(int old_size, int new_size); // Ajusta posiciones al cambiar tamaño + // Sistema de zoom dinámico int calculateMaxWindowZoom() const; void setWindowZoom(int new_zoom); diff --git a/source/external/sprite.h b/source/external/sprite.h index d6938ef..c379551 100644 --- a/source/external/sprite.h +++ b/source/external/sprite.h @@ -32,4 +32,7 @@ class Sprite { // Modulación de color void setColor(int r, int g, int b); + + // Cambio de textura dinámico + void setTexture(std::shared_ptr texture) { texture_ = texture; } }; \ No newline at end of file