diff --git a/source/director.cpp b/source/director.cpp index 7b8ea00..31055e2 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -42,7 +42,7 @@ Director::Director(int argc, std::span argv) { Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #elif _DEBUG - Section::name = Section::Name::CREDITS; + Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #else // NORMAL GAME Section::name = Section::Name::LOGO; diff --git a/source/sections/game.cpp b/source/sections/game.cpp index d307d8f..cc76105 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -210,7 +210,7 @@ void Game::updateHiScore() { } } -// Actualiza las variables del jugador +// Actualiza las variables del jugador (frame-based) void Game::updatePlayers() { for (auto &player : players_) { player->update(); @@ -246,6 +246,42 @@ void Game::updatePlayers() { sortPlayersByZOrder(); } +// Actualiza las variables del jugador (time-based) +void Game::updatePlayers(float deltaTime) { + for (auto &player : players_) { + player->update(deltaTime); + + if (player->isPlaying()) { + // Comprueba la colisión entre el jugador y los globos + auto balloon = checkPlayerBalloonCollision(player); + + // Si hay colisión + if (balloon) { + // Si el globo está parado y el temporizador activo, lo explota + if (balloon->isStopped() && time_stopped_counter_ > 0) { + balloon_manager_->popBalloon(balloon); + } + // En caso contrario, el jugador ha sido golpeado por un globo activo + else { + handlePlayerCollision(player, balloon); + + if (demo_.enabled && allPlayersAreNotPlaying()) { + fade_out_->setType(Fade::Type::RANDOM_SQUARE2); + fade_out_->setPostDuration(500); + fade_out_->activate(); + } + } + } + + // Comprueba las colisiones entre el jugador y los items + checkPlayerItemCollision(player); + } + } + + // Organiza la lista de jugadores + sortPlayersByZOrder(); +} + // Dibuja a los jugadores void Game::renderPlayers() { for (auto &player : players_) { @@ -892,14 +928,14 @@ void Game::updateTimeStopped() { if (time_stopped_counter_ > 0) { time_stopped_counter_--; if (time_stopped_counter_ > 120) { - if (time_stopped_counter_ % 30 == 0) { + if (static_cast(time_stopped_counter_) % 30 == 0) { playSound("clock.wav"); } } else { - if (time_stopped_counter_ % 30 == 0) { + if (static_cast(time_stopped_counter_) % 30 == 0) { balloon_manager_->normalColorsToAllBalloons(); playSound("clock.wav"); - } else if (time_stopped_counter_ % 30 == 15) { + } else if (static_cast(time_stopped_counter_) % 30 == 15) { balloon_manager_->reverseColorsToAllBalloons(); playSound("clock.wav"); } @@ -909,9 +945,10 @@ void Game::updateTimeStopped() { } } +// Actualiza toda la lógica del juego (frame-based) void Game::update() { - if (SDL_GetTicks() - ticks_ > param.game.speed) { - ticks_ = SDL_GetTicks(); + if (SDL_GetTicks() - last_time_ > param.game.speed) { + last_time_ = SDL_GetTicks(); screen_->update(); updateDemo(); @@ -925,6 +962,20 @@ void Game::update() { Audio::update(); } +// Actualiza toda la lógica del juego (time-based) +void Game::update(float deltaTime) { + screen_->update(); + + updateDemo(); +#ifdef RECORDING + updateRecording(); +#endif + updateGameStates(); + fillCanvas(); + + Audio::update(); +} + // Dibuja el juego void Game::render() { screen_->start(); // Prepara para empezar a dibujar en la textura de juego @@ -1006,13 +1057,24 @@ void Game::disableTimeStopItem() { balloon_manager_->normalColorsToAllBalloons(); } +// Calcula el deltatime +auto Game::calculateDeltaTime() -> float { + const Uint64 current_time = SDL_GetTicks(); + const float delta_time = static_cast(current_time - last_time_); + last_time_ = current_time; + return delta_time; +} + // Bucle para el juego void Game::run() { + last_time_ = SDL_GetTicks(); + while (Section::name == Section::Name::GAME) { #ifndef RECORDING checkInput(); #endif - update(); + const float delta_time = calculateDeltaTime(); + update(delta_time); handleEvents(); // Tiene que ir antes del render render(); } diff --git a/source/sections/game.h b/source/sections/game.h index afc0f2b..053ef38 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -77,7 +77,7 @@ class Game { 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 - int counter; // Contador para no dar ayudas consecutivas + 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 @@ -134,14 +134,14 @@ class Game { 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 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa + 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_; // 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 + float counter_ = 0; // Contador para el juego + float game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos + float game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida + float time_stopped_counter_ = 0; // 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 @@ -154,25 +154,28 @@ class Game { #endif // --- Ciclo principal del juego --- - void update(); // Actualiza la lógica principal del juego - void render(); // Renderiza todos los elementos del juego + void update(); // Actualiza la lógica principal del juego (frame-based) + void update(float deltaTime); // Actualiza la lógica principal del juego (time-based) + 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 cleanVectors(); // Limpia vectores de elementos deshabilitados // --- Gestión de estados del juego --- - void updateGameStates(); // Actualiza todos los estados del juego - void updateGameStateFadeIn(); // Gestiona el estado de transición de entrada - void updateGameStateEnteringPlayer(); // Gestiona el estado de entrada de jugador - void updateGameStateShowingGetReadyMessage(); // Gestiona el estado de mensaje "preparado" - void updateGameStatePlaying(); // Gestiona el estado de juego activo - void updateGameStateCompleted(); // Gestiona el estado de juego completado - void updateGameStateGameOver(); // Gestiona el estado de fin de partida + void updateGameStates(); // Actualiza todos los estados del juego (usa deltaTime interno) + void updateGameStateFadeIn(); // Gestiona el estado de transición de entrada + void updateGameStateEnteringPlayer(); // Gestiona el estado de entrada de jugador + void updateGameStateShowingGetReadyMessage(); // Gestiona el estado de mensaje "preparado" + void updateGameStatePlaying(); // Gestiona el estado de juego activo + void updateGameStateCompleted(); // Gestiona el estado de juego completado + void updateGameStateGameOver(); // Gestiona el estado de fin de partida // --- Gestión de jugadores --- void initPlayers(Player::Id player_id); // Inicializa los datos de los jugadores - void updatePlayers(); // Actualiza las variables y estados de los jugadores + void updatePlayers(); // Actualiza las variables y estados de los jugadores (frame-based) + void updatePlayers(float deltaTime); // Actualiza las variables y estados de los jugadores (time-based) 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 @@ -229,9 +232,10 @@ class Game { 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(); // Actualiza el estado del tiempo detenido + void enableTimeStopItem(); // Activa el efecto de detener el tiempo + void disableTimeStopItem(); // Desactiva el efecto de detener el tiempo + void updateTimeStopped(); // Actualiza el estado del tiempo detenido (frame-based) + void updateTimeStopped(float deltaTime); // Actualiza el estado del tiempo detenido (time-based) void throwCoffee(int x, int y); // Crea efecto de café arrojado al ser golpeado // --- Gestión de caída de ítems ---