diff --git a/source/fade.cpp b/source/fade.cpp index 80548d8..c29b182 100644 --- a/source/fade.cpp +++ b/source/fade.cpp @@ -56,6 +56,11 @@ void Fade::reset() { // Pinta una transición en pantalla void Fade::render() { if (state_ != State::NOT_ENABLED) { + // Para fade IN terminado, no renderizar (auto-desactivación visual) + if (state_ == State::FINISHED && mode_ == Mode::IN) { + return; + } + SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr); } } @@ -83,6 +88,10 @@ void Fade::updatePreState() { if (elapsed_time >= static_cast(pre_duration_)) { state_ = State::FADING; + // CRÍTICO: Reinicializar tiempo de inicio para tipos que usan random_squares_start_time_ + if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) { + random_squares_start_time_ = SDL_GetTicks(); + } } } @@ -100,6 +109,9 @@ void Fade::updateFadingState() { case Type::RANDOM_SQUARE2: updateRandomSquare2Fade(); break; + case Type::DIAGONAL: + updateDiagonalFade(); + break; case Type::VENETIAN: updateVenetianFade(); break; @@ -124,7 +136,7 @@ void Fade::updatePostState() { // Mantener el alpha final correcto para cada tipo de fade Uint8 post_alpha = a_; - if (type_ == Type::RANDOM_SQUARE2) { + if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) { post_alpha = (mode_ == Mode::OUT) ? 255 : 0; } @@ -263,6 +275,150 @@ void Fade::updateRandomSquare2Fade() { } } +void Fade::updateDiagonalFade() { + Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_; + + int total_squares = num_squares_width_ * num_squares_height_; + + // Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados + int activation_time = random_squares_duration_ - square_transition_duration_; + activation_time = std::max(activation_time, square_transition_duration_); + + // Calcula cuántas diagonales deberían estar activas + int max_diagonal = num_squares_width_ + num_squares_height_ - 1; // Número total de diagonales + int active_diagonals = 0; + + if (mode_ == Mode::OUT) { + // OUT: Activa diagonales gradualmente desde esquina superior izquierda + if (elapsed_time < static_cast(activation_time)) { + float activation_progress = static_cast(elapsed_time) / activation_time; + active_diagonals = static_cast(activation_progress * max_diagonal); + } else { + active_diagonals = max_diagonal; // Activar todas + } + + // Activa cuadrados por diagonales + for (int diagonal = 0; diagonal < active_diagonals; ++diagonal) { + activateDiagonal(diagonal, elapsed_time); + } + } else { + // IN: Todas las diagonales empiezan activas, van desapareciendo + active_diagonals = max_diagonal; + + // Activa diagonales gradualmente para transición + if (elapsed_time < static_cast(activation_time)) { + float activation_progress = static_cast(elapsed_time) / activation_time; + int diagonals_starting_transition = static_cast(activation_progress * max_diagonal); + + for (int diagonal = 0; diagonal < diagonals_starting_transition; ++diagonal) { + activateDiagonal(diagonal, elapsed_time); + } + } else { + // Activar transición en todas las diagonales restantes + for (int diagonal = 0; diagonal < max_diagonal; ++diagonal) { + activateDiagonal(diagonal, elapsed_time); + } + } + } + + drawDiagonal(); + + value_ = calculateValue(0, total_squares, active_diagonals * (total_squares / max_diagonal)); + + // Comprueba si ha terminado - todas las diagonales activadas y último cuadrado completó transición + bool all_completed = (active_diagonals >= max_diagonal); + if (all_completed) { + // Verificar que todos han completado su transición individual + for (int i = 0; i < total_squares; ++i) { + if (square_age_[i] >= 0) { // Cuadrado activado + Uint32 square_elapsed = elapsed_time - square_age_[i]; + if (square_elapsed < static_cast(square_transition_duration_)) { + all_completed = false; + break; + } + } + } + + if (all_completed) { + // Pintar textura final: OUT opaca, IN transparente + Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0; + cleanBackbuffer(r_, g_, b_, final_alpha); + changeToPostState(); + } + } +} + +void Fade::activateDiagonal(int diagonal_index, Uint32 current_time) { + // Para cada diagonal, activamos los cuadrados que pertenecen a esa diagonal + // Diagonal 0: (0,0) + // Diagonal 1: (1,0), (0,1) + // Diagonal 2: (2,0), (1,1), (0,2) + // etc. + + for (int x = 0; x < num_squares_width_; ++x) { + int y = diagonal_index - x; + + // Verificar que y está dentro de los límites + if (y >= 0 && y < num_squares_height_) { + // Convertir coordenadas (x,y) a índice en el vector + int index = y * num_squares_width_ + x; + + if (index >= 0 && index < static_cast(square_age_.size())) { + if (square_age_[index] == -1) { + square_age_[index] = current_time; // Guarda el tiempo de activación + } + } + } + } +} + +void Fade::drawDiagonal() { + auto *temp = SDL_GetRenderTarget(renderer_); + SDL_SetRenderTarget(renderer_, backbuffer_); + + // CRÍTICO: Limpiar la textura antes de dibujar + SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); + SDL_RenderClear(renderer_); + + SDL_BlendMode blend_mode; + SDL_GetRenderDrawBlendMode(renderer_, &blend_mode); + SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha + + Uint32 current_time = SDL_GetTicks() - random_squares_start_time_; + + // Lógica unificada: sobre textura transparente, pintar cuadrados según su estado + for (size_t i = 0; i < square_.size(); ++i) { + Uint8 current_alpha = 0; + + if (square_age_[i] == -1) { + // Cuadrado no activado + if (mode_ == Mode::OUT) { + current_alpha = 0; // OUT: transparente si no activado + } else { + current_alpha = a_; // IN: opaco si no activado + } + } else { + // Cuadrado activado - calculamos progreso + Uint32 square_elapsed = current_time - square_age_[i]; + float progress = std::min(static_cast(square_elapsed) / square_transition_duration_, 1.0f); + + if (mode_ == Mode::OUT) { + current_alpha = static_cast(progress * a_); // 0 → 255 + } else { + current_alpha = static_cast((1.0f - progress) * a_); // 255 → 0 + } + } + + if (current_alpha > 0) { + SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha); + SDL_RenderFillRect(renderer_, &square_[i]); + } + } + + SDL_SetRenderDrawBlendMode(renderer_, blend_mode); + SDL_SetRenderTarget(renderer_, temp); +} + void Fade::drawRandomSquares(int active_count) { auto *temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_); @@ -471,6 +627,33 @@ void Fade::activate() { break; } + case Type::DIAGONAL: { + rect1_ = {.x = 0, .y = 0, .w = static_cast(param.game.width / num_squares_width_), .h = static_cast(param.game.height / num_squares_height_)}; + square_.clear(); + square_age_.clear(); + + // Añade los cuadrados al vector en orden (sin desordenar) + for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) { + rect1_.x = (i % num_squares_width_) * rect1_.w; + rect1_.y = (i / num_squares_width_) * rect1_.h; + square_.push_back(rect1_); + square_age_.push_back(-1); // -1 indica cuadrado no activado aún + } + + // Textura inicial: OUT transparente, IN opaca + Uint8 initial_alpha = (mode_ == Mode::OUT) ? 0 : 255; + cleanBackbuffer(r_, g_, b_, initial_alpha); + + // Deja el color listo para usar (alpha target para los cuadrados) + a_ = 255; // Siempre usar 255 como alpha target + + // Inicializa el tiempo de inicio y recalcula la duración de transición + random_squares_start_time_ = SDL_GetTicks(); + square_transition_duration_ = std::max(random_squares_duration_ / 4, 100); // Mínimo 100ms + + break; + } + case Type::VENETIAN: { // Limpia la textura a_ = mode_ == Mode::OUT ? 0 : 255; diff --git a/source/fade.h b/source/fade.h index 789e42f..eff1303 100644 --- a/source/fade.h +++ b/source/fade.h @@ -15,7 +15,8 @@ class Fade { CENTER = 1, // Fundido desde el centro RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios RANDOM_SQUARE2 = 3, // Fundido con cuadrados aleatorios (variante 2) - VENETIAN = 4, // Fundido tipo persiana veneciana + DIAGONAL = 4, // Fundido diagonal desde esquina superior izquierda + VENETIAN = 5, // Fundido tipo persiana veneciana }; enum class Mode : Uint8 { @@ -97,6 +98,7 @@ class Fade { void updateCenterFade(); // Actualiza el fundido desde el centro void updateRandomSquareFade(); // Actualiza el fundido con cuadrados aleatorios void updateRandomSquare2Fade(); // Actualiza el fundido con cuadrados aleatorios (variante 2) + void updateDiagonalFade(); // Actualiza el fundido diagonal void updateVenetianFade(); // Actualiza el fundido tipo persiana veneciana void updateVenetianRectangles(); // Actualiza los rectángulos del efecto veneciano void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano @@ -105,5 +107,7 @@ class Fade { void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central void drawRandomSquares(int active_count = -1); // Dibuja los cuadrados aleatorios del fundido void drawRandomSquares2(); // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2) + void drawDiagonal(); // Dibuja los cuadrados con patrón diagonal + void activateDiagonal(int diagonal_index, Uint32 current_time); // Activa una diagonal específica void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido }; \ No newline at end of file diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 5e99827..099e1f6 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -1653,6 +1653,7 @@ void Game::updateDemo() { // Activa el fundido antes de acabar con los datos de la demo if (demo_.counter == TOTAL_DEMO_DATA - 200) { fade_out_->setType(Fade::Type::RANDOM_SQUARE2); + fade_out_->setPostDuration(param.fade.post_duration_ms); fade_out_->activate(); } diff --git a/source/sections/game.h b/source/sections/game.h index a9861f8..158f5ee 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -259,7 +259,6 @@ class Game { // --- Gestión de fases y progresión --- void updateStage(); // Verifica y actualiza cambio de fase - void setTotalPower(); // Calcula poder total necesario para completar el juego void initDifficultyVars(); // Inicializa variables de dificultad // --- Sistema de amenaza ---