treballant en Background i Stage
This commit is contained in:
@@ -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<float>(gradients_texture_->getWidth() / 2), static_cast<float>(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<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT};
|
||||
bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(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<MovingSprite>(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
|
||||
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
|
||||
|
||||
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
|
||||
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
|
||||
|
||||
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
|
||||
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
|
||||
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
|
||||
sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
|
||||
moon_sprite_ = std::make_unique<Sprite>(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<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT};
|
||||
bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(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<MovingSprite>(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
|
||||
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
|
||||
|
||||
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
|
||||
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
|
||||
|
||||
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
|
||||
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
|
||||
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
|
||||
sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
|
||||
moon_sprite_ = std::make_unique<Sprite>(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<float>(STAGES - 1));
|
||||
const float percent = gradient_float - static_cast<int>(gradient_float);
|
||||
|
||||
gradient_number_ = static_cast<size_t>(gradient_float);
|
||||
const float gradient_number_float = std::min(progress_ / progress_per_stage_, 3.0F);
|
||||
const float percent = gradient_number_float - static_cast<int>(gradient_number_float);
|
||||
|
||||
gradient_number_ = static_cast<size_t>(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;
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint, SDL_Texture, SDL_Renderer
|
||||
|
||||
#include <array> // Para array
|
||||
#include <cstddef> // Para size_t
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <vector> // Para vector
|
||||
#include <array> // Para array
|
||||
#include <cstddef> // Para size_t
|
||||
#include <functional> // Para std::function
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <vector> // 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(float)>;
|
||||
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
|
||||
};
|
||||
@@ -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<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>()),
|
||||
balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())),
|
||||
background_(std::make_unique<Background>(stage_manager_->getTotalPowerNeededToCompleteGame())),
|
||||
fade_in_(std::make_unique<Fade>()),
|
||||
fade_out_(std::make_unique<Fade>()),
|
||||
balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())),
|
||||
tabe_(std::make_unique<Tabe>()),
|
||||
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
|
||||
|
||||
@@ -101,29 +101,28 @@ class Game {
|
||||
Input *input_; // Manejador de entrada
|
||||
Scoreboard *scoreboard_; // Objeto para dibujar el marcador
|
||||
|
||||
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
|
||||
|
||||
SDL_Texture *canvas_; // Textura para dibujar la zona de juego
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores
|
||||
std::vector<std::shared_ptr<Bullet>> bullets_; // Vector con las balas
|
||||
std::vector<std::unique_ptr<Item>> items_; // Vector con los items
|
||||
std::vector<std::unique_ptr<SmartSprite>> smart_sprites_; // Vector con los smartsprites
|
||||
std::vector<std::unique_ptr<PathSprite>> path_sprites_; // Vector con los pathsprites
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
|
||||
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures_; // Vector con todas las texturas de los jugadores
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos
|
||||
|
||||
|
||||
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
|
||||
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<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
|
||||
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
|
||||
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
|
||||
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
|
||||
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include "stage.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// ===== 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<double>(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<double>(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;
|
||||
}
|
||||
145
source/stage.h
145
source/stage.h
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "stage_interface.h"
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "stage_interface.h"
|
||||
#include <functional> // ⬅️ 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<StageData> 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<StageData> 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<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; // ⬅️ 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(int)>;
|
||||
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<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();
|
||||
void createDefaultStages();
|
||||
bool validateStageIndex(size_t index) const;
|
||||
void updateStageStatuses();
|
||||
};
|
||||
Reference in New Issue
Block a user