posant ordre en Stage i Background

This commit is contained in:
2025-08-13 14:04:24 +02:00
parent d5ab5748a7
commit ea3e704d34
12 changed files with 644 additions and 182 deletions

View File

@@ -14,8 +14,11 @@
#include "texture.h" // Para Texture
// Constructor
Background::Background()
Background::Background(float total_progress_to_complete)
: renderer_(Screen::get()->getRenderer()),
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),
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
@@ -30,8 +33,8 @@ Background::Background()
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_text_(param.background.attenuate_color.a),
alpha_color_text_temp_(param.background.attenuate_color.a)
alpha_color_texture_(param.background.attenuate_color.a),
previous_alpha_color_texture_(param.background.attenuate_color.a)
{
// Precalcula rutas
@@ -102,7 +105,7 @@ Background::Background()
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_text_);
SDL_SetTextureAlphaMod(color_texture_, alpha_color_texture_);
}
// Destructor
@@ -113,6 +116,11 @@ Background::~Background() {
// Actualiza la lógica del objeto
void Background::update() {
// Actualiza la progresión y calcula transiciones (solo si no está en modo manual)
if (!manual_mode_) {
updateProgression();
}
// Actualiza el valor de alpha_
updateAlphaColorTexture();
@@ -125,7 +133,7 @@ void Background::update() {
// Calcula el valor de alpha_
alpha_ = std::max((255 - (int)(255 * transition_)), 0);
// Mueve el sol
// Mueve el sol y la luna según la progresión
sun_sprite_->setPosition(sun_path_.at(sun_index_));
moon_sprite_->setPosition(moon_path_.at(moon_index_));
@@ -136,6 +144,112 @@ void Background::update() {
fillCanvas();
}
// Incrementa la progresión interna
void Background::incrementProgress(float amount) {
if (state_ == State::NORMAL) {
progress_ += amount;
progress_ = std::min(progress_, total_progress_to_complete_);
}
}
// Cambia el estado del fondo
void Background::setState(State new_state) {
state_ = new_state;
}
// Reinicia la progresión
void Background::reset() {
progress_ = 0.0f;
state_ = State::NORMAL;
manual_mode_ = false;
gradient_number_ = 0;
transition_ = 0.0f;
sun_index_ = 0;
moon_index_ = 0;
}
// Activa/desactiva el modo manual
void Background::setManualMode(bool manual) {
manual_mode_ = manual;
}
// Ajusta la velocidad de las nubes
void Background::setCloudsSpeed(float value) {
clouds_speed_ = value;
}
// Establece el degradado de fondo
void Background::setGradientNumber(int value) {
gradient_number_ = value % STAGES;
}
// Ajusta la transición entre texturas
void Background::setTransition(float value) {
transition_ = std::clamp(value, 0.0F, 1.0F);
}
// Establece la posición del sol
void Background::setSunProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}
// Establece la posición de la luna
void Background::setMoonProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}
// Actualiza la progresión y calcula las transiciones
void Background::updateProgression() {
// Si el juego está completado, reduce la progresión gradualmente
if (state_ == State::COMPLETED) {
if (progress_ > MINIMUM_COMPLETED_PROGRESS) {
progress_ -= COMPLETED_REDUCTION_RATE;
} else {
progress_ = MINIMUM_COMPLETED_PROGRESS;
}
}
// Calcula la transición de los diferentes fondos
const float gradient_float = std::min(progress_ / progress_per_stage_, static_cast<float>(STAGES - 1));
const float percent = gradient_float - static_cast<int>(gradient_float);
gradient_number_ = static_cast<size_t>(gradient_float);
transition_ = percent;
// Calcula la posición del sol
const float sun_progression = std::min(progress_ / sun_completion_progress_, 1.0f);
sun_index_ = static_cast<size_t>(sun_progression * (sun_path_.size() - 1));
// Calcula la posición de la luna
const float moon_progression = std::min(progress_ / total_progress_to_complete_, 1.0f);
moon_index_ = static_cast<size_t>(moon_progression * (moon_path_.size() - 1));
// Actualiza la velocidad de las nubes
updateCloudsSpeed();
}
// 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;
// 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);
}
clouds_speed_ = BASE_TOP_CLOUDS_SPEED * speed_factor;
}
// Dibuja el gradiente de fondo
void Background::renderGradient() {
// Dibuja el gradiente de detras
@@ -221,21 +335,6 @@ void Background::render() {
SDL_RenderTexture(renderer_, color_texture_, &src_rect_, &dst_rect_);
}
// Ajusta el valor de la variable
void Background::setCloudsSpeed(float value) {
clouds_speed_ = value;
}
// Ajusta el valor de la variable
void Background::setGradientNumber(int value) {
gradient_number_ = value % 4;
}
// Ajusta el valor de la variable
void Background::setTransition(float value) {
transition_ = std::clamp(value, 0.0F, 1.0F);
}
// Establece la posición del objeto
void Background::setPos(SDL_FRect pos) {
dst_rect_ = pos;
@@ -267,17 +366,17 @@ void Background::setAlpha(int alpha) {
alpha_ = std::clamp(alpha, 0, 255);
// Guarda el valor actual y establece el nuevo valor
alpha_color_text_temp_ = alpha_color_text_;
alpha_color_text_ = alpha_;
previous_alpha_color_texture_ = alpha_color_texture_;
alpha_color_texture_ = alpha_;
}
// Actualiza el valor de alpha_
void Background::updateAlphaColorTexture() {
if (alpha_color_text_ == alpha_color_text_temp_) {
if (alpha_color_texture_ == previous_alpha_color_texture_) {
return;
}
alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_;
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_);
alpha_color_texture_ > previous_alpha_color_texture_ ? ++previous_alpha_color_texture_ : --previous_alpha_color_texture_;
SDL_SetTextureAlphaMod(color_texture_, previous_alpha_color_texture_);
}
// Actualiza las nubes
@@ -354,15 +453,3 @@ void Background::createMoonPath() {
moon_path_.push_back({x, y});
}
}
// Establece la posición del sol
void Background::setSunProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}
// Establece la posición de la luna
void Background::setMoonProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}

