diff --git a/source/pause_manager.h b/source/pause_manager.h new file mode 100644 index 0000000..dcae760 --- /dev/null +++ b/source/pause_manager.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include +#include + +// Clase dedicada para manejar el sistema de pausa +class PauseManager { + public: + // Enum encapsulado dentro de la clase + enum class Source : uint8_t { + NONE = 0, + PLAYER = 1 << 0, // 0001 + SERVICE_MENU = 1 << 1, // 0010 + FOCUS_LOST = 1 << 2 // 0100 + }; + + // Operadores para trabajar con las banderas (funciones friend) + friend Source operator|(Source a, Source b) { + return static_cast(static_cast(a) | static_cast(b)); + } + + friend Source operator&(Source a, Source b) { + return static_cast(static_cast(a) & static_cast(b)); + } + + friend Source operator~(Source a) { + return static_cast(~static_cast(a)); + } + + friend Source& operator|=(Source& a, Source b) { + return a = a | b; + } + + friend Source& operator&=(Source& a, Source b) { + return a = a & b; + } + + private: + Source flags_ = Source::NONE; + std::function onPauseChangedCallback_; + + bool hasFlag(Source flag) const { + return (flags_ & flag) != Source::NONE; + } + + void notifyPauseChanged() { + if (onPauseChangedCallback_) { + onPauseChangedCallback_(isPaused()); + } + } + + public: + // Constructor con callback opcional + explicit PauseManager(std::function callback = nullptr) + : onPauseChangedCallback_(callback) {} + + // Establece/quita una fuente de pausa específica + void setFlag(Source source, bool enable) { + bool wasPaused = isPaused(); + + if (enable) { + flags_ |= source; + } else { + flags_ &= ~source; + } + + // Solo notifica si cambió el estado general de pausa + if (wasPaused != isPaused()) { + notifyPauseChanged(); + } + } + + // Métodos específicos para cada fuente + void setPlayerPause(bool enable) { setFlag(Source::PLAYER, enable); } + void setServiceMenuPause(bool enable) { setFlag(Source::SERVICE_MENU, enable); } + void setFocusLossPause(bool enable) { setFlag(Source::FOCUS_LOST, enable); } + + // Toggle para el jugador (más común) + void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); } + + // Getters + bool isPaused() const { return flags_ != Source::NONE; } + bool isPlayerPaused() const { return hasFlag(Source::PLAYER); } + bool isServiceMenuPaused() const { return hasFlag(Source::SERVICE_MENU); } + bool isFocusLossPaused() const { return hasFlag(Source::FOCUS_LOST); } + + // Obtiene las banderas actuales + Source getFlags() const { return flags_; } + + // Limpia todas las pausas (útil para reset) + void clearAll() { + if (isPaused()) { + flags_ = Source::NONE; + notifyPauseChanged(); + } + } + + // Método para debug + std::string getStatusString() const { + if (flags_ == Source::NONE) return "Active"; + + std::string result = "Paused by: "; + bool first = true; + + if (hasFlag(Source::PLAYER)) { + if (!first) result += ", "; + result += "Player"; + first = false; + } + if (hasFlag(Source::SERVICE_MENU)) { + if (!first) result += ", "; + result += "ServiceMenu"; + first = false; + } + if (hasFlag(Source::FOCUS_LOST)) { + if (!first) result += ", "; + result += "FocusLoss"; + first = false; + } + + return result; + } + + // Permite cambiar el callback en runtime + void setCallback(std::function callback) { + onPauseChangedCallback_ = callback; + } +}; \ No newline at end of file diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 387640c..187b484 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -30,6 +30,7 @@ #include "manage_hiscore_table.h" // Para HiScoreEntry, ManageHiScoreTable #include "param.h" // Para Param, param, ParamGame, ParamScoreboard, ParamFade, ParamBalloon #include "path_sprite.h" // Para Path, PathSprite, createPath, PathType +#include "pause_manager.h" // Para PauseManager #include "player.h" // Para Player #include "resource.h" // Para Resource #include "scoreboard.h" // Para Scoreboard @@ -50,6 +51,7 @@ Game::Game(Player::Id player_id, int current_stage, bool demo) input_(Input::get()), background_(std::make_unique()), 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([this](bool isPaused) { onPauseStateChanged(isPaused); })), fade_in_(std::make_unique()), fade_out_(std::make_unique()), balloon_manager_(std::make_unique()), @@ -914,7 +916,7 @@ void Game::render() { // Actualiza los estados del juego void Game::updateGameStates() { - if (!paused_) { + if (!pause_manager_->isPaused()) { switch (state_) { case State::FADE_IN: updateGameStateFadeIn(); @@ -1121,11 +1123,11 @@ void Game::checkEvents() { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_EVENT_WINDOW_FOCUS_LOST: { - pause(!demo_.enabled); + pause_manager_->setFocusLossPause(!demo_.enabled); break; } case SDL_EVENT_WINDOW_FOCUS_GAINED: { - pause(false); + pause_manager_->setFocusLossPause(false); break; } default: @@ -1156,13 +1158,6 @@ void Game::updateScoreboard() { scoreboard_->update(); } -// Pausa el juego -void Game::pause(bool value) { - paused_ = value; - screen_->attenuate(paused_); - tabe_->pauseTimer(paused_); -} - // Añade una puntuación a la tabla de records void Game::addScoreToScoreBoard(const std::shared_ptr &player) { const auto ENTRY = HiScoreEntry(trim(player->getLastEnterName()), player->getScore(), player->get1CC()); @@ -1242,17 +1237,16 @@ void Game::checkInput() { // Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego. void Game::checkPauseInput() { // Comprueba los mandos - auto gamepads = input_->getGamepads(); - for (auto gamepad : gamepads) { + for (auto gamepad : input_->getGamepads()) { if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) { - pause(!paused_); + pause_manager_->togglePlayerPause(); return; } } // Comprueba el teclado if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) { - pause(!paused_); + pause_manager_->togglePlayerPause(); return; } } @@ -1872,21 +1866,11 @@ void Game::checkServiceMenu() { return; } - static bool was_paused_before_service_menu_ = false; - static bool service_menu_was_active_ = false; - - bool service_menu_is_active = ServiceMenu::get()->isEnabled(); - - if (service_menu_is_active && !service_menu_was_active_) { - // El menú acaba de abrirse - was_paused_before_service_menu_ = paused_; - pause(true); - } else if (!service_menu_is_active && service_menu_was_active_) { - // El menú acaba de cerrarse - pause(was_paused_before_service_menu_); + if (ServiceMenu::get()->isEnabled()) { + pause_manager_->setServiceMenuPause(true); + } else { + pause_manager_->setServiceMenuPause(false); } - - service_menu_was_active_ = service_menu_is_active; } // Mueve el jugador para pintarlo al fondo de la lista de jugadores @@ -1899,6 +1883,11 @@ void Game::sendPlayerToTheFront(const std::shared_ptr &player) { players_to_put_at_front_.push_back(player); } +void Game::onPauseStateChanged(bool isPaused) { + screen_->attenuate(isPaused); + tabe_->pauseTimer(isPaused); +} + #ifdef _DEBUG // Comprueba los eventos en el modo DEBUG void Game::checkDebugEvents(const SDL_Event &event) { diff --git a/source/sections/game.h b/source/sections/game.h index 5b13217..a86037e 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -3,6 +3,7 @@ #include // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64, Uint8 #include // Para shared_ptr, unique_ptr +#include // Para Set #include // Para string #include // Para vector @@ -11,6 +12,7 @@ #include "manage_hiscore_table.h" // Para HiScoreEntry #include "options.h" // Para SettingsOptions, settings #include "path_sprite.h" // Para PathSprite, Path +#include "pause_manager.h" // Para PauseManager #include "player.h" // Para Player #include "smart_sprite.h" // Para SmartSprite #include "utils.h" // Para Demo @@ -116,6 +118,7 @@ class Game { std::vector> item_animations_; // Vector con las animaciones de los items std::vector> player_animations_; // Vector con las animaciones del jugador + std::unique_ptr pause_manager_; // Objeto para gestionar la pausa std::unique_ptr fade_in_; // Objeto para renderizar fades std::unique_ptr fade_out_; // Objeto para renderizar fades std::unique_ptr balloon_manager_; // Objeto para gestionar los globos @@ -133,17 +136,15 @@ class Game { Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima - bool paused_ = false; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade) - // bool paused_by_service_menu_ = false; - float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad - int counter_ = 0; // Contador para el juego - 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 + float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad + int counter_ = 0; // Contador para el juego + 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 std::vector> players_to_put_at_back_; std::vector> players_to_put_at_front_; Hit hit_; // Para representar colisiones en pantalla @@ -158,7 +159,6 @@ class Game { void checkEvents(); // Procesa los eventos del sistema en cola void checkState(); // Verifica y actualiza el estado actual del juego void setState(State state); // Cambia el estado del juego - void pause(bool value); // Pausa o reanuda el juego void cleanVectors(); // Limpia vectores de elementos deshabilitados // --- Gestión de estados del juego --- @@ -294,6 +294,7 @@ class Game { void sendPlayerToTheBack(const std::shared_ptr &player); // Mueve el jugador para pintarlo al fondo de la lista de jugadores void sendPlayerToTheFront(const std::shared_ptr &player); // Mueve el jugador para pintarlo el primero de la lista de jugadores + void onPauseStateChanged(bool isPaused); // SISTEMA DE GRABACIÓN (CONDICIONAL) #ifdef RECORDING