#pragma once #include // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64 #include // Para shared_ptr, unique_ptr #include // Para string #include // Para vector #include // Para list #include "bullet.hpp" // for Bullet #include "demo.hpp" // for Demo #include "hit.hpp" // for Hit #include "item.hpp" // for Item (ptr only), ItemType #include "manage_hiscore_table.hpp" // for HiScoreEntry #include "options.hpp" // for Settings, settings #include "player.hpp" // for Player class Background; class Balloon; class BalloonManager; class BulletManager; class Fade; class Input; class PathSprite; class PauseManager; class Scoreboard; class Screen; class SmartSprite; class StageManager; class Tabe; class Texture; struct Path; namespace Difficulty { enum class Code; } // namespace Difficulty // --- Clase Game: núcleo principal del gameplay --- // // Esta clase gestiona toda la lógica del juego durante las partidas activas, // incluyendo mecánicas de juego, estados, objetos y sistemas de puntuación. // // Funcionalidades principales: // • Gestión de jugadores: soporte para 1 o 2 jugadores simultáneos // • Sistema de estados: fade-in, entrada, jugando, completado, game-over // • Mecánicas de juego: globos, balas, ítems, power-ups y efectos especiales // • Sistema de puntuación: scoreboard y tabla de récords // • Efectos temporales: tiempo detenido, ayudas automáticas // • Modo demo: reproducción automática para attract mode // • Gestión de fases: progresión entre niveles y dificultad // // Utiliza un sistema de tiempo basado en milisegundos para garantizar // comportamiento consistente independientemente del framerate. class Game { public: // --- Constantes --- static constexpr bool DEMO_OFF = false; // Modo demo desactivado static constexpr bool DEMO_ON = true; // Modo demo activado // --- Constructor y destructor --- Game(Player::Id player_id, int current_stage, bool demo_enabled); // Constructor principal ~Game(); // Destructor // --- Bucle principal --- void run(); // Ejecuta el bucle principal del juego private: // --- Enums --- enum class State { FADE_IN, // Transición de entrada ENTERING_PLAYER, // Jugador entrando SHOWING_GET_READY_MESSAGE, // Mostrando mensaje de preparado PLAYING, // Jugando COMPLETED, // Juego completado GAME_OVER, // Fin del juego }; // --- Constantes de tiempo (en segundos) --- static constexpr float HELP_COUNTER_S = 16.667F; // Contador de ayuda (1000 frames a 60fps → segundos) static constexpr float GAME_COMPLETED_START_FADE_S = 8.333F; // Inicio del fade al completar (500 frames → segundos) static constexpr float GAME_COMPLETED_END_S = 11.667F; // Fin del juego completado (700 frames → segundos) static constexpr float GAME_OVER_DURATION_S = 8.5F; static constexpr float TIME_STOPPED_DURATION_S = 6.0F; static constexpr float DEMO_FADE_PRE_DURATION_S = 0.5F; static constexpr int ITEM_POINTS_1_DISK_ODDS = 10; static constexpr int ITEM_POINTS_2_GAVINA_ODDS = 6; static constexpr int ITEM_POINTS_3_PACMAR_ODDS = 3; static constexpr int ITEM_CLOCK_ODDS = 5; static constexpr int ITEM_COFFEE_ODDS = 5; static constexpr int ITEM_POWER_BALL_ODDS = 0; static constexpr int ITEM_COFFEE_MACHINE_ODDS = 4; // --- Estructuras --- struct Helper { bool need_coffee{false}; // Indica si se necesitan cafes bool need_coffee_machine{false}; // Indica si se necesita PowerUp bool need_power_ball{false}; // Indica si se necesita una PowerBall float counter; // Contador para no dar ayudas consecutivas int item_disk_odds; // Probabilidad de aparición del objeto int item_gavina_odds; // Probabilidad de aparición del objeto int item_pacmar_odds; // Probabilidad de aparición del objeto int item_clock_odds; // Probabilidad de aparición del objeto int item_coffee_odds; // Probabilidad de aparición del objeto int item_coffee_machine_odds; // Probabilidad de aparición del objeto Helper() : counter(HELP_COUNTER_S * 1000), // Convertir a milisegundos para compatibilidad item_disk_odds(ITEM_POINTS_1_DISK_ODDS), item_gavina_odds(ITEM_POINTS_2_GAVINA_ODDS), item_pacmar_odds(ITEM_POINTS_3_PACMAR_ODDS), item_clock_odds(ITEM_CLOCK_ODDS), item_coffee_odds(ITEM_COFFEE_ODDS), item_coffee_machine_odds(ITEM_COFFEE_MACHINE_ODDS) {} }; // --- Objetos y punteros --- SDL_Renderer* renderer_; // El renderizador de la ventana Screen* screen_; // Objeto encargado de dibujar en pantalla Input* input_; // Manejador de entrada Scoreboard* scoreboard_; // Objeto para dibujar el marcador SDL_Texture* canvas_; // Textura para dibujar la zona de juego std::vector> players_; // Vector con los jugadores std::list> items_; // Vector con los items std::list> smart_sprites_; // Vector con los smartsprites std::list> path_sprites_; // Vector con los pathsprites std::vector> item_textures_; // Vector con las texturas de los items std::vector>> player_textures_; // Vector con todas las texturas de los jugadores std::vector> game_text_textures_; // Vector con las texturas para los sprites con textos 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 stage_manager_; // Objeto para gestionar las fases std::unique_ptr balloon_manager_; // Objeto para gestionar los globos std::unique_ptr bullet_manager_; // Objeto para gestionar las balas std::unique_ptr background_; // Objeto para dibujar el fondo del juego std::unique_ptr fade_in_; // Objeto para renderizar fades std::unique_ptr fade_out_; // Objeto para renderizar fades std::unique_ptr tabe_; // Objeto para gestionar el Tabe Volaor std::vector paths_; // Vector con los recorridos precalculados almacenados // --- Variables de estado --- HiScoreEntry hi_score_ = HiScoreEntry( Options::settings.hi_score_table[0].name, Options::settings.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta Demo demo_; // Variable con todas las variables relacionadas con el modo demo Difficulty::Code difficulty_ = Options::settings.difficulty; // Dificultad del juego Helper helper_; // Variable para gestionar las ayudas Uint64 last_time_ = 0; // Último tiempo registrado para deltaTime 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 float difficulty_score_multiplier_ = 1.0F; // Multiplicador de puntos en función de la dificultad float counter_ = 0.0F; // Contador para el juego float game_completed_timer_ = 0.0F; // Acumulador de tiempo para el tramo final (milisegundos) float game_over_timer_ = 0.0F; // Timer para el estado de fin de partida (milisegundos) float time_stopped_timer_ = 0.0F; // Temporizador para llevar la cuenta del tiempo detenido int menace_ = 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 // Estructuras para gestionar flags de eventos basados en tiempo struct GameOverFlags { bool music_fade_triggered = false; bool message_triggered = false; bool fade_out_triggered = false; void reset() { music_fade_triggered = false; message_triggered = false; fade_out_triggered = false; } } game_over_flags_; struct GameCompletedFlags { bool start_celebrations_triggered = false; bool end_celebrations_triggered = false; void reset() { start_celebrations_triggered = false; end_celebrations_triggered = false; } } game_completed_flags_; struct TimeStoppedFlags { bool color_flash_sound_played = false; bool warning_phase_started = false; void reset() { color_flash_sound_played = false; warning_phase_started = false; } } time_stopped_flags_; #ifdef _DEBUG bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados #endif // --- Ciclo principal del juego --- void update(float delta_time); // Actualiza la lógica principal del juego auto calculateDeltaTime() -> float; // Calcula el deltatime void render(); // Renderiza todos los elementos del juego void handleEvents(); // 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 cleanLists(); // Limpia vectores de elementos deshabilitados // --- Gestión de estados del juego --- void updateGameStates(float delta_time); // Actualiza todos los estados del juego void updateGameStateFadeIn(float delta_time); // Gestiona el estado de transición de entrada (time-based) void updateGameStateEnteringPlayer(float delta_time); // Gestiona el estado de entrada de jugador void updateGameStateShowingGetReadyMessage(float delta_time); // Gestiona el estado de mensaje "preparado" void updateGameStatePlaying(float delta_time); // Gestiona el estado de juego activo void updateGameStateCompleted(float delta_time); // Gestiona el estado de juego completado void updateGameStateGameOver(float delta_time); // Gestiona las actualizaciones continuas del estado de fin de partida // --- Gestión de jugadores --- void initPlayers(Player::Id player_id); // Inicializa los datos de los jugadores void updatePlayers(float delta_time); // Actualiza las variables y estados de los jugadores void renderPlayers(); // Renderiza todos los jugadores en pantalla void sortPlayersByZOrder(); // Reorganiza el orden de dibujado de jugadores auto getPlayer(Player::Id id) -> std::shared_ptr; // Obtiene un jugador por su identificador static auto getController(Player::Id player_id) -> int; // Obtiene el controlador asignado a un jugador // --- Estado de jugadores --- void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); // Actualiza estado entre jugadores void checkPlayersStatusPlaying(); // Verifica el estado de juego de todos los jugadores auto allPlayersAreWaitingOrGameOver() -> bool; // Verifica si todos esperan o han perdido auto allPlayersAreGameOver() -> bool; // Verifica si todos los jugadores han perdido auto allPlayersAreNotPlaying() -> bool; // Verifica si ningún jugador está activo // --- Colisiones de jugadores --- void handlePlayerCollision(std::shared_ptr& player, std::shared_ptr& balloon); // Procesa colisión de jugador con globo auto checkPlayerBalloonCollision(std::shared_ptr& player) -> std::shared_ptr; // Detecta colisión jugador-globo void checkPlayerItemCollision(std::shared_ptr& player); // Detecta colisión jugador-ítem // --- Sistema de entrada (input) --- void checkInput(); // Gestiona toda la entrada durante el juego void checkPauseInput(); // Verifica solicitudes de pausa de controladores // --- Entrada de jugadores normales --- void handlePlayersInput(); // Gestiona entrada de todos los jugadores void handleNormalPlayerInput(const std::shared_ptr& player); // Procesa entrada de un jugador específico void handleFireInput(const std::shared_ptr& player, Bullet::Type type); // Gestiona disparo de jugador void handleFireInputs(const std::shared_ptr& player, bool autofire); // Procesa disparos automáticos void handlePlayerContinueInput(const std::shared_ptr& player); // Permite continuar al jugador void handlePlayerWaitingInput(const std::shared_ptr& player); // Permite (re)entrar al jugador void handleNameInput(const std::shared_ptr& player); // Gestiona entrada de nombre del jugador // --- Entrada en modo demo --- void demoHandleInput(); // Gestiona entrada durante el modo demostración void demoHandlePassInput(); // Permite saltar la demostración void demoHandlePlayerInput(const std::shared_ptr& player, int index); // Procesa entrada de jugador en demo // --- Sistema de balas y proyectiles --- void checkBulletCollision(); // Verifica colisiones de todas las balas (delegado a BulletManager) // --- Colisiones específicas de balas --- auto checkBulletTabeCollision(const std::shared_ptr& bullet) -> bool; // Detecta colisión bala-Tabe auto checkBulletBalloonCollision(const std::shared_ptr& bullet) -> bool; // Detecta colisión bala-globo void processBalloonHit(const std::shared_ptr& bullet, const std::shared_ptr& balloon); // Procesa impacto en globo // --- Sistema de ítems y power-ups --- void updateItems(float delta_time); // Actualiza posición y estado de todos los ítems void renderItems(); // Renderiza todos los ítems activos auto dropItem() -> ItemType; // Determina aleatoriamente qué ítem soltar void createItem(ItemType type, float x, float y); // Crea un nuevo ítem en posición específica void freeItems(); // Libera memoria del vector de ítems void destroyAllItems(); // Elimina todos los ítems activos de la pantalla // --- ítems especiales --- void enableTimeStopItem(); // Activa el efecto de detener el tiempo void disableTimeStopItem(); // Desactiva el efecto de detener el tiempo void updateTimeStopped(float delta_time); // Actualiza el estado del tiempo detenido void handleGameCompletedEvents(); // Maneja eventos del juego completado void handleGameOverEvents(); // Maneja eventos discretos basados en tiempo durante game over void throwCoffee(int x, int y); // Crea efecto de café arrojado al ser golpeado // --- Gestión de caída de ítems --- void handleItemDrop(const std::shared_ptr& balloon, const std::shared_ptr& player); // Gestiona caída de ítem desde globo // --- Sprites inteligentes (smartsprites) --- void updateSmartSprites(float delta_time); // Actualiza todos los sprites con lógica propia (time-based) void renderSmartSprites(); // Renderiza todos los sprites inteligentes void freeSmartSprites(); // Libera memoria de sprites inteligentes // --- Sprites por ruta (pathsprites) --- void updatePathSprites(float delta_time); // Actualiza sprites que siguen rutas predefinidas void renderPathSprites(); // Renderiza sprites animados por ruta void freePathSprites(); // Libera memoria de sprites por ruta void initPaths(); // Inicializa rutas predefinidas para animaciones // --- Creación de sprites especiales --- void createItemText(int x, const std::shared_ptr& texture); // Crea texto animado para ítems void createMessage(const std::vector& paths, const std::shared_ptr& texture); // Crea mensaje con animación por ruta // --- Sistema de globos y enemigos --- void handleBalloonDestruction(const std::shared_ptr& balloon, const std::shared_ptr& player); // Procesa destrucción de globo void handleTabeHitEffects(); // Gestiona efectos al golpear a Tabe void checkAndUpdateBalloonSpeed(); // Ajusta velocidad de globos según progreso // --- Gestión de fases y progresión --- void updateStage(); // Verifica y actualiza cambio de fase void initDifficultyVars(); // Inicializa variables de dificultad // --- Sistema de amenaza --- void updateMenace(); // Gestiona el nivel de amenaza del juego void setMenace(); // Calcula y establece amenaza según globos activos // --- Puntuación y marcador --- void updateHiScore(); // Actualiza el récord máximo si es necesario void updateScoreboard(float delta_time); // Actualiza la visualización del marcador void updateHiScoreName(); // Pone en el marcador el nombre del primer jugador de la tabla void initScoreboard(); // Inicializa el sistema de puntuación // --- Modo demostración --- void initDemo(Player::Id player_id); // Inicializa variables para el modo demostración void updateDemo(float delta_time); // Actualiza lógica específica del modo demo // --- Recursos y renderizado --- void setResources(); // Asigna texturas y animaciones a los objetos void updateBackground(float delta_time); // Actualiza elementos del fondo (time-based) void fillCanvas(); // Renderiza elementos del área de juego en su textura void updateHelper(); // Actualiza variables auxiliares de renderizado // --- Sistema de audio --- static void playMusic(const std::string& music_file, int loop = -1); // Reproduce la música de fondo void stopMusic() const; // Detiene la reproducción de música static void pauseMusic(); // Pausa la música static void resumeMusic(); // Retoma la música que eestaba pausada void playSound(const std::string& name) const; // Reproduce un efecto de sonido específico 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 is_paused); // SISTEMA DE GRABACIÓN (CONDICIONAL) #ifdef RECORDING void updateRecording(float deltaTime); // Actualiza variables durante modo de grabación #endif // --- Depuración (solo en modo DEBUG) --- #ifdef _DEBUG void handleDebugEvents(const SDL_Event& event); // Comprueba los eventos en el modo DEBUG #endif };