View File

@@ -16,21 +16,29 @@ class Texture;
/*
Esta clase gestiona el fondo que aparece en la sección jugable.
Usa una textura compuesta y una capa superior con un color sólido cuya opacidad es ajustable.
Su área total está definida por "rect", pero solo se pinta la región "srcRect" en la pantalla en "dstRect".
Maneja internamente su progresión a través de diferentes estados del día/noche,
controlando las transiciones entre gradientes, posiciones del sol/luna y velocidad de nubes.
Estados:
- NORMAL: Progresión normal del día
- COMPLETED: Reducción gradual de la actividad (nubes más lentas)
Métodos clave:
- setCloudsSpeed(float value) -> Define la velocidad de las nubes
- setGradientNumber(int value) -> Ajusta el índice del color de cielo
- setTransition(float value) -> Configura la transición entre texturas
- setColor(Color color) -> Aplica un color de atenuación
- setAlpha(int alpha) -> Ajusta la transparencia de la capa de atenuación
- incrementProgress() -> Avanza la progresión del fondo
- setState() -> Cambia el estado del fondo
- setColor/setAlpha -> Efectos de atenuación
*/
class Background {
public:
// Enumeración de estados
enum class State {
NORMAL,
COMPLETED
};
// Constructor y Destructor
Background();
Background(float total_progress_to_complete = 6100.0f);
~Background();
// Actualización y renderizado
@@ -40,20 +48,40 @@ class Background {
// Configuración de posición
void setPos(SDL_FRect pos); // Establece la posición del objeto
// Configuración de animaciones y efectos
void setCloudsSpeed(float value); // Ajusta la velocidad de desplazamiento de las nubes
void setGradientNumber(int value); // Establece el degradado de fondo a usar
void setTransition(float value); // Ajusta la transición entre texturas de fondo
// Control de progresión
void incrementProgress(float amount = 1.0f); // Incrementa la progresión interna
void setState(State new_state); // Cambia el estado del fondo
void reset(); // Reinicia la progresión
// 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
// Configuración de efectos visuales
void setColor(Color color); // Establece el color de atenuación
void setAlpha(int alpha); // Ajusta la transparencia del fondo
// Configuración del sol y la luna
void setSunProgression(float progress); // Establece la posición del sol
void setMoonProgression(float progress); // Establece la posición de la luna
// Getters para información del estado
float getProgress() const { return progress_; }
State getState() const { return state_; }
int getCurrentGradient() const { return static_cast<int>(gradient_number_); }
private:
// Constantes de configuración
static constexpr size_t STAGES = 4;
static constexpr float COMPLETED_REDUCTION_RATE = 25.0f;
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0f;
static constexpr float SUN_COMPLETION_FACTOR = 0.5f; // El sol completa su recorrido a la mitad del progreso total
// Configuración paramétrica
const float total_progress_to_complete_;
const float progress_per_stage_;
const float sun_completion_progress_;
// Objetos y punteros
SDL_Renderer *renderer_; // Renderizador de la ventana
@@ -81,28 +109,39 @@ class Background {
SDL_Texture *canvas_; // Textura para componer el fondo
SDL_Texture *color_texture_; // Textura para atenuar el fondo
// Variables de control
std::array<SDL_FRect, 4> gradient_rect_;
std::array<SDL_FRect, 4> top_clouds_rect_;
std::array<SDL_FRect, 4> bottom_clouds_rect_;
int gradient_number_ = 0;
int alpha_ = 0;
float clouds_speed_ = 0;
float transition_ = 0;
int counter_ = 0;
SDL_FRect rect_;
SDL_FRect src_rect_;
SDL_FRect dst_rect_;
int base_;
Color attenuate_color_;
int alpha_color_text_;
int alpha_color_text_temp_;
std::vector<SDL_FPoint> sun_path_;
std::vector<SDL_FPoint> moon_path_;
size_t sun_index_ = 0;
size_t moon_index_ = 0;
// 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
// Variables de renderizado
SDL_FRect rect_; // Tamaño del objeto
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
Color attenuate_color_; // Color de atenuación
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
float clouds_speed_ = 0; // Velocidad de las nubes
float transition_ = 0; // Porcentaje de transición
size_t gradient_number_ = 0; // Índice de fondo degradado
size_t counter_ = 0; // Contador interno
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
size_t sun_index_ = 0; // Índice del recorrido del sol
size_t moon_index_ = 0; // Índice del recorrido de la luna
int base_ = 0; // Posición base del fondo
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

View File

@@ -12,13 +12,14 @@
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "stage.h" // Para addPower
#include "stage_interface.h" // Para IStageInfo
#include "utils.h"
// Constructor
BalloonManager::BalloonManager()
BalloonManager::BalloonManager(IStageInfo *stage_info)
: explosions_(std::make_unique<Explosions>()),
balloon_formations_(std::make_unique<BalloonFormations>()) { init(); }
balloon_formations_(std::make_unique<BalloonFormations>()),
stage_info_(stage_info) { init(); }
// Inicializa
void BalloonManager::init() {
@@ -227,7 +228,7 @@ void BalloonManager::setBalloonSpeed(float speed) {
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
auto BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) -> int {
Stage::addPower(1);
stage_info_->addPower(1);
int score = 0;
if (balloon->getType() == Balloon::Type::POWERBALL) {
@@ -274,7 +275,7 @@ auto BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int {
}
// Aumenta el poder de la fase
Stage::addPower(balloon->getPower());
stage_info_->addPower(balloon->getPower());
// Destruye el globo
explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize()));

View File

@@ -12,6 +12,7 @@
#include "balloon_formations.h" // Para BalloonFormations
#include "explosions.h" // Para Explosions
#include "param.h" // Para Param, ParamGame, param
#include "stage_interface.h" // Para IStageInfo
#include "utils.h" // Para Zone
class Texture;
@@ -22,7 +23,7 @@ using Balloons = std::vector<std::shared_ptr<Balloon>>;
class BalloonManager {
public:
// Constructor y Destructor
BalloonManager();
BalloonManager(IStageInfo *stage_info);
~BalloonManager() = default;
// Actualización y Renderizado
@@ -103,6 +104,7 @@ class BalloonManager {
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
IStageInfo *stage_info_; // Informacion de la pantalla actual
// Metodos privados
void init();

View File

@@ -14,6 +14,7 @@
#include "param.h" // Para Param, ParamGame, param
#include "scoreboard.h" // Para Scoreboard
#include "stage.h" // Para power_can_be_added
#include "stage_interface.h" // Para IStageInfo
#include "texture.h" // Para Texture
#ifdef _DEBUG
#include <iostream>
@@ -26,6 +27,7 @@ Player::Player(const Config &config)
enter_name_(std::make_unique<EnterName>()),
hi_score_table_(config.hi_score_table),
glowing_entry_(config.glowing_entry),
stage_info_(config.stage_info),
play_area_(*config.play_area),
id_(config.id),
default_pos_x_(config.x),
@@ -635,7 +637,7 @@ void Player::setPlayingState(State state) {
init();
setInvulnerable(true);
setScoreboardMode(Scoreboard::Mode::SCORE);
Stage::power_can_be_added = true;
stage_info_->canCollectPower();
break;
}
case State::CONTINUE: {

View File

@@ -12,6 +12,7 @@
#include "input.h" // Para Input
#include "manage_hiscore_table.h" // Para Table
#include "scoreboard.h" // Para Scoreboard
#include "stage_interface.h" // Para IStageInfo
#include "utils.h" // Para Circle
class Texture;
@@ -82,8 +83,9 @@ class Player {
SDL_FRect *play_area; // Usamos puntero para mantener la referencia
std::vector<std::shared_ptr<Texture>> texture;
std::vector<std::vector<std::string>> animations;
Table *hi_score_table; // También como puntero para referencia
int *glowing_entry; // Puntero para mantener la referencia
Table *hi_score_table; // También como puntero para referencia
int *glowing_entry; // Puntero para mantener la referencia
IStageInfo *stage_info; // Puntero para el gestor de pantallas
};
// --- Constructor y destructor ---
@@ -204,6 +206,7 @@ class Player {
std::shared_ptr<Input::Gamepad> gamepad_ = nullptr; // Dispositivo asociado
Table *hi_score_table_ = nullptr; // Tabla de máximas puntuaciones
int *glowing_entry_ = nullptr; // Entrada de la tabla de puntuaciones para hacerla brillar
IStageInfo *stage_info_; // Informacion de la pantalla actual
std::string name_; // Nombre del jugador
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones

View File

@@ -35,7 +35,7 @@ constexpr std::string_view TEXT_COPYRIGHT = "@2020,2025 JailDesigner";
// Constructor
Credits::Credits()
: balloon_manager_(std::make_unique<BalloonManager>()),
: balloon_manager_(std::make_unique<BalloonManager>(nullptr)),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)),
fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()),

View File

@@ -42,7 +42,7 @@
#include "texture.h" // Para Texture
#include "ui/service_menu.h" // Para ServiceMenu
#ifdef _DEBUG
#include <iostream> // Para Notifier
#include <iostream> // Para std::cout
#include "ui/notifier.h" // Para Notifier
#endif
@@ -55,9 +55,10 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
background_(std::make_unique<Background>()),
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<PauseManager>([this](bool is_paused) { onPauseStateChanged(is_paused); })),
stage_manager_(std::make_unique<StageManager>()),
fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()),
balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())),
tabe_(std::make_unique<Tabe>()),
hit_(Hit(Resource::get()->getTexture("hit.png"))) {
// Pasa variables
@@ -66,8 +67,8 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
// Otras variables
Section::name = Section::Name::GAME;
Section::options = Section::Options::NONE;
Stage::init();
Stage::number = current_stage;
stage_manager_->initialize();
stage_manager_->jumpToStage(current_stage);
// Asigna texturas y animaciones
setResources();
@@ -99,7 +100,6 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
initDifficultyVars();
initDemo(player_id);
initPaths();
setTotalPower();
// Registra callbacks
ServiceMenu::get()->setStateChangeCallback([this](bool is_active) {
@@ -109,14 +109,14 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
}
});
#ifdef _DEBUG
// Si se empieza en una fase que no es la primera
if (!demo_.enabled) {
for (int i = 0; i < Stage::number; ++i) {
Stage::total_power += Stage::get(i).power_to_complete;
/* #ifdef _DEBUG
// Si se empieza en una fase que no es la primera
if (!demo_.enabled) {
for (int i = 0; i < Stage::number; ++i) {
Stage::total_power += Stage::get(i).power_to_complete;
}
}
}
#endif
#endif */
}
Game::~Game() {
@@ -260,7 +260,7 @@ void Game::renderPlayers() {
}
}
// Comprueba si hay cambio de fase y actualiza las variables
/* // Comprueba si hay cambio de fase y actualiza las variables
void Game::updateStage() {
if (Stage::power >= Stage::get(Stage::number).power_to_complete) {
// Cambio de fase
@@ -289,6 +289,64 @@ void Game::updateStage() {
background_->setAlpha(96);
}
}
} */
// Comprueba si hay cambio de fase y actualiza las variables
void Game::updateStage() {
if (!stage_manager_->isCurrentStageCompleted()) {
return; // No hay cambio de fase
}
// Calcular poder sobrante antes de avanzar
int power_overflow = 0;
auto current_stage = stage_manager_->getCurrentStage();
if (current_stage.has_value()) {
int current_power = stage_manager_->getCurrentPower();
int power_needed = current_stage->getPowerToComplete();
power_overflow = current_power - power_needed; // Poder que sobra
}
// Intentar avanzar a la siguiente fase
if (!stage_manager_->advanceToNextStage()) {
// No se pudo avanzar (probablemente juego completado)
return;
}
// Aplicar el poder sobrante a la nueva fase
if (power_overflow > 0) {
stage_manager_->addPower(power_overflow);
}
// Efectos de cambio de fase
playSound("stage_change.wav");
balloon_manager_->resetBalloonSpeed();
screen_->flash(FLASH_COLOR, 3);
screen_->shake();
// Obtener datos de la nueva fase
size_t current_stage_index = stage_manager_->getCurrentStageIndex();
size_t total_stages = stage_manager_->getTotalStages();
// Escribir texto por pantalla
if (current_stage_index < total_stages - 1) { // No es la última fase
std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
if (current_stage_index == total_stages - 2) { // Penúltima fase (será la última)
createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
} else {
auto text = Resource::get()->getText("04b_25_2x");
const std::string CAPTION = Lang::getText("[GAME_TEXT] 2") +
std::to_string(total_stages - current_stage_index) +
Lang::getText("[GAME_TEXT] 2A");
createMessage(paths, text->writeToTexture(CAPTION, 1, -4));
}
}
// Modificar color de fondo en la última fase
if (current_stage_index == total_stages - 1) { // Última fase
background_->setColor(Color(0xdd, 0x19, 0x1d).DARKEN());
background_->setAlpha(96);
}
}
// Actualiza el estado de fin de la partida
@@ -363,11 +421,11 @@ void Game::updateGameStateCompleted() {
// Para la música y elimina todos los globos e items
if (game_completed_counter_ == 0) {
stopMusic();
Stage::number = 9; // Deja el valor dentro de los limites
// Stage::number = 9; // Deja el valor dentro de los limites
balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos
playSound("power_ball_explosion.wav");
destroyAllItems(); // Destruye todos los items
Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos
destroyAllItems(); // Destruye todos los items
// Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos
background_->setAlpha(0); // Elimina el tono rojo de las últimas pantallas
}
@@ -409,8 +467,10 @@ void Game::updateGameStateCompleted() {
// Comprueba el estado del juego
void Game::checkState() {
if (state_ != State::COMPLETED && Stage::number == 10) {
// if (state_ != State::COMPLETED && Stage::number == 10) {
if (state_ != State::COMPLETED && stage_manager_->isGameCompleted()) {
setState(State::COMPLETED);
background_->setState(Background::State::COMPLETED);
}
if (state_ != State::GAME_OVER && allPlayersAreGameOver()) {
@@ -876,7 +936,8 @@ void Game::handlePlayerCollision(std::shared_ptr<Player> &player, std::shared_pt
player->setPlayingState(Player::State::ROLLING);
sendPlayerToTheBack(player);
if (allPlayersAreNotPlaying()) {
Stage::power_can_be_added = false; // No se puede subir poder de fase si no hay nadie jugando
// Stage::power_can_be_added = false; // No se puede subir poder de fase si no hay nadie jugando
stage_manager_->disablePowerCollection();
}
}
}
@@ -961,6 +1022,8 @@ void Game::updateGameStates() {
// Actualiza el fondo
void Game::updateBackground() {
/* static const auto total_power_to_complete_game = stage_manager_->getTotalPowerNeededToCompleteGame();
// Si el juego está completado, se reduce la velocidad de las nubes
if (state_ == State::COMPLETED) {
Stage::total_power = (Stage::total_power > 200) ? (Stage::total_power - 25) : 200;
@@ -969,7 +1032,7 @@ void Game::updateBackground() {
// Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego
constexpr float CLOUDS_INITIAL_SPEED = 0.05F;
constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED;
const float CLOUDS_SPEED = (-CLOUDS_INITIAL_SPEED) + (-CLOUDS_FINAL_SPEED * (static_cast<float>(Stage::total_power) / total_power_to_complete_game_));
const float CLOUDS_SPEED = (-CLOUDS_INITIAL_SPEED) + (-CLOUDS_FINAL_SPEED * (static_cast<float>(Stage::total_power) / total_power_to_complete_game));
background_->setCloudsSpeed(CLOUDS_SPEED);
// Calcula la transición de los diferentes fondos
@@ -982,7 +1045,7 @@ void Game::updateBackground() {
// Calcula la posición del sol
constexpr float SUN_FINAL_POWER = NUM * 2;
background_->setSunProgression(Stage::total_power / SUN_FINAL_POWER);
background_->setMoonProgression(Stage::total_power / static_cast<float>(total_power_to_complete_game_));
background_->setMoonProgression(Stage::total_power / static_cast<float>(total_power_to_complete_game)); */
// Actualiza el objeto
background_->update();
@@ -1166,12 +1229,11 @@ void Game::updateScoreboard() {
}
// Resto de marcador
scoreboard_->setStage(Stage::number + 1);
scoreboard_->setPower((float)Stage::power / (float)Stage::get(Stage::number).power_to_complete);
scoreboard_->setStage(stage_manager_->getCurrentStageIndex() + 1);
scoreboard_->setPower(stage_manager_->getCurrentStageProgressFraction());
scoreboard_->setHiScore(hi_score_.score);
scoreboard_->setHiScoreName(hi_score_.name);
// Lógica del marcador
scoreboard_->update();
}
@@ -1488,13 +1550,14 @@ void Game::initDemo(Player::Id player_id) {
constexpr auto NUM_DEMOS = 3;
const auto DEMO = rand() % NUM_DEMOS;
constexpr std::array<int, NUM_DEMOS> STAGES = {0, 3, 5};
Stage::number = STAGES[DEMO];
// Stage::number = STAGES[DEMO];
stage_manager_->jumpToStage(STAGES.at(DEMO));
}
// Actualiza el numero de globos explotados según la fase del modo demostración
for (int i = 0; i < Stage::number; ++i) {
/* for (int i = 0; i < Stage::number; ++i) {
Stage::total_power += Stage::get(i).power_to_complete;
}
} */
// Activa o no al otro jugador
if (rand() % 3 != 0) {
@@ -1529,14 +1592,6 @@ void Game::initDemo(Player::Id player_id) {
demo_.counter = 0;
}
// Calcula el poder total necesario para completar el juego
void Game::setTotalPower() {
total_power_to_complete_game_ = 0;
for (const auto &stage : Stage::stages) {
total_power_to_complete_game_ += stage.power_to_complete;
}
}
// Inicializa el marcador
void Game::initScoreboard() {
scoreboard_->setPos(param.scoreboard.rect);
@@ -1596,6 +1651,7 @@ void Game::initPlayers(Player::Id player_id) {
config_player1.animations = player_animations_;
config_player1.hi_score_table = &Options::settings.hi_score_table;
config_player1.glowing_entry = &Options::settings.glowing_entries.at(static_cast<int>(Player::Id::PLAYER1) - 1);
config_player1.stage_info = stage_manager_.get();
auto player1 = std::make_unique<Player>(config_player1);
player1->setScoreBoardPanel(Scoreboard::Id::LEFT);
@@ -1616,6 +1672,7 @@ void Game::initPlayers(Player::Id player_id) {
config_player2.animations = player_animations_;
config_player2.hi_score_table = &Options::settings.hi_score_table;
config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast<int>(Player::Id::PLAYER2) - 1);
config_player2.stage_info = stage_manager_.get();
auto player2 = std::make_unique<Player>(config_player2);
player2->setScoreBoardPanel(Scoreboard::Id::RIGHT);
@@ -1755,7 +1812,8 @@ void Game::updateGameStateShowingGetReadyMessage() {
void Game::updateGameStatePlaying() {
#ifdef _DEBUG
if (auto_pop_balloons_) {
Stage::addPower(5);
// Stage::addPower(5);
stage_manager_->addPower(5);
}
#endif
updatePlayers();
@@ -1787,7 +1845,7 @@ void Game::cleanVectors() {
freePathSprites();
}
// Gestiona el nivel de amenaza
/* // Gestiona el nivel de amenaza
void Game::updateMenace() {
if (state_ == State::PLAYING) {
const auto STAGE = Stage::get(Stage::number);
@@ -1803,6 +1861,30 @@ void Game::updateMenace() {
evaluateAndSetMenace(); // Recalcula el nivel de amenaza con el nuevo globo
}
}
} */
// Gestiona el nivel de amenaza
void Game::updateMenace() {
if (state_ != State::PLAYING) {
return;
}
auto current_stage = stage_manager_->getCurrentStage();
if (!current_stage.has_value()) {
return;
}
const auto &stage = current_stage.value();
const double fraction = stage_manager_->getCurrentStageProgressFraction();
const int difference = stage.getMaxMenace() - stage.getMinMenace();
// Aumenta el nivel de amenaza en función del progreso de la fase
menace_threshold_ = stage.getMinMenace() + (difference * fraction);
if (menace_current_ < menace_threshold_) {
balloon_manager_->deployRandomFormation(stage_manager_->getCurrentStageIndex());
evaluateAndSetMenace();
}
}
// Calcula y establece el valor de amenaza en funcion de los globos activos
@@ -1816,7 +1898,8 @@ void Game::checkAndUpdateBalloonSpeed() {
return;
}
const float PERCENT = static_cast<float>(Stage::power) / Stage::get(Stage::number).power_to_complete;
// const float PERCENT = static_cast<float>(Stage::power) / Stage::get(Stage::number).power_to_complete;
const float PERCENT = stage_manager_->getCurrentStageProgressPercentage();
constexpr std::array<float, 4> THRESHOLDS = {0.2F, 0.4F, 0.6F, 0.8F};
for (size_t i = 0; i < std::size(THRESHOLDS); ++i) {

View File

@@ -14,6 +14,7 @@
#include "player.h" // Para Player
#include "smart_sprite.h" // Para SmartSprite
#include "utils.h" // Para Demo
#include "stage.h" // Para StageManager
class Background;
class Balloon;
@@ -119,6 +120,7 @@ class Game {
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<PauseManager> pause_manager_; // Objeto para gestionar la pausa
std::unique_ptr<StageManager> stage_manager_; // Objeto para gestionar las fases
std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
@@ -141,7 +143,6 @@ class Game {
int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos
int game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida
int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int menace_current_ = 0; // Nivel de amenaza actual
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
State state_ = State::FADE_IN; // Estado

View File

@@ -1,43 +1,210 @@
#include "stage.h"
#include <algorithm> // Para min
#include <vector> // Para vector
#include <algorithm>
namespace Stage {
// ===== 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) {}
std::vector<Stage> stages; // Variable con los datos de cada pantalla
int power = 0; // Poder acumulado en la fase
int total_power = 0; // Poder total necesario para completar el juego
int number = 0; // Fase actual
bool power_can_be_added = true; // Habilita la recolecta de poder
// Devuelve una fase
auto get(int index) -> Stage { return stages.at(std::min(9, index)); }
// Inicializa las variables del namespace Stage
void init() {
stages.clear();
stages.emplace_back(200, 7 + (4 * 1), 7 + (4 * 3));
stages.emplace_back(300, 7 + (4 * 2), 7 + (4 * 4));
stages.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5));
stages.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5));
stages.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6));
stages.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6));
stages.emplace_back(650, 7 + (4 * 5), 7 + (4 * 7));
stages.emplace_back(750, 7 + (4 * 5), 7 + (4 * 7));
stages.emplace_back(850, 7 + (4 * 6), 7 + (4 * 8));
stages.emplace_back(950, 7 + (4 * 7), 7 + (4 * 10));
power = 0;
total_power = 0;
number = 0;
// ===== IMPLEMENTACIÓN DE StageManager =====
StageManager::StageManager()
: current_power_(0), total_power_(0), current_stage_index_(0), power_collection_state_(PowerCollectionState::ENABLED) {
initialize();
}
// Añade poder
void addPower(int amount) {
if (power_can_be_added) {
power += amount;
total_power += amount;
void StageManager::initialize() {
stages_.clear();
createDefaultStages();
reset();
}
void StageManager::reset() {
current_power_ = 0;
total_power_ = 0;
current_stage_index_ = 0;
power_collection_state_ = PowerCollectionState::ENABLED;
updateStageStatuses();
}
void StageManager::createDefaultStages() {
// Crear las 10 fases como en tu código original
stages_.emplace_back(200, 7 + (4 * 1), 7 + (4 * 3), "Tutorial");
stages_.emplace_back(300, 7 + (4 * 2), 7 + (4 * 4), "Primeros pasos");
stages_.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5), "Intensificación");
stages_.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5), "Persistencia");
stages_.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6), "Desafío medio");
stages_.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6), "Resistencia");
stages_.emplace_back(650, 7 + (4 * 5), 7 + (4 * 7), "Aproximación final");
stages_.emplace_back(750, 7 + (4 * 5), 7 + (4 * 7), "Penúltimo obstáculo");
stages_.emplace_back(850, 7 + (4 * 6), 7 + (4 * 8), "Clímax");
stages_.emplace_back(950, 7 + (4 * 7), 7 + (4 * 10), "Maestría");
}
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
updateStageStatuses();
return true;
}
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
total_power_ = accumulated_power; // Poder total como si hubiéramos completado las anteriores
updateStageStatuses();
return true;
}
bool StageManager::subtractPower(int amount) {
if (amount <= 0 || current_power_ < amount) {
return false;
}
current_power_ -= amount;
updateStageStatuses();
return true;
}
void StageManager::enablePowerCollection() {
power_collection_state_ = PowerCollectionState::ENABLED;
}
void StageManager::disablePowerCollection() {
power_collection_state_ = PowerCollectionState::DISABLED;
}
std::optional<StageData> StageManager::getCurrentStage() const {
return getStage(current_stage_index_);
}
std::optional<StageData> StageManager::getStage(size_t index) const {
if (!validateStageIndex(index)) {
return std::nullopt;
}
return stages_[index];
}
bool StageManager::isCurrentStageCompleted() const {
auto current_stage = getCurrentStage();
if (!current_stage.has_value()) {
return false;
}
return current_power_ >= current_stage->getPowerToComplete();
}
bool StageManager::isGameCompleted() const {
return current_stage_index_ >= stages_.size() - 1 && isCurrentStageCompleted();
}
double StageManager::getProgressPercentage() const {
if (stages_.empty()) return 0.0;
int total_power_needed = getTotalPowerNeededToCompleteGame();
if (total_power_needed == 0) return 100.0;
return (static_cast<double>(total_power_) / total_power_needed) * 100.0;
}
double StageManager::getCurrentStageProgressPercentage() const {
return getCurrentStageProgressFraction() * 100.0;
}
double StageManager::getCurrentStageProgressFraction() const {
auto current_stage = getCurrentStage();
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<double>(current_power_) / power_needed;
return std::min(fraction, 1.0);
}
int StageManager::getPowerNeededForCurrentStage() const {
auto current_stage = getCurrentStage();
if (!current_stage.has_value()) {
return 0;
}
return std::max(0, current_stage->getPowerToComplete() - current_power_);
}
int StageManager::getTotalPowerNeededToCompleteGame() const {
int total_power_needed = 0;
for (const auto& stage : stages_) {
total_power_needed += stage.getPowerToComplete();
}
return total_power_needed;
}
// ===== IMPLEMENTACIÓN DE IStageInfo (lo que ven Player y Balloon) =====
bool StageManager::canCollectPower() const {
return power_collection_state_ == PowerCollectionState::ENABLED;
}
void StageManager::addPower(int amount) {
if (amount <= 0 || !canCollectPower()) {
return;
}
current_power_ += amount;
total_power_ += amount;
// Verificar si se completó la fase actual
if (isCurrentStageCompleted()) {
auto current_stage = getCurrentStage();
if (current_stage.has_value()) {
stages_[current_stage_index_].setStatus(StageStatus::COMPLETED);
}
}
updateStageStatuses();
}
int StageManager::getCurrentMenaceLevel() const {
auto current_stage = getCurrentStage();
if (!current_stage.has_value()) {
return 0;
}
return current_stage->getMinMenace();
}
// ===== MÉTODOS PRIVADOS =====
bool StageManager::validateStageIndex(size_t index) const {
return index < stages_.size();
}
void StageManager::updateStageStatuses() {
for (size_t i = 0; i < stages_.size(); ++i) {
if (i < current_stage_index_) {
stages_[i].setStatus(StageStatus::COMPLETED);
} else if (i == current_stage_index_) {
stages_[i].setStatus(StageStatus::IN_PROGRESS);
} else {
stages_[i].setStatus(StageStatus::LOCKED);
}
}
}
} // namespace Stage

View File

@@ -1,33 +1,96 @@
#pragma once
#include <vector> // Para vector
#include <optional>
#include <string>
#include <vector>
/*
Namespace Stage: gestiona los datos y operaciones de las fases del juego.
Permite consultar y modificar el poder necesario, la amenaza y el estado de cada fase.
*/
#include "stage_interface.h"
namespace Stage {
// --- Estructura con los datos de una fase ---
struct Stage {
int power_to_complete; // Cantidad de poder que se necesita para completar la fase
int min_menace; // Umbral mínimo de amenaza de la fase
int max_menace; // Umbral máximo de amenaza de la fase
// Constructor
Stage(int power_to_complete, int min_menace, int max_menace)
: power_to_complete(power_to_complete), min_menace(min_menace), max_menace(max_menace) {}
enum class PowerCollectionState {
ENABLED,
DISABLED
};
// --- Variables globales del estado de las fases ---
extern std::vector<Stage> stages; // Vector con los datos de cada pantalla
extern int power; // Poder acumulado en la fase actual
extern int total_power; // Poder total necesario para completar el juego
extern int number; // Índice de la fase actual
extern bool power_can_be_added; // Indica si se puede añadir poder a la fase
enum class StageStatus {
LOCKED,
IN_PROGRESS,
COMPLETED
};
// --- Funciones principales ---
auto get(int index) -> Stage; // Devuelve una fase por índice
void init(); // Inicializa las variables del namespace Stage
void addPower(int amount); // Añade poder a la fase actual
} // namespace Stage
class StageData {
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 = "");
// 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; }
};
class StageManager : public IStageInfo { // Hereda de la interfaz
private:
std::vector<StageData> stages_;
int current_power_;
int total_power_;
size_t current_stage_index_;
PowerCollectionState power_collection_state_;
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<StageData> getCurrentStage() const;
std::optional<StageData> 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();
};

14
source/stage_interface.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
// Interfaz simple para lo que necesitan Player y Balloon
class IStageInfo {
public:
virtual ~IStageInfo() = default;
// Lo que necesita Player para recolectar poder
virtual bool canCollectPower() const = 0;
virtual void addPower(int amount) = 0;
// Lo que necesitan Player y Balloon para ajustar comportamiento
virtual int getCurrentMenaceLevel() const = 0;
};