diff --git a/source/background.cpp b/source/background.cpp index fc03f6d..07a12d5 100644 --- a/source/background.cpp +++ b/source/background.cpp @@ -15,11 +15,12 @@ // Constructor Background::Background(float total_progress_to_complete) - : renderer_(Screen::get()->getRenderer()), - total_progress_to_complete_(total_progress_to_complete), + : total_progress_to_complete_(total_progress_to_complete), progress_per_stage_(total_progress_to_complete_ / STAGES), sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR), + renderer_(Screen::get()->getRenderer()), + buildings_texture_(Resource::get()->getTexture("game_buildings.png")), top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")), bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")), @@ -31,81 +32,16 @@ Background::Background(float total_progress_to_complete) rect_(SDL_FRect{0, 0, static_cast(gradients_texture_->getWidth() / 2), static_cast(gradients_texture_->getHeight() / 2)}), src_rect_({0, 0, 320, 240}), dst_rect_({0, 0, 320, 240}), - base_(rect_.h), attenuate_color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)), + alpha_color_texture_(param.background.attenuate_color.a), - previous_alpha_color_texture_(param.background.attenuate_color.a) - -{ - // Precalcula rutas - createSunPath(); - createMoonPath(); - - // Inicializa variables - { - gradient_rect_[0] = {0, 0, rect_.w, rect_.h}; - gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h}; - gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h}; - gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h}; - - const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4; - const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4; - for (int i = 0; i < 4; ++i) { - top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT}; - bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT}; - } - } - - // Crea los sprites - { - const float TOP_CLOUDS_Y = base_ - 165; - const float BOTTOM_CLOUDS_Y = base_ - 101; - - top_clouds_sprite_a_ = std::make_unique(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast(top_clouds_texture_->getHeight())}); - top_clouds_sprite_b_ = std::make_unique(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast(top_clouds_texture_->getHeight())}); - - bottom_clouds_sprite_a_ = std::make_unique(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast(bottom_clouds_texture_->getHeight())}); - bottom_clouds_sprite_b_ = std::make_unique(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast(bottom_clouds_texture_->getHeight())}); - - buildings_sprite_ = std::make_unique(buildings_texture_); - gradient_sprite_ = std::make_unique(gradients_texture_, 0, 0, rect_.w, rect_.h); - grass_sprite_ = std::make_unique(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2); - sun_sprite_ = std::make_unique(sun_texture_); - moon_sprite_ = std::make_unique(moon_texture_); - } - - // Inicializa objetos - { - constexpr float TOP_CLOUDS_SPEED = 0.1F; - constexpr float BOTTOM_CLOUDS_SPEED = 0.05F; - - top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); - top_clouds_sprite_a_->setVelX(-TOP_CLOUDS_SPEED); - - top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); - top_clouds_sprite_b_->setVelX(-TOP_CLOUDS_SPEED); - - bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); - bottom_clouds_sprite_a_->setVelX(-BOTTOM_CLOUDS_SPEED); - - bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); - bottom_clouds_sprite_b_->setVelX(-BOTTOM_CLOUDS_SPEED); - - buildings_sprite_->setY(base_ - buildings_sprite_->getHeight()); - grass_sprite_->setY(base_ - grass_sprite_->getHeight()); - sun_sprite_->setPosition(sun_path_.front()); - moon_sprite_->setPosition(moon_path_.front()); - } - - // Crea la textura para componer el fondo - canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); - SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND); - - // Crea la textura para atenuar el fondo - color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); - SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND); - setColor(attenuate_color_); - SDL_SetTextureAlphaMod(color_texture_, alpha_color_texture_); + previous_alpha_color_texture_(param.background.attenuate_color.a), + base_(rect_.h) { + initializePaths(); + initializeRects(); + initializeSprites(); + initializeSpriteProperties(); + initializeTextures(); } // Destructor @@ -114,14 +50,88 @@ Background::~Background() { SDL_DestroyTexture(color_texture_); } +// Inicializa las rutas del sol y la luna +void Background::initializePaths() { + createSunPath(); + createMoonPath(); +} + +// Inicializa los rectángulos de gradientes y nubes +void Background::initializeRects() { + gradient_rect_[0] = {0, 0, rect_.w, rect_.h}; + gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h}; + gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h}; + gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h}; + + const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4; + const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4; + + for (int i = 0; i < 4; ++i) { + top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT}; + bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT}; + } +} + +// Crea los sprites +void Background::initializeSprites() { + const float TOP_CLOUDS_Y = base_ - 165; + const float BOTTOM_CLOUDS_Y = base_ - 101; + + top_clouds_sprite_a_ = std::make_unique(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast(top_clouds_texture_->getHeight())}); + top_clouds_sprite_b_ = std::make_unique(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast(top_clouds_texture_->getHeight())}); + + bottom_clouds_sprite_a_ = std::make_unique(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast(bottom_clouds_texture_->getHeight())}); + bottom_clouds_sprite_b_ = std::make_unique(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast(bottom_clouds_texture_->getHeight())}); + + buildings_sprite_ = std::make_unique(buildings_texture_); + gradient_sprite_ = std::make_unique(gradients_texture_, 0, 0, rect_.w, rect_.h); + grass_sprite_ = std::make_unique(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2); + sun_sprite_ = std::make_unique(sun_texture_); + moon_sprite_ = std::make_unique(moon_texture_); +} + +// Configura las propiedades iniciales de los sprites +void Background::initializeSpriteProperties() { + constexpr float TOP_CLOUDS_SPEED = 0.1F; + constexpr float BOTTOM_CLOUDS_SPEED = 0.05F; + + top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); + top_clouds_sprite_a_->setVelX(-TOP_CLOUDS_SPEED); + + top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); + top_clouds_sprite_b_->setVelX(-TOP_CLOUDS_SPEED); + + bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); + bottom_clouds_sprite_a_->setVelX(-BOTTOM_CLOUDS_SPEED); + + bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); + bottom_clouds_sprite_b_->setVelX(-BOTTOM_CLOUDS_SPEED); + + buildings_sprite_->setY(base_ - buildings_sprite_->getHeight()); + grass_sprite_->setY(base_ - grass_sprite_->getHeight()); + sun_sprite_->setPosition(sun_path_.front()); + moon_sprite_->setPosition(moon_path_.front()); +} + +// Inicializa las texturas de renderizado +void Background::initializeTextures() { + canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); + SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND); + + color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); + SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND); + setColor(attenuate_color_); + SDL_SetTextureAlphaMod(color_texture_, alpha_color_texture_); +} + // Actualiza la lógica del objeto void Background::update() { - // Actualiza la progresión y calcula transiciones (solo si no está en modo manual) + // Actualiza la progresión y calcula transiciones if (!manual_mode_) { updateProgression(); } - - // Actualiza el valor de alpha_ + + // Actualiza el valor de alpha updateAlphaColorTexture(); // Actualiza las nubes @@ -130,7 +140,7 @@ void Background::update() { // Calcula el frame de la hierba grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10); - // Calcula el valor de alpha_ + // Calcula el valor de alpha alpha_ = std::max((255 - (int)(255 * transition_)), 0); // Mueve el sol y la luna según la progresión @@ -147,8 +157,25 @@ void Background::update() { // Incrementa la progresión interna void Background::incrementProgress(float amount) { if (state_ == State::NORMAL) { + float old_progress = progress_; progress_ += amount; progress_ = std::min(progress_, total_progress_to_complete_); + + // Notifica el cambio si hay callback y el progreso cambió + if (progress_callback_ && progress_ != old_progress) { + progress_callback_(progress_); + } + } +} + +// Establece la progresión absoluta +void Background::setProgress(float absolute_progress) { + float old_progress = progress_; + progress_ = std::clamp(absolute_progress, 0.0f, total_progress_to_complete_); + + // Notifica el cambio si hay callback y el progreso cambió + if (progress_callback_ && progress_ != old_progress) { + progress_callback_(progress_); } } @@ -159,6 +186,7 @@ void Background::setState(State new_state) { // Reinicia la progresión void Background::reset() { + float old_progress = progress_; progress_ = 0.0f; state_ = State::NORMAL; manual_mode_ = false; @@ -166,6 +194,11 @@ void Background::reset() { transition_ = 0.0f; sun_index_ = 0; moon_index_ = 0; + + // Notifica el cambio si hay callback + if (progress_callback_ && progress_ != old_progress) { + progress_callback_(progress_); + } } // Activa/desactiva el modo manual @@ -173,9 +206,26 @@ void Background::setManualMode(bool manual) { manual_mode_ = manual; } +// Establece callback para sincronización automática +void Background::setProgressCallback(ProgressCallback callback) { + progress_callback_ = callback; +} + +// Elimina el callback +void Background::removeProgressCallback() { + progress_callback_ = nullptr; +} + // Ajusta la velocidad de las nubes void Background::setCloudsSpeed(float value) { clouds_speed_ = value; + + // En modo manual, aplicar la velocidad directamente + // Las nubes inferiores van a la mitad de velocidad que las superiores + top_clouds_sprite_a_->setVelX(value); + top_clouds_sprite_b_->setVelX(value); + bottom_clouds_sprite_a_->setVelX(value / 2.0f); + bottom_clouds_sprite_b_->setVelX(value / 2.0f); } // Establece el degradado de fondo @@ -212,10 +262,10 @@ void Background::updateProgression() { } // Calcula la transición de los diferentes fondos - const float gradient_float = std::min(progress_ / progress_per_stage_, static_cast(STAGES - 1)); - const float percent = gradient_float - static_cast(gradient_float); - - gradient_number_ = static_cast(gradient_float); + const float gradient_number_float = std::min(progress_ / progress_per_stage_, 3.0F); + const float percent = gradient_number_float - static_cast(gradient_number_float); + + gradient_number_ = static_cast(gradient_number_float); transition_ = percent; // Calcula la posición del sol @@ -232,22 +282,60 @@ void Background::updateProgression() { // Actualiza la velocidad de las nubes según el estado y progresión void Background::updateCloudsSpeed() { - // Velocidades base - constexpr float BASE_TOP_CLOUDS_SPEED = -0.1F; - constexpr float BASE_BOTTOM_CLOUDS_SPEED = -0.05F; + // Cálculo de velocidad según progreso + constexpr float CLOUDS_INITIAL_SPEED = 0.05F; + constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED; + + // Velocidad base según progreso (de -0.05 a -2.00) + float base_clouds_speed = (-CLOUDS_INITIAL_SPEED) + + (-CLOUDS_FINAL_SPEED * (progress_ / total_progress_to_complete_)); - // Factor de velocidad basado en la progresión (más rápido durante el día) - float speed_factor = 1.0f; - // En estado completado, las nubes se ralentizan gradualmente if (state_ == State::COMPLETED) { - // Factor de ralentización basado en qué tan cerca está de MINIMUM_COMPLETED_PROGRESS - float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) / - (total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS); - speed_factor = std::max(0.1f, completion_factor); + float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) / + (total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS); + completion_factor = std::max(0.1f, completion_factor); + base_clouds_speed *= completion_factor; } - clouds_speed_ = BASE_TOP_CLOUDS_SPEED * speed_factor; + // Aplicar velocidades diferentes para nubes superiores e inferiores + const float top_clouds_speed = base_clouds_speed; + const float bottom_clouds_speed = base_clouds_speed / 2.0f; + + // Aplicar las velocidades a los sprites correspondientes + top_clouds_sprite_a_->setVelX(top_clouds_speed); + top_clouds_sprite_b_->setVelX(top_clouds_speed); + bottom_clouds_sprite_a_->setVelX(bottom_clouds_speed); + bottom_clouds_sprite_b_->setVelX(bottom_clouds_speed); + + // Guardar la velocidad principal + clouds_speed_ = top_clouds_speed; +} + +// Actualiza las nubes +void Background::updateClouds() { + // Mueve las nubes + top_clouds_sprite_a_->update(); + top_clouds_sprite_b_->update(); + bottom_clouds_sprite_a_->update(); + bottom_clouds_sprite_b_->update(); + + // Calcula el offset de las nubes + if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) { + top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth()); + } + + if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) { + top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth()); + } + + if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) { + bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth()); + } + + if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) { + bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth()); + } } // Dibuja el gradiente de fondo @@ -346,7 +434,7 @@ void Background::setPos(SDL_FRect pos) { src_rect_.h = pos.h; } -// Establece el color_ de atenuación +// Establece el color de atenuación void Background::setColor(Color color) { attenuate_color_ = color; @@ -363,14 +451,14 @@ void Background::setColor(Color color) { // Establece la transparencia de la atenuación void Background::setAlpha(int alpha) { // Evita que se asignen valores fuera de rango - alpha_ = std::clamp(alpha, 0, 255); + alpha = std::clamp(alpha, 0, 255); // Guarda el valor actual y establece el nuevo valor previous_alpha_color_texture_ = alpha_color_texture_; - alpha_color_texture_ = alpha_; + alpha_color_texture_ = alpha; } -// Actualiza el valor de alpha_ +// Actualiza el valor de alpha void Background::updateAlphaColorTexture() { if (alpha_color_texture_ == previous_alpha_color_texture_) { return; @@ -379,38 +467,6 @@ void Background::updateAlphaColorTexture() { SDL_SetTextureAlphaMod(color_texture_, previous_alpha_color_texture_); } -// Actualiza las nubes -void Background::updateClouds() { - // Aplica la velocidad calculada a las nubes - top_clouds_sprite_a_->setVelX(clouds_speed_); - top_clouds_sprite_b_->setVelX(clouds_speed_); - bottom_clouds_sprite_a_->setVelX(clouds_speed_ / 2); - bottom_clouds_sprite_b_->setVelX(clouds_speed_ / 2); - - // Mueve las nubes - top_clouds_sprite_a_->update(); - top_clouds_sprite_b_->update(); - bottom_clouds_sprite_a_->update(); - bottom_clouds_sprite_b_->update(); - - // Calcula el offset de las nubes - if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) { - top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth()); - } - - if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) { - top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth()); - } - - if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) { - bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth()); - } - - if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) { - bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth()); - } -} - // Precalcula el vector con el recorrido del sol void Background::createSunPath() { constexpr float CENTER_X = 170; diff --git a/source/background.h b/source/background.h index c1b7fbf..d173ff8 100644 --- a/source/background.h +++ b/source/background.h @@ -2,10 +2,11 @@ #include // Para SDL_FRect, SDL_FPoint, SDL_Texture, SDL_Renderer -#include // Para array -#include // Para size_t -#include // Para unique_ptr, shared_ptr -#include // Para vector +#include // Para array +#include // Para size_t +#include // Para std::function +#include // Para unique_ptr, shared_ptr +#include // Para vector #include "color.h" // Para Color @@ -50,16 +51,22 @@ class Background { // Control de progresión void incrementProgress(float amount = 1.0f); // Incrementa la progresión interna + void setProgress(float absolute_progress); // Establece la progresión absoluta void setState(State new_state); // Cambia el estado del fondo void reset(); // Reinicia la progresión + // Sistema de callback para sincronización automática + using ProgressCallback = std::function; + void setProgressCallback(ProgressCallback callback); // Establece callback para sincronización + void removeProgressCallback(); // Elimina el callback + // Configuración manual (para uso fuera del juego principal) - void setManualMode(bool manual); // Activa/desactiva el modo manual - void setCloudsSpeed(float value); // Ajusta la velocidad de las nubes - void setGradientNumber(int value); // Establece el degradado de fondo - void setTransition(float value); // Ajusta la transición entre texturas - void setSunProgression(float progress); // Establece la posición del sol - void setMoonProgression(float progress); // Establece la posición de la luna + void setManualMode(bool manual); // Activa/desactiva el modo manual + void setCloudsSpeed(float value); // Ajusta la velocidad de las nubes + void setGradientNumber(int value); // Establece el degradado de fondo + void setTransition(float value); // Ajusta la transición entre texturas + void setSunProgression(float progress); // Establece la posición del sol + void setMoonProgression(float progress); // Establece la posición de la luna // Configuración de efectos visuales void setColor(Color color); // Establece el color de atenuación @@ -111,8 +118,9 @@ class Background { // Variables de estado y progresión State state_ = State::NORMAL; - float progress_ = 0.0f; // Progresión interna (0 a total_progress_to_complete_) - bool manual_mode_ = false; // Si está en modo manual, no actualiza automáticamente + float progress_ = 0.0f; // Progresión interna (0 a total_progress_to_complete_) + bool manual_mode_ = false; // Si está en modo manual, no actualiza automáticamente + ProgressCallback progress_callback_; // Callback para notificar cambios de progreso // Variables de renderizado SDL_FRect rect_; // Tamaño del objeto @@ -140,14 +148,19 @@ class Background { Uint8 alpha_ = 0; // Transparencia entre fases // Métodos internos - void updateProgression(); // Actualiza la progresión y calcula transiciones (solo si no está en modo manual) - void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado - void renderGradient(); // Dibuja el gradiente de fondo - void renderTopClouds(); // Dibuja las nubes superiores - void renderBottomClouds(); // Dibuja las nubes inferiores - void fillCanvas(); // Compone todos los elementos en la textura - void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación - void updateClouds(); // Actualiza el movimiento de las nubes - void createSunPath(); // Precalcula el recorrido del sol - void createMoonPath(); // Precalcula el recorrido de la luna + void initializePaths(); // Inicializa las rutas del sol y la luna + void initializeRects(); // Inicializa los rectángulos de gradientes y nubes + void initializeSprites(); // Crea los sprites + void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites + void initializeTextures(); // Inicializa las texturas de renderizado + void updateProgression(); // Actualiza la progresión y calcula transiciones + void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado + void renderGradient(); // Dibuja el gradiente de fondo + void renderTopClouds(); // Dibuja las nubes superiores + void renderBottomClouds(); // Dibuja las nubes inferiores + void fillCanvas(); // Compone todos los elementos en la textura + void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación + void updateClouds(); // Actualiza el movimiento de las nubes + void createSunPath(); // Precalcula el recorrido del sol + void createMoonPath(); // Precalcula el recorrido de la luna }; \ No newline at end of file diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 51c26ad..100699c 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -52,13 +52,13 @@ Game::Game(Player::Id player_id, int current_stage, bool demo) : renderer_(Screen::get()->getRenderer()), screen_(Screen::get()), input_(Input::get()), - background_(std::make_unique()), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), pause_manager_(std::make_unique([this](bool is_paused) { onPauseStateChanged(is_paused); })), stage_manager_(std::make_unique()), + balloon_manager_(std::make_unique(stage_manager_.get())), + background_(std::make_unique(stage_manager_->getTotalPowerNeededToCompleteGame())), fade_in_(std::make_unique()), fade_out_(std::make_unique()), - balloon_manager_(std::make_unique(stage_manager_.get())), tabe_(std::make_unique()), hit_(Hit(Resource::get()->getTexture("hit.png"))) { // Pasa variables @@ -68,6 +68,7 @@ Game::Game(Player::Id player_id, int current_stage, bool demo) Section::name = Section::Name::GAME; Section::options = Section::Options::NONE; stage_manager_->initialize(); + stage_manager_->setPowerChangeCallback([this](int amount) { background_->incrementProgress(amount); }); stage_manager_->jumpToStage(current_stage); // Asigna texturas y animaciones diff --git a/source/sections/game.h b/source/sections/game.h index 4307763..2b523db 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -101,29 +101,28 @@ class Game { Input *input_; // Manejador de entrada Scoreboard *scoreboard_; // Objeto para dibujar el marcador - std::unique_ptr background_; // Objeto para dibujar el fondo del juego - SDL_Texture *canvas_; // Textura para dibujar la zona de juego - + std::vector> players_; // Vector con los jugadores std::vector> bullets_; // Vector con las balas std::vector> items_; // Vector con los items std::vector> smart_sprites_; // Vector con los smartsprites std::vector> path_sprites_; // Vector con los pathsprites - + std::vector> item_textures_; // Vector con las texturas de los items std::vector>> player_textures_; // Vector con todas las texturas de los jugadores - + std::vector> game_text_textures_; // Vector con las texturas para los sprites con textos - + std::vector> item_animations_; // Vector con las animaciones de los items std::vector> player_animations_; // Vector con las animaciones del jugador - + std::unique_ptr pause_manager_; // Objeto para gestionar la pausa std::unique_ptr stage_manager_; // Objeto para gestionar las fases + std::unique_ptr balloon_manager_; // Objeto para gestionar los globos + std::unique_ptr background_; // Objeto para dibujar el fondo del juego std::unique_ptr fade_in_; // Objeto para renderizar fades std::unique_ptr fade_out_; // Objeto para renderizar fades - std::unique_ptr balloon_manager_; // Objeto para gestionar los globos std::unique_ptr tabe_; // Objeto para gestionar el Tabe Volaor std::vector paths_; // Vector con los recorridos precalculados almacenados diff --git a/source/stage.cpp b/source/stage.cpp index 0c303a0..4cf8526 100644 --- a/source/stage.cpp +++ b/source/stage.cpp @@ -1,14 +1,16 @@ #include "stage.h" - #include // ===== IMPLEMENTACIÓN DE StageData ===== StageData::StageData(int power_to_complete, int min_menace, int max_menace, const std::string& name) - : power_to_complete_(power_to_complete), min_menace_(min_menace), max_menace_(max_menace), name_(name), status_(StageStatus::LOCKED) {} + : power_to_complete_(power_to_complete), min_menace_(min_menace), + max_menace_(max_menace), name_(name), status_(StageStatus::LOCKED) {} // ===== IMPLEMENTACIÓN DE StageManager ===== StageManager::StageManager() - : current_power_(0), total_power_(0), current_stage_index_(0), power_collection_state_(PowerCollectionState::ENABLED) { + : current_power_(0), total_power_(0), current_stage_index_(0), + power_collection_state_(PowerCollectionState::ENABLED), + power_change_callback_(nullptr) { initialize(); } @@ -44,9 +46,9 @@ bool StageManager::advanceToNextStage() { if (!isCurrentStageCompleted() || current_stage_index_ >= stages_.size() - 1) { return false; } - + current_stage_index_++; - current_power_ = 0; // Reiniciar poder para la nueva fase + current_power_ = 0; // Reiniciar poder para la nueva fase updateStageStatuses(); return true; } @@ -55,18 +57,18 @@ bool StageManager::jumpToStage(size_t target_stage_index) { if (!validateStageIndex(target_stage_index)) { return false; } - + // Calcular el poder total acumulado hasta la fase objetivo int accumulated_power = 0; for (size_t i = 0; i < target_stage_index; ++i) { accumulated_power += stages_[i].getPowerToComplete(); } - + // Actualizar estado current_stage_index_ = target_stage_index; - current_power_ = 0; // Empezar la fase objetivo sin poder + current_power_ = 0; // Empezar la fase objetivo sin poder total_power_ = accumulated_power; // Poder total como si hubiéramos completado las anteriores - + updateStageStatuses(); return true; } @@ -75,7 +77,7 @@ bool StageManager::subtractPower(int amount) { if (amount <= 0 || current_power_ < amount) { return false; } - + current_power_ -= amount; updateStageStatuses(); return true; @@ -105,7 +107,7 @@ bool StageManager::isCurrentStageCompleted() const { if (!current_stage.has_value()) { return false; } - + return current_power_ >= current_stage->getPowerToComplete(); } @@ -115,10 +117,10 @@ bool StageManager::isGameCompleted() const { double StageManager::getProgressPercentage() const { if (stages_.empty()) return 0.0; - - int total_power_needed = getTotalPowerNeededToCompleteGame(); + + int total_power_needed = getTotalPowerNeededToCompleteGame(); // ⬅️ Usar el nuevo método if (total_power_needed == 0) return 100.0; - + return (static_cast(total_power_) / total_power_needed) * 100.0; } @@ -131,12 +133,12 @@ double StageManager::getCurrentStageProgressFraction() const { if (!current_stage.has_value()) { return 0.0; } - + int power_needed = current_stage->getPowerToComplete(); if (power_needed == 0) { return 1.0; } - + // Retorna fracción entre 0.0 y 1.0 double fraction = static_cast(current_power_) / power_needed; return std::min(fraction, 1.0); @@ -147,7 +149,7 @@ int StageManager::getPowerNeededForCurrentStage() const { if (!current_stage.has_value()) { return 0; } - + return std::max(0, current_stage->getPowerToComplete() - current_power_); } @@ -168,10 +170,14 @@ void StageManager::addPower(int amount) { if (amount <= 0 || !canCollectPower()) { return; } - + current_power_ += amount; total_power_ += amount; + if (power_change_callback_) { + power_change_callback_(amount); +} + // Verificar si se completó la fase actual if (isCurrentStageCompleted()) { auto current_stage = getCurrentStage(); @@ -179,7 +185,7 @@ void StageManager::addPower(int amount) { stages_[current_stage_index_].setStatus(StageStatus::COMPLETED); } } - + updateStageStatuses(); } @@ -188,7 +194,7 @@ int StageManager::getCurrentMenaceLevel() const { if (!current_stage.has_value()) { return 0; } - + return current_stage->getMinMenace(); } @@ -207,4 +213,12 @@ void StageManager::updateStageStatuses() { stages_[i].setStatus(StageStatus::LOCKED); } } +} + +void StageManager::setPowerChangeCallback(PowerChangeCallback callback) { + power_change_callback_ = callback; +} + +void StageManager::removePowerChangeCallback() { + power_change_callback_ = nullptr; } \ No newline at end of file diff --git a/source/stage.h b/source/stage.h index 984cb16..bf478d5 100644 --- a/source/stage.h +++ b/source/stage.h @@ -1,10 +1,10 @@ #pragma once +#include "stage_interface.h" +#include #include #include -#include - -#include "stage_interface.h" +#include // ⬅️ Para std::function enum class PowerCollectionState { ENABLED, @@ -18,79 +18,84 @@ enum class StageStatus { }; class StageData { - private: - int power_to_complete_; - int min_menace_; - int max_menace_; - std::string name_; - StageStatus status_; +private: + int power_to_complete_; + int min_menace_; + int max_menace_; + std::string name_; + StageStatus status_; - public: - StageData(int power_to_complete, int min_menace, int max_menace, const std::string& name = ""); +public: + StageData(int power_to_complete, int min_menace, int max_menace, const std::string& name = ""); - // Getters - int getPowerToComplete() const { return power_to_complete_; } - int getMinMenace() const { return min_menace_; } - int getMaxMenace() const { return max_menace_; } - const std::string& getName() const { return name_; } - StageStatus getStatus() const { return status_; } + // Getters + int getPowerToComplete() const { return power_to_complete_; } + int getMinMenace() const { return min_menace_; } + int getMaxMenace() const { return max_menace_; } + const std::string& getName() const { return name_; } + StageStatus getStatus() const { return status_; } - // Setters - void setStatus(StageStatus status) { status_ = status; } - - // Utilidades - bool isCompleted() const { return status_ == StageStatus::COMPLETED; } + // Setters + void setStatus(StageStatus status) { status_ = status; } + + // Utilidades + bool isCompleted() const { return status_ == StageStatus::COMPLETED; } }; -class StageManager : public IStageInfo { // Hereda de la interfaz - private: - std::vector stages_; - int current_power_; - int total_power_; - size_t current_stage_index_; - PowerCollectionState power_collection_state_; +class StageManager : public IStageInfo { // ⬅️ Hereda de la interfaz +private: + std::vector stages_; + int current_power_; + int total_power_; + size_t current_stage_index_; + PowerCollectionState power_collection_state_; - public: - StageManager(); +public: + StageManager(); + + // Métodos principales para Game + void initialize(); + void reset(); + bool advanceToNextStage(); + + // Gestión de poder + bool subtractPower(int amount); + void enablePowerCollection(); + void disablePowerCollection(); + + // Navegación avanzada + bool jumpToStage(size_t target_stage_index); + + // Consultas de estado + std::optional getCurrentStage() const; + std::optional getStage(size_t index) const; + size_t getCurrentStageIndex() const { return current_stage_index_; } + int getCurrentPower() const { return current_power_; } + int getTotalPower() const { return total_power_; } + int getTotalPowerNeededToCompleteGame() const; // ⬅️ Nuevo método + size_t getTotalStages() const { return stages_.size(); } + + // Progreso + bool isCurrentStageCompleted() const; + bool isGameCompleted() const; + double getProgressPercentage() const; // Progreso total del juego + double getCurrentStageProgressPercentage() const; // Progreso de la fase actual (0-100%) + double getCurrentStageProgressFraction() const; // Progreso de la fase actual (0.0-1.0) + int getPowerNeededForCurrentStage() const; + + // ===== IMPLEMENTACIÓN DE IStageInfo ===== + // (Esto es lo que ven Player y Balloon) + bool canCollectPower() const override; + void addPower(int amount) override; + int getCurrentMenaceLevel() const override; +using PowerChangeCallback = std::function; +void setPowerChangeCallback(PowerChangeCallback callback); +void removePowerChangeCallback(); - // Métodos principales para Game - void initialize(); - void reset(); - bool advanceToNextStage(); +private: +PowerChangeCallback power_change_callback_; - // Gestión de poder - bool subtractPower(int amount); - void enablePowerCollection(); - void disablePowerCollection(); - - // Navegación avanzada - bool jumpToStage(size_t target_stage_index); - - // Consultas de estado - std::optional getCurrentStage() const; - std::optional getStage(size_t index) const; - size_t getCurrentStageIndex() const { return current_stage_index_; } - int getCurrentPower() const { return current_power_; } - int getTotalPower() const { return total_power_; } - int getTotalPowerNeededToCompleteGame() const; - size_t getTotalStages() const { return stages_.size(); } - - // Progreso - bool isCurrentStageCompleted() const; - bool isGameCompleted() const; - double getProgressPercentage() const; // Progreso total del juego - double getCurrentStageProgressPercentage() const; // Progreso de la fase actual (0-100%) - double getCurrentStageProgressFraction() const; // Progreso de la fase actual (0.0-1.0) - int getPowerNeededForCurrentStage() const; - - // ===== IMPLEMENTACIÓN DE IStageInfo ===== - // (Esto es lo que ven Player y Balloon) - bool canCollectPower() const override; - void addPower(int amount) override; - int getCurrentMenaceLevel() const override; - - private: - void createDefaultStages(); - bool validateStageIndex(size_t index) const; - void updateStageStatuses(); + void createDefaultStages(); + bool validateStageIndex(size_t index) const; + void updateStageStatuses(); }; \ No newline at end of file