Implementar cambio de sprite dinámico con hot-swap (Tecla N)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <cmath> // 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> 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> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir, float mass_factor)
|
||||
: sprite_(std::make_unique<Sprite>(texture)),
|
||||
pos_({x, 0.0f, BALL_SIZE, BALL_SIZE}) {
|
||||
pos_({x, 0.0f, static_cast<float>(ball_size), static_cast<float>(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<float>(ball_size), static_cast<float>(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<float>(new_size);
|
||||
pos_.h = static_cast<float>(new_size);
|
||||
|
||||
// Actualizar sprite
|
||||
sprite_->setSize(new_size, new_size);
|
||||
sprite_->setClip({0.0f, 0.0f, static_cast<float>(new_size), static_cast<float>(new_size)});
|
||||
}
|
||||
|
||||
void Ball::setTexture(std::shared_ptr<Texture> texture) {
|
||||
// Actualizar textura del sprite
|
||||
sprite_->setTexture(texture);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class Ball {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Ball(float x, float vx, float vy, Color color, std::shared_ptr<Texture> 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> 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> texture); // Cambiar textura del sprite
|
||||
|
||||
// Funciones para modo RotoBall
|
||||
void setRotoBallPosition3D(float x, float y, float z);
|
||||
void setRotoBallTarget2D(float x, float y);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Texture>(renderer_, texture_path);
|
||||
|
||||
// Textura 0: ball.png (10x10)
|
||||
std::string texture_path_normal = exe_dir + "/data/ball.png";
|
||||
textures_.push_back(std::make_shared<Texture>(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<Texture>(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<unsigned>(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<Ball>(X, VX, VY, COLOR, texture_, current_screen_width_, current_screen_height_, current_gravity_, mass_factor));
|
||||
balls_.emplace_back(std::make_unique<Ball>(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<float>(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<int>(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) {
|
||||
|
||||
@@ -26,7 +26,10 @@ private:
|
||||
// Recursos SDL
|
||||
SDL_Window* window_ = nullptr;
|
||||
SDL_Renderer* renderer_ = nullptr;
|
||||
std::shared_ptr<Texture> texture_ = nullptr;
|
||||
std::shared_ptr<Texture> texture_ = nullptr; // Textura activa actual
|
||||
std::vector<std::shared_ptr<Texture>> 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<std::unique_ptr<Ball>> 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);
|
||||
|
||||
3
source/external/sprite.h
vendored
3
source/external/sprite.h
vendored
@@ -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_ = texture; }
|
||||
};
|
||||
Reference in New Issue
Block a user