Files
2025-10-24 18:22:15 +02:00

358 lines
23 KiB
C++

#pragma once
#include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64
#include <list> // Para list
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "bullet.hpp" // for Bullet
#include "demo.hpp" // for Demo
#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:
using Players = std::vector<std::shared_ptr<Player>>;
// --- 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
Players players_; // Vector con los jugadores
Players players_draw_list_; // Vector con los jugadores ordenados para ser renderizados
std::list<std::unique_ptr<Item>> items_; // Vector con los items
std::list<std::unique_ptr<SmartSprite>> smart_sprites_; // Vector con los smartsprites
std::list<std::unique_ptr<PathSprite>> path_sprites_; // Vector con los pathsprites
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures_; // Vector con todas las texturas de los jugadores
std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
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::unique_ptr<PauseManager> pause_manager_; // Objeto para gestionar la pausa
std::unique_ptr<StageManager> stage_manager_; // Objeto para gestionar las fases
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
std::unique_ptr<BulletManager> bullet_manager_; // Objeto para gestionar las balas
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
std::vector<Path> 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
float time_stopped_sound_timer_ = 0.0F; // Temporizador para controlar el sonido 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
// 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
auto getPlayer(Player::Id id) -> std::shared_ptr<Player>; // 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>& player, std::shared_ptr<Balloon>& balloon); // Procesa colisión de jugador con globo
auto checkPlayerBalloonCollision(std::shared_ptr<Player>& player) -> std::shared_ptr<Balloon>; // Detecta colisión jugador-globo
void checkPlayerItemCollision(std::shared_ptr<Player>& 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>& player); // Procesa entrada de un jugador específico
void handleFireInput(const std::shared_ptr<Player>& player, Bullet::Type type); // Gestiona disparo de jugador
void handleFireInputs(const std::shared_ptr<Player>& player, bool autofire); // Procesa disparos automáticos
void handlePlayerContinueInput(const std::shared_ptr<Player>& player); // Permite continuar al jugador
void handlePlayerWaitingInput(const std::shared_ptr<Player>& player); // Permite (re)entrar al jugador
void handleNameInput(const std::shared_ptr<Player>& 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>& player, int index); // Procesa entrada de jugador en demo
// --- Colisiones específicas de balas ---
auto checkBulletTabeCollision(const std::shared_ptr<Bullet>& bullet) -> bool; // Detecta colisión bala-Tabe
auto checkBulletBalloonCollision(const std::shared_ptr<Bullet>& bullet) -> bool; // Detecta colisión bala-globo
void processBalloonHit(const std::shared_ptr<Bullet>& bullet, const std::shared_ptr<Balloon>& 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>& balloon, const std::shared_ptr<Player>& 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>& texture); // Crea texto animado para ítems
void createMessage(const std::vector<Path>& paths, const std::shared_ptr<Texture>& texture); // Crea mensaje con animación por ruta
// --- Sistema de globos y enemigos ---
void handleBalloonDestruction(const std::shared_ptr<Balloon>& balloon, const std::shared_ptr<Player>& 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
// --- Gestion y dibujado de jugadores en z-order ---
static void buildPlayerDrawList(const Players& elements, Players& draw_list); // Construye el draw_list a partir del vector principal
static void updatePlayerDrawList(const Players& elements, Players& draw_list); // Actualiza draw_list tras cambios en los z_order
static void renderPlayerDrawList(const Players& draw_list); // Dibuja en el orden definido
static auto findPlayerIndex(const Players& elems, const std::shared_ptr<Player>& who) -> size_t;
static void sendPlayerToBack(Players& elements, const std::shared_ptr<Player>& who, Players& draw_list); // Envia al jugador al fondo de la pantalla
static void bringPlayerToFront(Players& elements, const std::shared_ptr<Player>& who, Players& draw_list); // Envia al jugador al frente de la pantalla
// --- Varios ---
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
};