From 808abb28ea749f1714a70e48b9f620e8e32a12b0 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 20 May 2026 07:57:36 +0200 Subject: [PATCH] Fase 9d: descomponer GameScene::update en sub-pasos privados update() pasa de 339 LOC monolitico (cognitive complexity ~137) a 18 LOC orquestadores. Cada seccion logica vive en su propio metodo privado con responsabilidad unica: - stepPhysics(dt): physics_world.update + postUpdate. - stepShootingInput(): SHOOT de P1/P2. - stepMidGameJoin(): START de jugador inactivo o muerto sin vidas. - stepContinueScreen(dt): wrapping del Systems::ContinueScreen + update de fondo. Devuelve true si frame debe terminar. - stepGameOver(dt): timer final + transicion a TITLE. Devuelve true si frame debe terminar. - stepDeathSequence(dt): death timer/respawn/transicion a CONTINUE. - stepStageStateMachine(dt): despacha a runStage{InitHud,LevelStart, Playing,LevelCompleted} segun el estado actual. - runCollisionDetections(): construye el Systems::Collision::Context y llama detectAll. GameScene.cpp acumulado tras Fase 9 (a+b+c+d): 1429 -> 1015 LOC. update() solo: 339 -> 18 LOC. Smoke test xvfb OK. Co-Authored-By: Claude Opus 4.7 (1M context) --- source/game/scenes/game_scene.cpp | 562 ++++++++++++++---------------- source/game/scenes/game_scene.hpp | 20 ++ 2 files changed, 287 insertions(+), 295 deletions(-) diff --git a/source/game/scenes/game_scene.cpp b/source/game/scenes/game_scene.cpp index a14828a..c7ee347 100644 --- a/source/game/scenes/game_scene.cpp +++ b/source/game/scenes/game_scene.cpp @@ -226,10 +226,28 @@ void GameScene::init() { } void GameScene::update(float delta_time) { - // === FÍSICA: integrar bodies del frame anterior y resolver colisiones === - // Se ejecuta al inicio del frame: las fuerzas aplicadas en el frame N-1 - // por processInput/AI se integran ahora, y postUpdate sincroniza los - // mirrors (center_/angle_) antes de la lógica de juego que los lee. + // Orquestador delgado: cada paso vive en su propia función para + // mantener update() legible y reducir complejidad cognitiva. + stepPhysics(delta_time); + + if (game_over_state_ == GameOverState::NONE) { + stepShootingInput(); + stepMidGameJoin(); + } + if (stepContinueScreen(delta_time)) { + return; + } + if (stepGameOver(delta_time)) { + return; + } + stepDeathSequence(delta_time); + stepStageStateMachine(delta_time); +} + +void GameScene::stepPhysics(float delta_time) { + // Las fuerzas aplicadas en el frame N-1 por processInput/AI se integran + // ahora; postUpdate sincroniza los mirrors (center_/angle_) antes de la + // lógica de juego que los lee. physics_world_.update(delta_time); for (auto& ship : ships_) { ship.postUpdate(delta_time); @@ -240,331 +258,285 @@ void GameScene::update(float delta_time) { for (auto& bullet : bullets_) { bullet.postUpdate(delta_time); } +} - // Processar disparos (state-based, no event-based) - if (game_over_state_ == GameOverState::NONE) { - auto* input = Input::get(); - - // Jugador 1 dispara (solo si está active) - if (match_config_.jugador1_actiu) { - if (input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { - disparar_bala(0); - } - } - - // Jugador 2 dispara (solo si está active) - if (match_config_.jugador2_actiu) { - if (input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { - disparar_bala(1); - } - } - - // [FIXED] Allow mid-game join: inactive or dead player presses START - // Only during PLAYING state (not INIT_HUD, CONTINUE, GAME_OVER) - if (stage_manager_->get_estat() == StageSystem::EstatStage::PLAYING) { - // Check if at least one player is alive and playing (game in progress) - bool algun_jugador_viu = false; - if (match_config_.jugador1_actiu && hit_timer_per_player_[0] != 999.0F) { - algun_jugador_viu = true; - } - if (match_config_.jugador2_actiu && hit_timer_per_player_[1] != 999.0F) { - algun_jugador_viu = true; - } - - // Only allow join if there's an active game - if (algun_jugador_viu) { - // P2 can join if not currently playing (never joined OR dead without lives) - bool p2_no_juga = !match_config_.jugador2_actiu || // Never joined - hit_timer_per_player_[1] == 999.0F; // Dead without lives - - if (p2_no_juga) { - if (input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT)) { - unir_jugador(1); - } - } - - // P1 can join if not currently playing (never joined OR dead without lives) - bool p1_no_juga = !match_config_.jugador1_actiu || // Never joined - hit_timer_per_player_[0] == 999.0F; // Dead without lives - - if (p1_no_juga) { - if (input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT)) { - unir_jugador(0); - } - } - } - } +void GameScene::stepShootingInput() { + auto* input = Input::get(); + if (match_config_.jugador1_actiu && + input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { + disparar_bala(0); } + if (match_config_.jugador2_actiu && + input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { + disparar_bala(1); + } +} - // Handle CONTINUE screen - if (game_over_state_ == GameOverState::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_) { - enemy.update(delta_time); - } - for (auto& bullet : bullets_) { - bullet.update(delta_time); - } - debris_manager_.update(delta_time); - floating_score_manager_.update(delta_time); +void GameScene::stepMidGameJoin() { + // Permitir join solo durante PLAYING. + if (stage_manager_->get_estat() != StageSystem::EstatStage::PLAYING) { return; } - // Handle final GAME OVER state - if (game_over_state_ == GameOverState::GAME_OVER) { - // Game over: only update timer, enemies, bullets, and debris - game_over_timer_ -= delta_time; - - if (game_over_timer_ <= 0.0F) { - // Aturar música de juego antes de tornar al título - Audio::get()->stopMusic(); - // Transición a pantalla de título - context_.setNextScene(SceneType::TITLE); - SceneManager::actual = SceneType::TITLE; - return; - } - - // Enemies and bullets continue moving during game over - for (auto& enemy : enemies_) { - enemy.update(delta_time); - } - - for (auto& bullet : bullets_) { - bullet.update(delta_time); - } - - debris_manager_.update(delta_time); - floating_score_manager_.update(delta_time); + // Solo se permite join si hay al menos un jugador vivo (no se puede + // hacer join en pantalla vacía). + const bool ALGU_VIU = + (match_config_.jugador1_actiu && hit_timer_per_player_[0] != 999.0F) || + (match_config_.jugador2_actiu && hit_timer_per_player_[1] != 999.0F); + if (!ALGU_VIU) { return; } - // Check death sequence state for BOTH players - bool algun_jugador_mort = false; + auto* input = Input::get(); + for (uint8_t pid = 0; pid < 2; pid++) { + const bool ACTIU = (pid == 0) ? match_config_.jugador1_actiu + : match_config_.jugador2_actiu; + const bool MUERTO_SIN_VIDAS = hit_timer_per_player_[pid] == 999.0F; + if (ACTIU && !MUERTO_SIN_VIDAS) { + continue; // jugador ya está jugando + } + const bool START_PRESSED = (pid == 0) + ? input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT) + : input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT); + if (START_PRESSED) { + unir_jugador(pid); + } + } +} + +auto GameScene::stepContinueScreen(float delta_time) -> bool { + if (game_over_state_ != GameOverState::CONTINUE) { + return false; + } + + 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); + + // Enemies, bullets y efectos siguen moviéndose en background. + for (auto& enemy : enemies_) { + enemy.update(delta_time); + } + for (auto& bullet : bullets_) { + bullet.update(delta_time); + } + debris_manager_.update(delta_time); + floating_score_manager_.update(delta_time); + return true; +} + +auto GameScene::stepGameOver(float delta_time) -> bool { + if (game_over_state_ != GameOverState::GAME_OVER) { + return false; + } + + game_over_timer_ -= delta_time; + if (game_over_timer_ <= 0.0F) { + Audio::get()->stopMusic(); + context_.setNextScene(SceneType::TITLE); + SceneManager::actual = SceneType::TITLE; + return true; + } + + // Enemies, bullets y efectos siguen moviéndose como fondo. + for (auto& enemy : enemies_) { + enemy.update(delta_time); + } + for (auto& bullet : bullets_) { + bullet.update(delta_time); + } + debris_manager_.update(delta_time); + floating_score_manager_.update(delta_time); + return true; +} + +auto GameScene::stepDeathSequence(float delta_time) -> bool { + bool algun_mort = false; for (uint8_t i = 0; i < 2; i++) { - if (hit_timer_per_player_[i] > 0.0F && hit_timer_per_player_[i] < 999.0F) { - algun_jugador_mort = true; - // Death sequence active: update timer - hit_timer_per_player_[i] += delta_time; + if (hit_timer_per_player_[i] <= 0.0F || hit_timer_per_player_[i] >= 999.0F) { + continue; + } + algun_mort = true; + hit_timer_per_player_[i] += delta_time; - // Check if death duration completed (only trigger ONCE using sentinel value) - if (hit_timer_per_player_[i] >= Defaults::Game::DEATH_DURATION) { - // *** PHASE 3: RESPAWN OR GAME OVER *** + if (hit_timer_per_player_[i] < Defaults::Game::DEATH_DURATION) { + continue; + } - // Decrement lives for this player (only once) - lives_per_player_[i]--; + // *** PHASE 3: RESPAWN OR GAME OVER *** + lives_per_player_[i]--; + if (lives_per_player_[i] > 0) { + Vec2 spawn_pos = obtenir_punt_spawn(i); + ships_[i].init(&spawn_pos, /*activar_invulnerabilitat=*/true); + hit_timer_per_player_[i] = 0.0F; + continue; + } - if (lives_per_player_[i] > 0) { - // Respawn ship en spawn position con invulnerabilidad - Vec2 spawn_pos = obtenir_punt_spawn(i); - ships_[i].init(&spawn_pos, true); - hit_timer_per_player_[i] = 0.0F; - } else { - // Player is permanently dead (out of lives) - // Set sentinel value to prevent re-entering this block - hit_timer_per_player_[i] = 999.0F; - - // Check if ALL ACTIVE players are dead (trigger continue screen) - bool p1_dead = !match_config_.jugador1_actiu || lives_per_player_[0] <= 0; - bool p2_dead = !match_config_.jugador2_actiu || lives_per_player_[1] <= 0; - - if (p1_dead && p2_dead) { - game_over_state_ = GameOverState::CONTINUE; - continue_counter_ = Defaults::Game::CONTINUE_COUNT_START; - continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION; - } - } - } + // Sin vidas: marcar definitivamente muerto y comprobar transición a CONTINUE. + hit_timer_per_player_[i] = 999.0F; + const bool P1_DEAD = !match_config_.jugador1_actiu || lives_per_player_[0] <= 0; + const bool P2_DEAD = !match_config_.jugador2_actiu || lives_per_player_[1] <= 0; + if (P1_DEAD && P2_DEAD) { + game_over_state_ = GameOverState::CONTINUE; + continue_counter_ = Defaults::Game::CONTINUE_COUNT_START; + continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION; } } - // If any player is dead, still update enemies/bullets/effects - if (algun_jugador_mort) { - // Enemies and bullets continue moving during death sequence + // Si hay algún muerto, los enemigos/balas/efectos siguen actualizándose + // aunque otros jugadores aún jueguen. + if (algun_mort) { for (auto& enemy : enemies_) { enemy.update(delta_time); } - for (auto& bullet : bullets_) { bullet.update(delta_time); } - debris_manager_.update(delta_time); floating_score_manager_.update(delta_time); - - // Don't return - allow alive players to continue playing } + return algun_mort; +} - // *** STAGE SYSTEM STATE MACHINE *** - - StageSystem::EstatStage state = stage_manager_->get_estat(); - - switch (state) { - case StageSystem::EstatStage::INIT_HUD: { - // Update stage manager timer (pot canviar l'state!) - stage_manager_->update(delta_time); - - // [FIX] Si l'state ha canviat durante update(), salir immediatament - // per evitar recalcular la posición de la ship con el nuevo timer - if (stage_manager_->get_estat() != StageSystem::EstatStage::INIT_HUD) { - break; - } - - // Calcular global progress (0.0 al inicio → 1.0 al final) - float global_progress = 1.0F - (stage_manager_->get_timer_transicio() / Defaults::Game::INIT_HUD_DURATION); - global_progress = std::min(1.0F, global_progress); - - // [NEW] Calcular progress independiente para cada nave - float ship1_progress = Systems::InitHud::computeRangeProgress( - global_progress, - Defaults::Game::INIT_HUD_SHIP1_RATIO_INIT, - Defaults::Game::INIT_HUD_SHIP1_RATIO_END); - - float ship2_progress = Systems::InitHud::computeRangeProgress( - global_progress, - Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT, - Defaults::Game::INIT_HUD_SHIP2_RATIO_END); - - // [MODIFICAT] Animar AMBAS naves con sus progress respectivos - if (match_config_.jugador1_actiu && ship1_progress < 1.0F) { - Vec2 pos_p1 = Systems::InitHud::computeShipPosition(ship1_progress, obtenir_punt_spawn(0)); - ships_[0].setCenter(pos_p1); - } - - if (match_config_.jugador2_actiu && ship2_progress < 1.0F) { - Vec2 pos_p2 = Systems::InitHud::computeShipPosition(ship2_progress, obtenir_punt_spawn(1)); - ships_[1].setCenter(pos_p2); - } - - // Una vez l'animación acaba, permetre control normal - // pero mantenir la posición inicial especial hasta LEVEL_START - +void GameScene::stepStageStateMachine(float delta_time) { + const StageSystem::EstatStage STATE = stage_manager_->get_estat(); + switch (STATE) { + case StageSystem::EstatStage::INIT_HUD: + runStageInitHud(delta_time); break; - } - - case StageSystem::EstatStage::LEVEL_START: { - // [DEBUG] Log entrada a LEVEL_START - static bool first_entry = true; - if (first_entry) { - std::cout << "[LEVEL_START] ENTERED with P1 pos.y=" << ships_[0].getCenter().y << '\n'; - first_entry = false; - } - - // Update countdown timer - stage_manager_->update(delta_time); - - // [NEW] Allow both ships movement and shooting during intro - for (uint8_t i = 0; i < 2; i++) { - bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; - if (jugador_actiu && hit_timer_per_player_[i] == 0.0F) { // Only active, alive players - ships_[i].processInput(delta_time, i); - ships_[i].update(delta_time); - } - } - - // [NEW] Update bullets - for (auto& bullet : bullets_) { - bullet.update(delta_time); - } - - // [NEW] Update debris - debris_manager_.update(delta_time); + case StageSystem::EstatStage::LEVEL_START: + runStageLevelStart(delta_time); break; - } - - case StageSystem::EstatStage::PLAYING: { - // [NEW] Update stage manager (spawns enemies, pause if BOTH dead) - bool pause_spawn = (hit_timer_per_player_[0] > 0.0F && hit_timer_per_player_[1] > 0.0F); - stage_manager_->getSpawnController().update(delta_time, enemies_, pause_spawn); - - // [NEW] Check stage completion (only when at least one player alive) - bool algun_jugador_viu = (hit_timer_per_player_[0] == 0.0F || hit_timer_per_player_[1] == 0.0F); - if (algun_jugador_viu) { - auto& spawn_ctrl = stage_manager_->getSpawnController(); - if (spawn_ctrl.tots_enemics_destruits(enemies_)) { - stage_manager_->stage_completat(); - Audio::get()->playSound(Defaults::Sound::GOOD_JOB_COMMANDER, Audio::Group::GAME); - break; - } - } - - // [EXISTING] Normal gameplay - update active players - for (uint8_t i = 0; i < 2; i++) { - bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; - if (jugador_actiu && hit_timer_per_player_[i] == 0.0F) { // Only active, alive players - ships_[i].processInput(delta_time, i); - ships_[i].update(delta_time); - } - } - - for (auto& enemy : enemies_) { - enemy.update(delta_time); - } - - for (auto& bullet : bullets_) { - bullet.update(delta_time); - } - - { - Systems::Collision::Context col_ctx{ - .ships = ships_, - .enemies = enemies_, - .bullets = bullets_, - .hit_timer_per_player = hit_timer_per_player_, - .score_per_player = score_per_player_, - .lives_per_player = lives_per_player_, - .debris_manager = debris_manager_, - .floating_score_manager = floating_score_manager_, - .match_config = match_config_, - .on_player_hit = [this](uint8_t pid) { tocado(pid); }, - }; - Systems::Collision::detectAll(col_ctx); - } - debris_manager_.update(delta_time); - floating_score_manager_.update(delta_time); + case StageSystem::EstatStage::PLAYING: + runStagePlaying(delta_time); break; - } - case StageSystem::EstatStage::LEVEL_COMPLETED: - // Update countdown timer - stage_manager_->update(delta_time); - - // [NEW] Allow both ships movement and shooting during outro - for (uint8_t i = 0; i < 2; i++) { - bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; - if (jugador_actiu && hit_timer_per_player_[i] == 0.0F) { // Only active, alive players - ships_[i].processInput(delta_time, i); - ships_[i].update(delta_time); - } - } - - // [NEW] Update bullets (allow last shots to continue) - for (auto& bullet : bullets_) { - bullet.update(delta_time); - } - - // [NEW] Update debris (from last destroyed enemies) - debris_manager_.update(delta_time); - floating_score_manager_.update(delta_time); + runStageLevelCompleted(delta_time); break; } } +void GameScene::runStageInitHud(float delta_time) { + // Update stage manager timer (puede cambiar el state). + stage_manager_->update(delta_time); + // Si el state cambió, salir para no usar el timer del nuevo state. + if (stage_manager_->get_estat() != StageSystem::EstatStage::INIT_HUD) { + return; + } + + float global_progress = 1.0F - (stage_manager_->get_timer_transicio() / Defaults::Game::INIT_HUD_DURATION); + global_progress = std::min(1.0F, global_progress); + + const float SHIP1_P = Systems::InitHud::computeRangeProgress( + global_progress, + Defaults::Game::INIT_HUD_SHIP1_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP1_RATIO_END); + const float SHIP2_P = Systems::InitHud::computeRangeProgress( + global_progress, + Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT, + Defaults::Game::INIT_HUD_SHIP2_RATIO_END); + + if (match_config_.jugador1_actiu && SHIP1_P < 1.0F) { + ships_[0].setCenter(Systems::InitHud::computeShipPosition(SHIP1_P, obtenir_punt_spawn(0))); + } + if (match_config_.jugador2_actiu && SHIP2_P < 1.0F) { + ships_[1].setCenter(Systems::InitHud::computeShipPosition(SHIP2_P, obtenir_punt_spawn(1))); + } +} + +void GameScene::runStageLevelStart(float delta_time) { + stage_manager_->update(delta_time); + + // Ambas naves pueden moverse y disparar durante el intro. + for (uint8_t i = 0; i < 2; i++) { + const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; + if (ACTIU && hit_timer_per_player_[i] == 0.0F) { + ships_[i].processInput(delta_time, i); + ships_[i].update(delta_time); + } + } + for (auto& bullet : bullets_) { + bullet.update(delta_time); + } + debris_manager_.update(delta_time); +} + +void GameScene::runStagePlaying(float delta_time) { + const bool PAUSE_SPAWN = (hit_timer_per_player_[0] > 0.0F && hit_timer_per_player_[1] > 0.0F); + stage_manager_->getSpawnController().update(delta_time, enemies_, PAUSE_SPAWN); + + // Stage completado: cuando al menos un jugador está vivo y todos los enemies muertos. + const bool ALGU_VIU = (hit_timer_per_player_[0] == 0.0F || hit_timer_per_player_[1] == 0.0F); + if (ALGU_VIU && stage_manager_->getSpawnController().tots_enemics_destruits(enemies_)) { + stage_manager_->stage_completat(); + Audio::get()->playSound(Defaults::Sound::GOOD_JOB_COMMANDER, Audio::Group::GAME); + return; + } + + // Gameplay normal: ships activos + entidades + colisiones + efectos. + for (uint8_t i = 0; i < 2; i++) { + const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; + if (ACTIU && hit_timer_per_player_[i] == 0.0F) { + ships_[i].processInput(delta_time, i); + ships_[i].update(delta_time); + } + } + for (auto& enemy : enemies_) { + enemy.update(delta_time); + } + for (auto& bullet : bullets_) { + bullet.update(delta_time); + } + + runCollisionDetections(); + debris_manager_.update(delta_time); + floating_score_manager_.update(delta_time); +} + +void GameScene::runStageLevelCompleted(float delta_time) { + stage_manager_->update(delta_time); + for (uint8_t i = 0; i < 2; i++) { + const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; + if (ACTIU && hit_timer_per_player_[i] == 0.0F) { + ships_[i].processInput(delta_time, i); + ships_[i].update(delta_time); + } + } + for (auto& bullet : bullets_) { + bullet.update(delta_time); + } + debris_manager_.update(delta_time); + floating_score_manager_.update(delta_time); +} + +void GameScene::runCollisionDetections() { + Systems::Collision::Context col_ctx{ + .ships = ships_, + .enemies = enemies_, + .bullets = bullets_, + .hit_timer_per_player = hit_timer_per_player_, + .score_per_player = score_per_player_, + .lives_per_player = lives_per_player_, + .debris_manager = debris_manager_, + .floating_score_manager = floating_score_manager_, + .match_config = match_config_, + .on_player_hit = [this](uint8_t pid) { tocado(pid); }, + }; + Systems::Collision::detectAll(col_ctx); +} + void GameScene::draw() { // Handle CONTINUE screen if (game_over_state_ == GameOverState::CONTINUE) { diff --git a/source/game/scenes/game_scene.hpp b/source/game/scenes/game_scene.hpp index e58a4a0..36b2984 100644 --- a/source/game/scenes/game_scene.hpp +++ b/source/game/scenes/game_scene.hpp @@ -96,4 +96,24 @@ class GameScene { // [NEW] Función helper del marcador [[nodiscard]] std::string buildScoreboard() const; + + // Sub-pasos de update() (descompuestos en Fase 9d para reducir + // complejidad cognitiva; cada uno es responsable de una sección). + void stepPhysics(float delta_time); + void stepShootingInput(); + void stepMidGameJoin(); + // Devuelven true si el frame debe salir tras esta sección. + [[nodiscard]] auto stepContinueScreen(float delta_time) -> bool; + [[nodiscard]] auto stepGameOver(float delta_time) -> bool; + // Avanza el death timer / respawn / transition a CONTINUE. Devuelve + // true si algun jugador está en secuencia de muerte (para que el + // caller actualice efectos sin gameplay). + [[nodiscard]] auto stepDeathSequence(float delta_time) -> bool; + void stepStageStateMachine(float delta_time); + void runStageInitHud(float delta_time); + void runStageLevelStart(float delta_time); + void runStagePlaying(float delta_time); + void runStageLevelCompleted(float delta_time); + // Helper: ejecuta colisiones de gameplay con el Context preparado. + void runCollisionDetections(); };