Fase 9b: extraer ContinueSystem de GameScene

GameScene::actualitzar_continue, processar_input_continue y el
helper check_and_apply_continue_timeout (3 funciones, ~140 LOC) salen
a Systems::ContinueScreen en source/game/systems/continue_system.{hpp,cpp}.

API:
- struct Systems::ContinueScreen::Context: agrupa el estado mutable
  (state, counter, tick_timer, continues_used, game_over_timer,
  lives/score/hit_timer arrays, ships, match_config) y un callback
  get_spawn_point inyectado por GameScene.
- update(ctx, dt): avanza countdown automatico y transiciona a
  GAME_OVER si timeout.
- processInput(ctx): START revive jugador(es), THRUST/SHOOT acelera
  countdown.

Helpers privados (revivePlayer, checkAndApplyTimeout) en anonymous
namespace del .cpp para evitar contaminar el header.

GameOverState ahora con underlying type explicito (uint8_t) para
permitir forward-declaration limpia en continue_system.hpp.

dibuixar_continue y unir_jugador se quedan en GameScene (render y
gameplay normal, no parte del state machine).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
JailDesignerandClaude Opus 4.7 committed 2026-05-20 07:50:43 +02:00
1 parent 896a899b0f
commit 816bc02d9d
4 files changed
+175 -116

No files matched your search

+16 -112
View File
@@ -22,6 +22,7 @@
#include "core/system/global_events.hpp"
#include "game/stage_system/stage_loader.hpp"
#include "game/systems/collision_system.hpp"
#include "game/systems/continue_system.hpp"
// Using declarations per simplificar el codi
using SceneManager::SceneContext;
@@ -296,8 +297,21 @@ void GameScene::update(float delta_time) {
// Handle CONTINUE screen
if (game_over_state_ == GameOverState::CONTINUE) {
actualitzar_continue(delta_time);
processar_input_continue();
Systems::ContinueScreen::Context cont_ctx{
.state = game_over_state_,
.counter = continue_counter_,
.tick_timer = continue_tick_timer_,
.continues_used = continues_used_,
.game_over_timer = game_over_timer_,
.lives_per_player = lives_per_player_,
.score_per_player = score_per_player_,
.hit_timer_per_player = hit_timer_per_player_,
.ships = ships_,
.match_config = match_config_,
.get_spawn_point = [this](uint8_t pid) { return obtenir_punt_spawn(pid); },
};
Systems::ContinueScreen::update(cont_ctx, delta_time);
Systems::ContinueScreen::processInput(cont_ctx);
// Still update enemies, bullets, and effects during continue screen
for (auto& enemy : enemies_) {
@@ -1106,116 +1120,6 @@ void GameScene::disparar_bala(uint8_t player_id) {
}
}
// ==================== CONTINUE & JOIN SYSTEM ====================
void GameScene::check_and_apply_continue_timeout() {
if (continue_counter_ < 0) {
game_over_state_ = GameOverState::GAME_OVER;
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
}
}
void GameScene::actualitzar_continue(float delta_time) {
continue_tick_timer_ -= delta_time;
if (continue_tick_timer_ <= 0.0F) {
continue_counter_--;
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
// Check if timeout reached (counter < 0)
check_and_apply_continue_timeout();
// Play sound only if still in CONTINUE state (not transitioned to GAME_OVER)
if (game_over_state_ == GameOverState::CONTINUE) {
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
}
}
}
void GameScene::processar_input_continue() {
auto* input = Input::get();
// Check START for both players
bool p1_start = input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
bool p2_start = input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
if (p1_start || p2_start) {
// Check continue limit (skip if infinite continues)
if (!Defaults::Game::INFINITE_CONTINUES && continues_used_ >= Defaults::Game::MAX_CONTINUES) {
// Max continues reached → final game over
game_over_state_ = GameOverState::GAME_OVER;
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
return;
}
// Only increment if not infinite
if (!Defaults::Game::INFINITE_CONTINUES) {
continues_used_++;
}
// Determine which player(s) to revive
uint8_t player_to_revive = p1_start ? 0 : 1;
// Reset score and lives (KEEP level and enemies!)
score_per_player_[player_to_revive] = 0;
lives_per_player_[player_to_revive] = Defaults::Game::STARTING_LIVES;
hit_timer_per_player_[player_to_revive] = 0.0F;
// Activate player if not already
if (player_to_revive == 0) {
match_config_.jugador1_actiu = true;
} else {
match_config_.jugador2_actiu = true;
}
// Spawn with invulnerability
Vec2 spawn_pos = obtenir_punt_spawn(player_to_revive);
ships_[player_to_revive].init(&spawn_pos, true);
// Check if other player wants to continue too
if (p1_start && p2_start) {
uint8_t other_player = 1;
score_per_player_[other_player] = 0;
lives_per_player_[other_player] = Defaults::Game::STARTING_LIVES;
hit_timer_per_player_[other_player] = 0.0F;
match_config_.jugador2_actiu = true;
Vec2 spawn_pos2 = obtenir_punt_spawn(other_player);
ships_[other_player].init(&spawn_pos2, true);
}
// Resume game
game_over_state_ = GameOverState::NONE;
continue_counter_ = 0;
continue_tick_timer_ = 0.0F;
// Play continue confirmation sound
Audio::get()->playSound(Defaults::Sound::START, Audio::Group::GAME);
return;
}
// Check THRUST/FIRE to accelerate countdown (DO_NOT_ALLOW_REPEAT to avoid spam)
bool thrust_p1 = input->checkActionPlayer1(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT);
bool thrust_p2 = input->checkActionPlayer2(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT);
bool fire_p1 = input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
bool fire_p2 = input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
if (thrust_p1 || thrust_p2 || fire_p1 || fire_p2) {
continue_counter_--;
// Check if timeout reached (counter < 0)
check_and_apply_continue_timeout();
// Play sound only if still in CONTINUE state
if (game_over_state_ == GameOverState::CONTINUE) {
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
}
// Reset timer to prevent double-decrement
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
}
}
void GameScene::dibuixar_continue() {
const SDL_FRect& play_area = Defaults::Zones::PLAYAREA;
constexpr float spacing = 4.0F;