Plan A: frame loop al Director, interfaz Scene común

Cada escena ahora implementa una interfaz Scene { handleEvent, update,
draw, isFinished } y el Director es quien posee el bucle de frames.
Antes había tres bucles casi idénticos duplicados en logo/title/game
con ~30 LOC cada uno; ahora hay uno solo en Director::runFrameLoop.

Cambios:

- Nueva interfaz core/system/scene.hpp (pura virtual).
- Cada escena hereda final + override de handleEvent/update/draw/
  isFinished. Los métodos privados que ya existían (update, draw,
  processar_events) pasan a públicos como override; processar_events
  se renombra a handleEvent.
- Director::run gestiona la transición entre escenas vía
  buildScene(type) → runFrameLoop(scene), ambas estáticas.
- isFinished() = context_.nextScene() != mi_tipo, así que la única
  vía de transición es context_.setNextScene().
- TitleScene tenía un bug latente: llamaba a setNextScene(GAME)
  prematuramente al entrar en PLAYER_JOIN_PHASE, lo que con el nuevo
  modelo habría saltado las animaciones de salida. Movido el
  setNextScene al final de BLACK_SCREEN, que es donde la transición
  ocurría de verdad (vía la variable global SceneManager::actual).
- LogoScene::draw llamaba a clear() y present() dentro del draw, una
  anomalía. Sacados al Director para que la composición sea uniforme.
- Eliminadas todas las escrituras a SceneManager::actual desde las
  escenas. El Director es ahora la única fuente que actualiza la
  variable global (sigue ahí para lecturas externas, por compatibilidad).

Net: -60 LOC reales (las escenas pierden ~25 cada una de boilerplate),
y queda un único punto de inyección para los overlays globales que
vienen en el siguiente paso del roadmap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 09:25:56 +02:00
parent a7aecbadd1
commit 5e82dc880f
9 changed files with 181 additions and 241 deletions
+12 -63
View File
@@ -14,12 +14,10 @@
#include "core/audio/audio.hpp"
#include "core/entities/entity.hpp"
#include "core/input/input.hpp"
#include "core/input/mouse.hpp"
#include "core/math/easing.hpp"
#include "core/physics/collision.hpp"
#include "core/rendering/line_renderer.hpp"
#include "core/system/scene_context.hpp"
#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"
@@ -64,69 +62,21 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
for (auto& enemy : enemies_) {
enemy = Enemy(sdl.getRenderer());
}
// El resto del estado del juego (física, stages, naves, vidas, puntuación)
// se inicializa en init(), que se llama al final del constructor para que
// la escena esté lista en cuanto el Director la haya construido.
init();
}
void GameScene::run() {
std::cout << "SceneType Juego: Inicialitzant...\n";
auto GameScene::isFinished() const -> bool {
return context_.nextScene() != SceneType::GAME;
}
// Inicialitzar state del juego
init();
SDL_Event event;
Uint64 last_time = SDL_GetTicks();
while (SceneManager::actual == SceneType::GAME) {
// Calcular delta_time real
Uint64 current_time = SDL_GetTicks();
float delta_time = (current_time - last_time) / 1000.0F;
last_time = current_time;
// Limitar delta_time per evitar grandes salts
delta_time = std::min(delta_time, 0.05F);
// Actualitzar counter de FPS
sdl_.updateFPS(delta_time);
// Actualitzar visibilitat del cursor (auto-ocultar)
Mouse::updateCursorVisibility();
// Actualitzar sistema de input ABANS del event loop
Input::get()->update();
// Processar events SDL
while (SDL_PollEvent(&event)) {
// Manejo de finestra
if (sdl_.handleWindowEvent(event)) {
continue;
}
// Events globals (F1/F2/F3/ESC/QUIT)
GlobalEvents::handle(event, sdl_, context_);
}
// Actualitzar física del juego con delta_time real
update(delta_time);
// Actualitzar sistema de audio
Audio::update();
// Actualitzar colors oscil·lats
sdl_.updateColors(delta_time);
// Netejar pantalla (usa color oscil·lat)
sdl_.clear(0, 0, 0);
// Actualitzar context de renderizado (factor de scale global)
sdl_.updateRenderingContext();
// Dibuixar juego
draw();
// Presentar renderer (swap buffers)
sdl_.present();
}
std::cout << "SceneType Juego: Finalitzant...\n";
void GameScene::handleEvent(const SDL_Event& event) {
// GameScene no procesa eventos puntuales SDL: la lógica de input se
// resuelve en update() consultando Input::checkAction.
(void)event;
}
void GameScene::init() {
@@ -346,7 +296,6 @@ auto GameScene::stepGameOver(float delta_time) -> bool {
if (game_over_timer_ <= 0.0F) {
Audio::get()->stopMusic();
context_.setNextScene(SceneType::TITLE);
SceneManager::actual = SceneType::TITLE;
return true;
}