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:
2025-10-04 08:08:00 +02:00
parent 6bb814e61c
commit dcd05e502f
6 changed files with 133 additions and 12 deletions

View File

@@ -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) {