fix: la logica de Rects dels credits

This commit is contained in:
2025-10-22 21:02:09 +02:00
parent 5a5c06efd1
commit ac6f521288
3 changed files with 232 additions and 76 deletions

View File

@@ -44,7 +44,7 @@ Director::Director(int argc, std::span<char*> argv) {
Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P;
#elif _DEBUG
Section::name = Section::Name::GAME;
Section::name = Section::Name::CREDITS;
Section::options = Section::Options::GAME_PLAY_1P;
#else // NORMAL GAME
Section::name = Section::Name::LOGO;

View File

@@ -45,27 +45,8 @@ Credits::Credits()
if (text_texture_ == nullptr) {
throw std::runtime_error("Failed to create SDL texture for text.");
}
Section::name = Section::Name::CREDITS;
balloon_manager_->setPlayArea(play_area_);
fade_in_->setColor(param.fade.color);
fade_in_->setType(Fade::Type::FULLSCREEN);
fade_in_->setPostDuration(800);
fade_in_->setMode(Fade::Mode::IN);
fade_in_->activate();
fade_out_->setColor(0, 0, 0);
fade_out_->setType(Fade::Type::FULLSCREEN);
fade_out_->setPostDuration(7000);
updateRedRect();
tiled_bg_->setColor(Color(255, 96, 96));
tiled_bg_->setSpeed(60.0F);
initPlayers();
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
fillTextTexture();
steps_ = static_cast<int>(std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4)));
initVars();
startCredits();
}
// Destructor
@@ -103,7 +84,7 @@ void Credits::run() {
// Actualiza las variables (time-based)
void Credits::update(float delta_time) {
const float MULTIPLIER = want_to_pass_ ? 4.0F : 1.0F;
const float MULTIPLIER = want_to_pass_ ? FAST_FORWARD_MULTIPLIER : 1.0F;
const float ADJUSTED_DELTA_TIME = delta_time * MULTIPLIER;
static auto* const SCREEN = Screen::get();
@@ -274,9 +255,7 @@ void Credits::fillCanvas() {
SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_);
// Dibuja el rectangulo rojo
const Color COLOR = color_.LIGHTEN();
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), COLOR.r, COLOR.g, COLOR.b, 0xFF);
SDL_RenderRect(Screen::get()->getRenderer(), &border_rect_);
drawBorderRect();
// Si el mini_logo está en su destino, lo dibuja encima de lo anterior
if (mini_logo_on_position_) {
@@ -354,8 +333,8 @@ void Credits::throwBalloons(float delta_time) {
// Inicializa los jugadores
void Credits::initPlayers() {
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores;
std::vector<std::vector<std::string>> player1_animations; // Vector con las animaciones del jugador 1
std::vector<std::vector<std::string>> player2_animations; // Vector con las animaciones del jugador 2
std::vector<std::vector<std::string>> player1_animations; // Vector con las animaciones del jugador 1
std::vector<std::vector<std::string>> player2_animations; // Vector con las animaciones del jugador 2
// Texturas - Player1
std::vector<std::shared_ptr<Texture>> player1_textures;
@@ -423,66 +402,114 @@ void Credits::initPlayers() {
// Actualiza los rectangulos negros (time-based)
void Credits::updateBlackRects(float delta_time) {
static auto current_step_ = static_cast<float>(steps_);
constexpr float BLACK_RECT_INTERVAL_S = 4.0F / 60.0F; // ~0.067s (cada 4 frames)
if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1) {
// Si los rectangulos superior e inferior no han llegado al centro
if (!initialized_) return;
if (delta_time < 0.0f) delta_time = 0.0f;
// Fase vertical: hasta que ambos rects verticales estén exactos en su target
if (!vertical_done_) {
credits_state_.black_rect_accumulator += delta_time;
if (credits_state_.black_rect_accumulator >= BLACK_RECT_INTERVAL_S) {
credits_state_.black_rect_accumulator -= BLACK_RECT_INTERVAL_S;
// Incrementa la altura del rectangulo superior
top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1);
// top
int prev_top_h = static_cast<int>(top_black_rect_.h);
top_black_rect_.h = std::min(top_black_rect_.h + 1.0f,
static_cast<float>(param.game.game_area.center_y - 1));
int top_delta = static_cast<int>(top_black_rect_.h) - prev_top_h;
// Incrementa la altura y modifica la posición del rectangulo inferior
++bottom_black_rect_.h;
bottom_black_rect_.y = std::max(bottom_black_rect_.y - 1, param.game.game_area.center_y + 1);
// bottom
int prev_bottom_h = static_cast<int>(bottom_black_rect_.h);
int prev_bottom_y = static_cast<int>(bottom_black_rect_.y);
bottom_black_rect_.h = bottom_black_rect_.h + 1.0f;
bottom_black_rect_.y = std::max(bottom_black_rect_.y - 1.0f,
static_cast<float>(param.game.game_area.center_y + 1));
int bottom_steps_by_h = static_cast<int>(bottom_black_rect_.h) - prev_bottom_h;
int bottom_steps_by_y = prev_bottom_y - static_cast<int>(bottom_black_rect_.y);
int bottom_steps = std::max(0, std::max(bottom_steps_by_h, bottom_steps_by_y));
--current_step_;
setVolume(static_cast<int>(initial_volume_ * current_step_ / steps_));
}
} else {
// Si los rectangulos superior e inferior han llegado al centro
if (left_black_rect_.w != param.game.game_area.center_x && right_black_rect_.x != param.game.game_area.center_x) {
constexpr int SPEED = 2;
// Si los rectangulos izquierdo y derecho no han llegado al centro
// Incrementa la anchura del rectangulo situado a la izquierda
left_black_rect_.w = std::min(left_black_rect_.w + SPEED, param.game.game_area.center_x);
int steps_done = top_delta + bottom_steps;
if (steps_done > 0) {
current_step_ = std::max(0.0f, current_step_ - static_cast<float>(steps_done));
float vol_f = initial_volume_ * (current_step_ / static_cast<float>(total_steps_));
int vol_i = static_cast<int>(std::clamp(vol_f, 0.0f, static_cast<float>(initial_volume_)));
Audio::get()->setMusicVolume(vol_i); // usa tu API de audio aquí
}
// Incrementa la anchura y modifica la posición del rectangulo situado a la derecha
right_black_rect_.w += SPEED;
right_black_rect_.x = std::max(right_black_rect_.x - SPEED, param.game.game_area.center_x);
--current_step_;
setVolume(static_cast<int>(initial_volume_ * current_step_ / steps_));
} else {
// Si los rectangulos izquierdo y derecho han llegado al centro
setVolume(0);
Audio::get()->stopMusic();
if (counter_pre_fade_ == 400) {
fade_out_->activate();
} else {
// Convertir deltaTime a equivalente de frames
const float FRAME_FACTOR = delta_time * 60.0F;
counter_pre_fade_ += FRAME_FACTOR;
// Si han alcanzado los objetivos, fijarlos exactamente y marcar done
bool top_at_target = static_cast<int>(top_black_rect_.h) == param.game.game_area.center_y - 1;
bool bottom_at_target = static_cast<int>(bottom_black_rect_.y) == param.game.game_area.center_y + 1;
if (top_at_target && bottom_at_target) {
top_black_rect_.h = static_cast<float>(param.game.game_area.center_y - 1);
bottom_black_rect_.y = static_cast<float>(param.game.game_area.center_y + 1);
vertical_done_ = true;
}
}
// actualizar border_rect cada frame aunque todavía en fase vertical
updateBorderRect();
return;
}
// Fase horizontal
if (!horizontal_done_) {
int prev_left_w = static_cast<int>(left_black_rect_.w);
left_black_rect_.w = std::min(left_black_rect_.w + static_cast<float>(HORIZONTAL_SPEED),
static_cast<float>(param.game.game_area.center_x));
int left_gain = static_cast<int>(left_black_rect_.w) - prev_left_w;
int prev_right_x = static_cast<int>(right_black_rect_.x);
right_black_rect_.w = right_black_rect_.w + static_cast<float>(HORIZONTAL_SPEED);
right_black_rect_.x = std::max(right_black_rect_.x - static_cast<float>(HORIZONTAL_SPEED),
static_cast<float>(param.game.game_area.center_x));
int right_move = prev_right_x - static_cast<int>(right_black_rect_.x);
int steps_done = left_gain + right_move;
if (steps_done > 0) {
current_step_ = std::max(0.0f, current_step_ - static_cast<float>(steps_done));
float vol_f = initial_volume_ * (current_step_ / static_cast<float>(total_steps_));
int vol_i = static_cast<int>(std::clamp(vol_f, 0.0f, static_cast<float>(initial_volume_)));
Audio::get()->setMusicVolume(vol_i); // usa tu API de audio aquí
}
bool left_at_target = static_cast<int>(left_black_rect_.w) == param.game.game_area.center_x;
bool right_at_target = static_cast<int>(right_black_rect_.x) == param.game.game_area.center_x;
if (left_at_target && right_at_target) {
left_black_rect_.w = static_cast<float>(param.game.game_area.center_x);
right_black_rect_.x = static_cast<float>(param.game.game_area.center_x);
horizontal_done_ = true;
}
updateBorderRect();
return;
}
// Fase final: ya completado el movimiento de rects
Audio::get()->setMusicVolume(0);
// Audio::get()->stopMusic(); // opcional, si quieres parar la reproducción
if (counter_pre_fade_ >= 400.0f) {
if (fade_out_) fade_out_->activate();
} else {
const float frame_increment = delta_time * FRAMES_PER_SECOND;
counter_pre_fade_ += frame_increment;
}
}
// Actualiza el rectangulo rojo
void Credits::updateRedRect() {
// Actualiza el rectangulo del borde
void Credits::updateBorderRect() {
border_rect_.x = left_black_rect_.x + left_black_rect_.w;
border_rect_.y = top_black_rect_.y + top_black_rect_.h - 1;
border_rect_.w = right_black_rect_.x - border_rect_.x;
border_rect_.h = bottom_black_rect_.y - border_rect_.y + 1;
float raw_w = right_black_rect_.x - border_rect_.x;
float raw_h = bottom_black_rect_.y - border_rect_.y + 1.0f;
border_rect_.w = std::max(0.0f, raw_w);
border_rect_.h = std::max(0.0f, raw_h);
}
// Actualiza el estado de fade (time-based)
void Credits::updateAllFades(float delta_time) {
if (fading_) {
updateBlackRects(delta_time);
updateRedRect();
updateBorderRect();
}
fade_in_->update();
@@ -527,10 +554,10 @@ void Credits::cycleColors(float delta_time) {
// Ajustar valores de R
credits_state_.r += credits_state_.step_r * FRAME_ADJUSTMENT;
if (credits_state_.r >= UPPER_LIMIT) {
credits_state_.r = UPPER_LIMIT; // Clamp para evitar que se pase
credits_state_.r = UPPER_LIMIT; // Clamp para evitar que se pase
credits_state_.step_r = -credits_state_.step_r; // Cambia de dirección al alcanzar los límites
} else if (credits_state_.r <= LOWER_LIMIT) {
credits_state_.r = LOWER_LIMIT; // Clamp para evitar que se pase
credits_state_.r = LOWER_LIMIT; // Clamp para evitar que se pase
credits_state_.step_r = -credits_state_.step_r;
}
@@ -572,3 +599,114 @@ void Credits::renderPlayers() {
player->render();
}
}
// Inicializa variables
void Credits::initVars() {
// Inicialización segura de rects tal y como los mostraste
top_black_rect_ = {
play_area_.x,
param.game.game_area.rect.y,
play_area_.w,
black_bars_size_};
bottom_black_rect_ = {
play_area_.x,
param.game.game_area.rect.h - black_bars_size_,
play_area_.w,
black_bars_size_};
left_black_rect_ = {
play_area_.x,
param.game.game_area.center_y - 1,
0,
2};
right_black_rect_ = {
play_area_.x + play_area_.w,
param.game.game_area.center_y - 1,
0,
2};
initialized_ = false;
Section::name = Section::Name::CREDITS;
balloon_manager_->setPlayArea(play_area_);
fade_in_->setColor(param.fade.color);
fade_in_->setType(Fade::Type::FULLSCREEN);
fade_in_->setPostDuration(800);
fade_in_->setMode(Fade::Mode::IN);
fade_in_->activate();
fade_out_->setColor(0, 0, 0);
fade_out_->setType(Fade::Type::FULLSCREEN);
fade_out_->setPostDuration(7000);
updateBorderRect();
tiled_bg_->setColor(Color(255, 96, 96));
tiled_bg_->setSpeed(60.0F);
initPlayers();
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
fillTextTexture();
steps_ = static_cast<int>(std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4)));
}
void Credits::startCredits() {
// Guardar iniciales (enteros para contar "pasos" por píxel)
init_top_h = static_cast<int>(top_black_rect_.h);
init_bottom_y = static_cast<int>(bottom_black_rect_.y);
init_left_w = static_cast<int>(left_black_rect_.w);
init_right_x = static_cast<int>(right_black_rect_.x);
// Objetivos
int top_target_h = param.game.game_area.center_y - 1;
int bottom_target_y = param.game.game_area.center_y + 1;
int left_target_w = param.game.game_area.center_x;
int right_target_x = param.game.game_area.center_x;
// Pasos verticales
int pasos_top = std::max(0, top_target_h - init_top_h);
int pasos_bottom = std::max(0, init_bottom_y - bottom_target_y);
// Pasos horizontales. right se mueve a velocidad HORIZONTAL_SPEED, contamos pasos como unidades de movimiento equivalentes
int pasos_left = std::max(0, left_target_w - init_left_w);
int dx_right = std::max(0, init_right_x - right_target_x);
int pasos_right = (dx_right + (HORIZONTAL_SPEED - 1)) / HORIZONTAL_SPEED; // ceil
total_steps_ = pasos_top + pasos_bottom + pasos_left + pasos_right;
if (total_steps_ <= 0) total_steps_ = 1;
current_step_ = static_cast<float>(total_steps_);
// Reiniciar contadores y estado
credits_state_.black_rect_accumulator = 0.0f;
counter_pre_fade_ = 0.0f;
initialized_ = true;
// Asegurar volumen inicial consistente
if (steps_ <= 0) steps_ = 1;
float vol_f = initial_volume_ * (current_step_ / static_cast<float>(total_steps_));
setVolume(static_cast<int>(std::clamp(vol_f, 0.0f, static_cast<float>(initial_volume_))));
}
// Dibuja el rectángulo del borde si es visible
void Credits::drawBorderRect() {
// Umbral: cualquier valor menor que 1 píxel no se considera visible
constexpr float VISIBLE_THRESHOLD = 1.0f;
if (border_rect_.w < VISIBLE_THRESHOLD || border_rect_.h < VISIBLE_THRESHOLD) {
return; // no dibujar
}
const Color COLOR = color_.LIGHTEN();
SDL_Renderer* rdr = Screen::get()->getRenderer();
SDL_SetRenderDrawColor(rdr, COLOR.r, COLOR.g, COLOR.b, 0xFF);
// Convertir a enteros de forma conservadora para evitar líneas de 1px por redondeo extraño
SDL_Rect r;
r.x = static_cast<int>(std::floor(border_rect_.x + 0.5f));
r.y = static_cast<int>(std::floor(border_rect_.y + 0.5f));
r.w = static_cast<int>(std::max(0.0f, std::floor(border_rect_.w + 0.5f)));
r.h = static_cast<int>(std::max(0.0f, std::floor(border_rect_.h + 0.5f)));
if (r.w > 0 && r.h > 0) {
SDL_RenderRect(Screen::get()->getRenderer(), &border_rect_);
}
}

View File

@@ -29,9 +29,15 @@ class Credits {
// --- Métodos del bucle principal ---
void update(float delta_time); // Actualización principal de la lógica (time-based)
auto calculateDeltaTime() -> float; // Calcula el deltatime
void initVars(); // Inicializa variables
void startCredits(); // Inicializa mas variables
// --- Constantes de clase ---
static constexpr int PLAY_AREA_HEIGHT = 200;
static constexpr float FAST_FORWARD_MULTIPLIER = 6.0F;
static constexpr float BLACK_RECT_INTERVAL_S = 4.0F / 60.0F; // ~0.0667s
static constexpr float FRAMES_PER_SECOND = 60.0F;
static constexpr int HORIZONTAL_SPEED = 2;
// --- Objetos principales ---
std::unique_ptr<BalloonManager> balloon_manager_; // Gestión de globos
@@ -45,15 +51,26 @@ class Credits {
SDL_Texture* canvas_; // Textura donde se dibuja todo
// --- Temporización y contadores ---
Uint64 last_time_ = 0; // Último tiempo registrado para deltaTime
float counter_ = 0; // Contador principal de lógica
float counter_pre_fade_ = 0; // Activación del fundido final
float counter_prevent_endless_ = 0; // Prevención de bucle infinito
Uint64 last_time_ = 0; // Último tiempo registrado para deltaTime
float counter_ = 0.0F; // Contador principal de lógica
float counter_pre_fade_ = 0.0F; // Activación del fundido final
float counter_prevent_endless_ = 0.0F; // Prevención de bucle infinito
float current_step_ = 0.0F;
int total_steps_ = 1;
bool initialized_ = false;
// --- Guardar estados iniciales para cálculo de pasos ---
int init_top_h = 0;
int init_bottom_y = 0;
int init_left_w = 0;
int init_right_x = 0;
// --- Variables de estado ---
bool fading_ = false; // Estado del fade final
bool want_to_pass_ = false; // Jugador quiere saltarse créditos
bool mini_logo_on_position_ = false; // Minilogo en posición final
bool vertical_done_ = false;
bool horizontal_done_ = false;
// --- Diseño y posicionamiento ---
float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2; // Tamaño de las barras negras
@@ -127,6 +144,7 @@ class Credits {
void fillTextTexture(); // Crear textura de texto de créditos
void fillCanvas(); // Renderizar todos los sprites y fondos
void renderPlayers(); // Renderiza los jugadores
void drawBorderRect(); // Renderiza el rectangulo del borde
// --- Métodos de lógica del juego ---
void throwBalloons(float delta_time); // Lanzar globos al escenario (time-based)
@@ -138,7 +156,7 @@ class Credits {
// --- Métodos de interfaz ---
void updateBlackRects(); // Actualizar rectángulos negros (letterbox) (frame-based)
void updateBlackRects(float delta_time); // Actualizar rectángulos negros (letterbox) (time-based)
void updateRedRect(); // Actualizar rectángulo rojo (borde)
void updateBorderRect(); // Actualizar rectángulo rojo (borde)
void updateTextureDstRects(); // Actualizar destinos de texturas (frame-based)
void updateTextureDstRects(float delta_time); // Actualizar destinos de texturas (time-based)