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

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;
}

View File

@@ -2,29 +2,31 @@
#include <SDL3/SDL.h>
#include <memory> // Para unique_ptr
#include <string> // Para string
#include "game/scene_manager.hpp" // Para SceneManager::Scene
#include "game/scenes/scene.hpp" // Para Scene base
class Director {
public:
Director(); // Constructor
~Director(); // Destructor
static auto run() -> int; // Bucle principal
Director(); // Constructor: inicialitza sistemes i crea l'escena inicial
~Director(); // Destructor
// SDL3 Callback API: un frame i un event
auto iterate() -> SDL_AppResult;
auto handleEvent(const SDL_Event& event) -> SDL_AppResult;
private:
// --- Variables ---
std::string executable_path_; // Path del ejecutable
std::string system_folder_; // Carpeta del sistema donde guardar datos
std::unique_ptr<Scene> active_scene_; // Escena activa
SceneManager::Scene current_scene_{SceneManager::Scene::LOGO}; // Tipus d'escena activa
// --- Funciones ---
void createSystemFolder(const std::string& folder); // Crea la carpeta del sistema donde guardar datos
void setFileList(); // Carga la configuración de assets desde assets.yaml
static void runLogo(); // Ejecuta la seccion de juego con el logo
static void runLoadingScreen(); // Ejecuta la seccion de juego de la pantalla de carga
static void runTitle(); // Ejecuta la seccion de juego con el titulo y los menus
static void runCredits(); // Ejecuta la seccion de los creditos del juego
static void runDemo(); // Ejecuta la seccion de la demo, donde se ven pantallas del juego
static void runEnding(); // Ejecuta la seccion del final del juego
static void runEnding2(); // Ejecuta la seccion del final del juego
static void runGameOver(); // Ejecuta la seccion del final de la partida
static void runGame(); // Ejecuta la seccion de juego donde se juega
};
void switchToActiveScene(); // Construeix l'escena segons SceneManager::current
};

View File

@@ -1,19 +1,13 @@
#include "core/system/global_events.hpp"
#include "core/input/mouse.hpp"
#include "game/options.hpp" // Para Options, options, OptionsGame, OptionsAudio
#include "game/scene_manager.hpp" // Para SceneManager
#include "game/ui/console.hpp" // Para Console
#include "game/options.hpp" // Para Options, options, OptionsGame, OptionsAudio
#include "game/ui/console.hpp" // Para Console
namespace GlobalEvents {
// Comprueba los eventos que se pueden producir en cualquier sección del juego
// Comprueba los eventos que se pueden producir en cualquier sección del juego.
// Nota: SDL_EVENT_QUIT el gestiona Director::handleEvent() directament.
void handle(const SDL_Event& event) {
// Evento de salida de la aplicación
if (event.type == SDL_EVENT_QUIT) {
SceneManager::current = SceneManager::Scene::QUIT;
return;
}
if (event.type == SDL_EVENT_RENDER_DEVICE_RESET || event.type == SDL_EVENT_RENDER_TARGETS_RESET) {
// reLoadTextures();
}