diff --git a/source/credits.cpp b/source/credits.cpp index 74d00c7..ead2187 100644 --- a/source/credits.cpp +++ b/source/credits.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #include "credits.h" #include // Para SDL_BLENDMODE_BLEND #include // Para SDL_PollEvent, SDL_Event, SDL_QUIT @@ -18,6 +21,7 @@ #include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "utils.h" // Para Color, no_color, shdw_txt_color, Zone #include "player.h" +#include "fade.h" // Textos constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; @@ -26,22 +30,34 @@ constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; Credits::Credits() : balloon_manager_(std::make_unique()), text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), - tiled_bg_(std::make_unique(param.game.game_area.rect, TiledBGMode::DIAGONAL)) + tiled_bg_(std::make_unique(param.game.game_area.rect, TiledBGMode::DIAGONAL)), + fade_in_(std::make_unique()), + fade_out_(std::make_unique()) { section::name = section::Name::CREDITS; top_black_rect_ = {play_area_.x, 0, 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_}; balloon_manager_->setPlayArea(play_area_); + fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b); + fade_in_->setType(FadeType::FULLSCREEN); + fade_in_->setPost(50); + fade_in_->setMode(FadeMode::IN); + fade_in_->activate(); + fade_out_->setColor(0, 0, 0); + fade_out_->setType(FadeType::FULLSCREEN); + fade_out_->setPost(400); initPlayers(); SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND); fillTextTexture(); - JA_PlayMusic(Resource::get()->getMusic("credits.ogg")); + // JA_PlayMusic(Resource::get()->getMusic("credits.ogg")); + steps_ = std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4)); } // Destructor Credits::~Credits() { SDL_DestroyTexture(text_texture_); + resetVolume(); } // Bucle principal @@ -59,9 +75,7 @@ void Credits::run() // Actualiza las variables void Credits::update() { - constexpr int TICKS_SPEED = 15; - - if (SDL_GetTicks() - ticks_ > TICKS_SPEED) + if (SDL_GetTicks() - ticks_ > ticks_speed_) { ticks_ = SDL_GetTicks(); tiled_bg_->update(); @@ -72,7 +86,7 @@ void Credits::update() { player->update(); } - updateFinalFade(); + updateAllFades(); Screen::get()->update(); ++counter_; } @@ -97,17 +111,28 @@ void Credits::render() // Dibuja los titulos de credito SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &credits_rect_src_, &credits_rect_dst_); + + // Dibuja el mini_logo SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_); // Dibuja los rectangulos negros + // SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0x27, 0x27, 0x36, 255); SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 255); SDL_RenderFillRect(Screen::get()->getRenderer(), &top_black_rect_); SDL_RenderFillRect(Screen::get()->getRenderer(), &bottom_black_rect_); SDL_RenderFillRect(Screen::get()->getRenderer(), &left_black_rect_); SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_); - SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_); - + // Si el mini_logo está en su destino, lo dibuja encima del resto + if (mini_logo_on_position_) + { + SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_); + } + + // Dibuja el fade sobre el resto + fade_in_->render(); + fade_out_->render(); + // Vuelca el contenido del renderizador en pantalla Screen::get()->blit(); } @@ -136,10 +161,17 @@ void Credits::checkInput() // Comprueba si se ha pulsado cualquier botón (de los usados para jugar) if (Input::get()->checkAnyButtonPressed()) { - // JA_StopMusic(); - // section::name = section::Name::LOGO; - // return; - fading = true; + if (mini_logo_on_position_) + { + // Si el mini_logo ha llegado a su posición final, al pulsar cualquier tecla se activa el fundido + fading_ = true; + } + else + { + // Si todavía estan los creditos en marcha, se pasan solos a toda pastilla + want_to_pass_ = true; + ticks_speed_ = 3; + } } // Comprueba los inputs que se pueden introducir en cualquier sección del juego @@ -239,10 +271,38 @@ void Credits::updateTextureDstRects() { if (counter_ % 10 == 0) { - --credits_rect_dst_.y; - --mini_logo_rect_dst_.y; + // Comprueba la posición de la textura con los titulos de credito + if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y) + { + --credits_rect_dst_.y; + } + + // Comprueba la posición de la textura con el mini_logo + if (mini_logo_rect_dst_.y == mini_logo_final_pos_) + { + mini_logo_on_position_ = true; + + // Si el jugador quiere pasar los titulos de credito, el fade se inicia solo + if (want_to_pass_) + { + fading_ = true; + } + + // Se activa el contador para evitar que la sección sea infinita + if (counter_prevent_endless_ == 1000) + { + fading_ = true; + } + else + { + ++counter_prevent_endless_; + } + } + else + { + --mini_logo_rect_dst_.y; + } } - mini_logo_rect_dst_.y = std::max(mini_logo_rect_dst_.y, mini_logo_final_pos_); } // Tira globos al escenario @@ -313,6 +373,7 @@ void Credits::initPlayers() // Actualiza los rectangulos negros void Credits::updateBlackRects() { + static int current_step = steps_; 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 @@ -324,27 +385,78 @@ void Credits::updateBlackRects() // 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); + + --current_step; + setVolume(static_cast(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) { + // 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 + 4, param.game.game_area.center_x); // Incrementa la anchura y modifica la posición del rectangulo situado a la derecha right_black_rect_.w += 4; right_black_rect_.x = std::max(right_black_rect_.x - 4, param.game.game_area.center_x); + + --current_step; + setVolume(static_cast(initial_volume_ * current_step / steps_)); + } + else + { + // Si los rectangulos izquierdo y derecho han llegado al centro + setVolume(0); + JA_StopMusic(); + if (counter_pre_fade_ == 400) + { + fade_out_->activate(); + } + else + { + ++counter_pre_fade_; + } } } } // Actualiza el estado de fade -void Credits::updateFinalFade() +void Credits::updateAllFades() { - if (fading) + if (fading_) { updateBlackRects(); } + + fade_in_->update(); + if (fade_in_->hasEnded()) + { + if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) + { + JA_PlayMusic(Resource::get()->getMusic("credits.ogg")); + } + } + + fade_out_->update(); + if (fade_out_->hasEnded()) + { + section::name = section::Name::LOGO; + } +} + +// Establece el nivel de volumen +void Credits::setVolume(int amount) +{ + options.audio.music.volume = std::clamp(amount, 0, 100); + JA_SetMusicVolume(to_JA_volume(options.audio.music.volume)); +} + +// Reestablece el nivel de volumen +void Credits::resetVolume() +{ + options.audio.music.volume = initial_volume_; + JA_SetMusicVolume(to_JA_volume(options.audio.music.volume)); } \ No newline at end of file diff --git a/source/credits.h b/source/credits.h index 0dfb8df..a8616eb 100644 --- a/source/credits.h +++ b/source/credits.h @@ -4,9 +4,11 @@ #include // Para Uint32 #include // Para unique_ptr #include "param.h" +#include "options.h" class BalloonManager; class TiledBG; class Player; +class Fade; class Credits { @@ -15,14 +17,23 @@ private: std::unique_ptr balloon_manager_; // Objeto para gestionar los globos SDL_Texture *text_texture_; // Textura con el texto std::unique_ptr tiled_bg_; // Objeto para dibujar el mosaico animado de fondo + std::unique_ptr fade_in_; // Objeto para realizar el fundido de entrada + std::unique_ptr fade_out_; // Objeto para realizar el fundido de salida std::vector> players_; // Vector con los jugadores // Variables - Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa - Uint32 counter_ = 0; // Contador para la lógica de la clase - int black_bars_size_ = 28; // Tamaño de las barras negras - int mini_logo_final_pos_ = 0; // Ubicación donde se detiene el minilogo - bool fading = false; // Indica si se está realizando el fade final + Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa + Uint32 ticks_speed_ = 15; // Velocidad del bucle update + Uint32 counter_ = 0; // Contador para la lógica de la clase + Uint32 counter_pre_fade_ = 0; // Contador para activar el fundido final + Uint32 counter_prevent_endless_ = 0; // Contador para evitar que el juego se quede para siempre en los creditos + int black_bars_size_ = 28; // Tamaño de las barras negras + int mini_logo_final_pos_ = 0; // Ubicación donde se detiene el minilogo + bool fading_ = false; // Indica si se está realizando el fade final + bool want_to_pass_ = false; // Indica si el jugador quiere saltarse los titulos de crédito + bool mini_logo_on_position_ = false; // Indica si el minilogo ya se ha quedado en su posición + int initial_volume_ = options.audio.music.volume; // Volumen actual al crear el objeto + int steps_ = 0; // Cantidad de pasos a dar para ir reduciendo el audio // Rectangulos SDL_Rect credits_rect_src_ = param.game.game_area.rect; // Rectangulo con el texto de los créditos (origen) @@ -67,7 +78,13 @@ private: void updateBlackRects(); // Actualiza el estado de fade - void updateFinalFade(); + void updateAllFades(); + + // Establece el nivel de volumen + void setVolume(int amount); + + // Reestablece el nivel de volumen + void resetVolume(); public: // Constructor diff --git a/source/director.cpp b/source/director.cpp index c577f41..86d2b67 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -60,7 +60,7 @@ Director::Director(int argc, const char *argv[]) section::name = section::Name::GAME; section::options = section::Options::GAME_PLAY_1P; #elif DEBUG - section::name = section::Name::CREDITS; + section::name = section::Name::LOGO; #else // NORMAL GAME section::name = section::Name::LOGO; section::attract_mode = section::AttractMode::TITLE_TO_DEMO; diff --git a/source/game.cpp b/source/game.cpp index d688912..d0aec86 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -303,7 +303,16 @@ void Game::updateGameOverState() if (fade_->hasEnded()) { - section::name = section::Name::HI_SCORE_TABLE; + if (game_completed_counter_ > 0) + { + // Los jugadores han completado el juego + section::name = section::Name::CREDITS; + } + else + { + // La partida ha terminado con la derrota de los jugadores + section::name = section::Name::HI_SCORE_TABLE; + } } } } @@ -951,8 +960,7 @@ void Game::disableTimeStopItem() void Game::checkMusicStatus() { // Si la música no está sonando - if (JA_GetMusicState() == JA_MUSIC_INVALID || - JA_GetMusicState() == JA_MUSIC_STOPPED) + if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) // Si se ha completado el juego o los jugadores han terminado, detiene la música state_ == GameState::COMPLETED || allPlayersAreGameOver() ? JA_StopMusic() : JA_PlayMusic(Resource::get()->getMusic("playing.ogg")); }