refactor: migració a l'arquitectura SDL3 Callback API

Substitueix el bucle blocant main() → Director::run() → escena::run() per
SDL_AppInit/Iterate/Event/Quit. Cada escena implementa ara iterate() (un frame)
i handleEvent() (un event) sota una interfície base Scene.

- Director gestiona l'escena activa i les transicions via switchToActiveScene()
- Setup/cleanup que estava al voltant del while de run() mogut a ctor/dtor
  (música de Game/Ending/Ending2, volum de LoadingScreen)
- GlobalEvents ja no processa SDL_EVENT_QUIT (ho fa Director::handleEvent)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 08:49:19 +02:00
parent 714de067c8
commit c32a880b6a
21 changed files with 319 additions and 362 deletions
+87 -112
View File
@@ -211,6 +211,9 @@ Director::Director() {
#else
Cheevos::init(Resource::List::get()->get("cheevos.bin"));
#endif
// Construeix la primera escena (LOGO per defecte, o la que digui Debug)
switchToActiveScene();
}
Director::~Director() {
@@ -311,118 +314,90 @@ void Director::setFileList() { // NOLINT(readability-convert-member-functions-t
Resource::List::get()->loadFromFile(config_path, PREFIX, system_folder_);
}
// Ejecuta la seccion de juego con el logo
void Director::runLogo() {
auto logo = std::make_unique<Logo>();
logo->run();
}
// Ejecuta la seccion de juego de la pantalla de carga
void Director::runLoadingScreen() {
auto loading_screen = std::make_unique<LoadingScreen>();
loading_screen->run();
}
// Ejecuta la seccion de juego con el titulo y los menus
void Director::runTitle() {
auto title = std::make_unique<Title>();
title->run();
}
// Ejecuta la seccion de los creditos del juego
void Director::runCredits() {
auto credits = std::make_unique<Credits>();
credits->run();
}
// Ejecuta la seccion de la demo, donde se ven pantallas del juego
void Director::runDemo() {
auto game = std::make_unique<Game>(Game::Mode::DEMO);
game->run();
}
// Ejecuta la seccion del final del juego
void Director::runEnding() {
auto ending = std::make_unique<Ending>();
ending->run();
}
// Ejecuta la seccion del final del juego
void Director::runEnding2() {
auto ending2 = std::make_unique<Ending2>();
ending2->run();
}
// Ejecuta la seccion del final de la partida
void Director::runGameOver() {
auto game_over = std::make_unique<GameOver>();
game_over->run();
}
// Ejecuta la seccion de juego donde se juega
void Director::runGame() {
Audio::get()->stopMusic();
auto game = std::make_unique<Game>(Game::Mode::GAME);
game->run();
}
auto Director::run() -> int {
// Bucle principal
while (SceneManager::current != SceneManager::Scene::QUIT) {
const SceneManager::Scene ACTIVE = SceneManager::current;
switch (SceneManager::current) {
case SceneManager::Scene::LOGO:
runLogo();
break;
case SceneManager::Scene::LOADING_SCREEN:
runLoadingScreen();
break;
case SceneManager::Scene::TITLE:
runTitle();
break;
case SceneManager::Scene::CREDITS:
runCredits();
break;
case SceneManager::Scene::DEMO:
runDemo();
break;
case SceneManager::Scene::GAME:
runGame();
break;
case SceneManager::Scene::GAME_OVER:
runGameOver();
break;
case SceneManager::Scene::ENDING:
runEnding();
break;
case SceneManager::Scene::ENDING2:
runEnding2();
break;
case SceneManager::Scene::RESTART_CURRENT:
// La escena salió por RESTART_CURRENT → relanzar la escena guardada
SceneManager::current = SceneManager::scene_before_restart;
break;
default:
break;
}
// Si la escena que acaba de correr dejó RESTART_CURRENT pendiente,
// restaurar la escena que estaba activa para relanzarla en la próxima iteración
if (SceneManager::current == SceneManager::Scene::RESTART_CURRENT) {
SceneManager::current = ACTIVE;
}
// Construeix l'escena segons SceneManager::current i la deixa en active_scene_.
// Substitueix els vells runLogo(), runTitle(), runGame(), etc.
void Director::switchToActiveScene() {
// Si la escena anterior va demanar RESTART_CURRENT, restaurem la que estava activa
if (SceneManager::current == SceneManager::Scene::RESTART_CURRENT) {
SceneManager::current = SceneManager::scene_before_restart;
}
return 0;
// Destrueix l'escena anterior (pot parar música, etc. al seu destructor)
active_scene_.reset();
switch (SceneManager::current) {
case SceneManager::Scene::LOGO:
active_scene_ = std::make_unique<Logo>();
break;
case SceneManager::Scene::LOADING_SCREEN:
active_scene_ = std::make_unique<LoadingScreen>();
break;
case SceneManager::Scene::TITLE:
active_scene_ = std::make_unique<Title>();
break;
case SceneManager::Scene::CREDITS:
active_scene_ = std::make_unique<Credits>();
break;
case SceneManager::Scene::DEMO:
active_scene_ = std::make_unique<Game>(Game::Mode::DEMO);
break;
case SceneManager::Scene::GAME:
Audio::get()->stopMusic();
active_scene_ = std::make_unique<Game>(Game::Mode::GAME);
break;
case SceneManager::Scene::GAME_OVER:
active_scene_ = std::make_unique<GameOver>();
break;
case SceneManager::Scene::ENDING:
active_scene_ = std::make_unique<Ending>();
break;
case SceneManager::Scene::ENDING2:
active_scene_ = std::make_unique<Ending2>();
break;
default:
break;
}
current_scene_ = SceneManager::current;
}
// SDL_AppIterate: executa un frame de l'escena activa
auto Director::iterate() -> SDL_AppResult {
if (SceneManager::current == SceneManager::Scene::QUIT) {
return SDL_APP_SUCCESS;
}
// Si l'escena ha canviat (o s'ha demanat RESTART_CURRENT), canviar-la abans del frame
if (SceneManager::current != current_scene_ || SceneManager::current == SceneManager::Scene::RESTART_CURRENT) {
switchToActiveScene();
}
if (active_scene_) {
active_scene_->iterate();
}
return SDL_APP_CONTINUE;
}
// SDL_AppEvent: despatxa un event a l'escena activa
auto Director::handleEvent(const SDL_Event& event) -> SDL_AppResult {
if (event.type == SDL_EVENT_QUIT) {
SceneManager::current = SceneManager::Scene::QUIT;
return SDL_APP_SUCCESS;
}
if (active_scene_) {
active_scene_->handleEvent(event);
}
return SDL_APP_CONTINUE;
}