diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index f4e8b21..dd2daa4 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -20,6 +20,7 @@ #include "core/resources/resource_helper.hpp" // Para ResourceHelper #include "core/resources/resource_list.hpp" // Para Asset, AssetType #include "core/resources/resource_loader.hpp" // Para ResourceLoader +#include "core/system/event_buffer.hpp" // Para EventBuffer #include "game/gameplay/cheevos.hpp" // Para Cheevos #include "game/options.hpp" // Para Options, options, OptionsVideo #include "game/scene_manager.hpp" // Para SceneManager @@ -319,58 +320,80 @@ 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->run(); +// Destruye la escena activa +void Director::destroyCurrentScene() { + logo_.reset(); + title_.reset(); + game_.reset(); + active_scene_ = SceneManager::Scene::QUIT; } -// Ejecuta la seccion de juego con el titulo y los menus -void Director::runTitle() { - auto title = std::make_unique(); - title->run(); -} +// Crea la escena indicada +void Director::createScene(SceneManager::Scene scene) { + destroyCurrentScene(); -// 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(); -} + switch (scene) { + case SceneManager::Scene::LOGO: + logo_ = std::make_unique<Logo>(); + break; -auto Director::run() -> int { - // Bucle principal - while (SceneManager::current != SceneManager::Scene::QUIT) { - const SceneManager::Scene ACTIVE = SceneManager::current; + case SceneManager::Scene::TITLE: + title_ = std::make_unique<Title>(); + break; - switch (SceneManager::current) { - case SceneManager::Scene::LOGO: - runLogo(); - break; + case SceneManager::Scene::GAME: + Audio::get()->stopMusic(); + game_ = std::make_unique<Game>(Game::Mode::GAME); + break; - case SceneManager::Scene::TITLE: - runTitle(); - break; - - case SceneManager::Scene::GAME: - runGame(); - 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; - } + default: + break; } - return 0; + active_scene_ = scene; +} + +// Una iteración del bucle principal (callback model) +auto Director::iterate() -> SDL_AppResult { + // Resolver RESTART_CURRENT antes de comprobar escena + if (SceneManager::current == SceneManager::Scene::RESTART_CURRENT) { + SceneManager::current = SceneManager::scene_before_restart; + } + + // Salir si se ha pedido QUIT + if (SceneManager::current == SceneManager::Scene::QUIT) { + EventBuffer::events.clear(); + return SDL_APP_SUCCESS; + } + + // Si la escena solicitada no coincide con la activa, crear la nueva + if (SceneManager::current != active_scene_) { + createScene(SceneManager::current); + } + + // Ejecutar un frame de la escena activa + switch (active_scene_) { + case SceneManager::Scene::LOGO: + logo_->update(); + logo_->render(); + break; + + case SceneManager::Scene::TITLE: + title_->update(); + title_->render(); + break; + + case SceneManager::Scene::GAME: + game_->update(); + game_->render(); + break; + + default: + break; + } + + // Limpiar el buffer de eventos tras cada frame + EventBuffer::events.clear(); + + return SDL_APP_CONTINUE; } \ No newline at end of file diff --git a/source/core/system/director.hpp b/source/core/system/director.hpp index 2d24e4f..9e6a3f8 100644 --- a/source/core/system/director.hpp +++ b/source/core/system/director.hpp @@ -2,23 +2,35 @@ #include <SDL3/SDL.h> +#include <memory> // Para unique_ptr #include <string> // Para string +#include "game/scene_manager.hpp" // Para SceneManager::Scene + +class Logo; +class Title; +class Game; + class Director { public: - Director(); // Constructor - ~Director(); // Destructor - static auto run() -> int; // Bucle principal + Director(); // Constructor + ~Director(); // Destructor + auto iterate() -> SDL_AppResult; // Una iteración del bucle principal (callback model) private: // --- Variables --- std::string executable_path_; // Path del ejecutable std::string system_folder_; // Carpeta del sistema donde guardar datos + // --- Gestión de escenas --- + SceneManager::Scene active_scene_{SceneManager::Scene::QUIT}; // Escena activa (la que tiene objeto creado) + std::unique_ptr<Logo> logo_; + std::unique_ptr<Title> title_; + std::unique_ptr<Game> game_; + // --- 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 runTitle(); // Ejecuta la seccion de juego con el titulo y los menus - static void runGame(); // Ejecuta la seccion de juego donde se juega -}; \ No newline at end of file + void destroyCurrentScene(); // Destruye la escena activa + void createScene(SceneManager::Scene scene); // Crea la escena indicada +}; diff --git a/source/core/system/event_buffer.hpp b/source/core/system/event_buffer.hpp new file mode 100644 index 0000000..77c92bc --- /dev/null +++ b/source/core/system/event_buffer.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include <SDL3/SDL.h> + +#include <vector> + +// Buffer global de eventos SDL para el modelo de callbacks (SDL_MAIN_USE_CALLBACKS). +// SDL_AppEvent() almacena los eventos aquí; las escenas los consumen en su handleEvents(). +// El buffer se limpia al final de cada iteración en Director::iterate(). +namespace EventBuffer { + inline std::vector<SDL_Event> events; +} // namespace EventBuffer diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index abff60a..418797f 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -15,6 +15,7 @@ #include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG #include "core/resources/resource_cache.hpp" // Para ResourceRoom, Resource #include "core/resources/resource_list.hpp" // Para Asset +#include "core/system/event_buffer.hpp" // Para EventBuffer #include "core/system/global_events.hpp" // Para check #include "game/defaults.hpp" // Para Defaults::Game #include "game/game_control.hpp" // Para GameControl @@ -158,9 +159,20 @@ Game::Game(Mode mode) SceneManager::current = SceneManager::Scene::GAME; SceneManager::options = SceneManager::Options::NONE; + + // Inicialización de música (antes estaba al principio de run()) + keepMusicPlaying(); + if (!scoreboard_data_->music && mode_ == Mode::GAME) { + Audio::get()->pauseMusic(); + } } Game::~Game() { + // Parar música al destruir la escena (antes estaba al final de run()) + if (mode_ == Mode::GAME) { + Audio::get()->stopMusic(); + } + ItemTracker::destroy(); GameControl::change_player_skin = nullptr; @@ -185,8 +197,7 @@ Game::~Game() { // Comprueba los eventos de la cola void Game::handleEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { + for (const auto& event : EventBuffer::events) { GlobalEvents::handle(event); #ifdef _DEBUG // En modo editor: click del ratón cierra la consola @@ -257,23 +268,6 @@ void Game::handleInput() { GlobalInputs::handle(); } -// Bucle para el juego -void Game::run() { - keepMusicPlaying(); - if (!scoreboard_data_->music && mode_ == Mode::GAME) { - Audio::get()->pauseMusic(); - } - - while (SceneManager::current == SceneManager::Scene::GAME) { - update(); - render(); - } - - if (mode_ == Mode::GAME) { - Audio::get()->stopMusic(); - } -} - // Actualiza el juego, las variables, comprueba la entrada, etc. void Game::update() { const float DELTA_TIME = delta_timer_.tick(); diff --git a/source/game/scenes/game.hpp b/source/game/scenes/game.hpp index 35f33ed..1a04322 100644 --- a/source/game/scenes/game.hpp +++ b/source/game/scenes/game.hpp @@ -34,8 +34,9 @@ class Game { explicit Game(Mode mode); ~Game(); - // --- Bucle para el juego --- - void run(); + // --- Frame (llamados desde Director::iterate) --- + void update(); + void render(); private: // --- Constantes de tiempo --- @@ -53,8 +54,6 @@ class Game { }; // --- Métodos --- - void update(); // Actualiza el juego, las variables, comprueba la entrada, etc. - void render(); // Pinta los objetos en pantalla void handleEvents(); // Comprueba los eventos de la cola void transitionToState(State new_state); // Cambia al estado especificado y resetea los timers void updatePlaying(float delta_time); // Actualiza el juego en estado PLAYING diff --git a/source/game/scenes/logo.cpp b/source/game/scenes/logo.cpp index 60b2e7a..1434bdf 100644 --- a/source/game/scenes/logo.cpp +++ b/source/game/scenes/logo.cpp @@ -13,6 +13,7 @@ #include "core/rendering/sprite/sprite.hpp" // Para SSprite #include "core/rendering/surface.hpp" // Para Surface #include "core/resources/resource_cache.hpp" // Para Resource +#include "core/system/event_buffer.hpp" // Para EventBuffer #include "core/system/global_events.hpp" // Para check #include "game/options.hpp" // Para Options, SectionState, options, Section #include "game/scene_manager.hpp" // Para SceneManager @@ -56,8 +57,7 @@ Logo::Logo() // Comprueba el manejador de eventos void Logo::handleEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { + for (const auto& event : EventBuffer::events) { GlobalEvents::handle(event); } } @@ -228,14 +228,6 @@ void Logo::render() { // NOLINT(readability-convert-member-functions-to-static) Screen::get()->render(); } -// Bucle para el logo del juego -void Logo::run() { - while (SceneManager::current == SceneManager::Scene::LOGO) { - update(); - render(); - } -} - // Termina la sección void Logo::endSection() { SceneManager::current = SceneManager::Scene::TITLE; diff --git a/source/game/scenes/logo.hpp b/source/game/scenes/logo.hpp index d9839c3..a7cd828 100644 --- a/source/game/scenes/logo.hpp +++ b/source/game/scenes/logo.hpp @@ -30,8 +30,9 @@ class Logo { Logo(); ~Logo() = default; - // --- Bucle principal --- - void run(); + // --- Frame (llamados desde Director::iterate) --- + void update(); + void render(); private: // --- Constantes de tiempo (en segundos) --- @@ -46,8 +47,6 @@ class Logo { static constexpr int JAILGAMES_DEST_X = 37; // Posición X de destino para JAILGAMES // --- Métodos --- - void update(); // Actualiza las variables - void render(); // Dibuja en pantalla static void handleEvents(); // Comprueba el manejador de eventos static void handleInput(); // Comprueba las entradas void updateJAILGAMES(float delta_time); // Gestiona el logo de JAILGAME (time-based) diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 9bd70e1..1b6c332 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -14,6 +14,7 @@ #include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG #include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_list.hpp" // Para Asset +#include "core/system/event_buffer.hpp" // Para EventBuffer #include "core/system/global_events.hpp" // Para check #include "game/gameplay/cheevos.hpp" // Para Cheevos, Achievement #include "game/options.hpp" // Para Options, options, SectionState, Section @@ -53,8 +54,7 @@ Title::~Title() { // NOLINT(modernize-use-equals-default) // Comprueba el manejador de eventos void Title::handleEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { + for (const auto& event : EventBuffer::events) { GlobalEvents::handle(event); // Manejo especial para captura de botones de gamepad @@ -311,14 +311,6 @@ void Title::render() { Screen::get()->render(); } -// Bucle para el logo del juego -void Title::run() { - while (SceneManager::current == SceneManager::Scene::TITLE) { - update(); - render(); - } -} - // Crea y rellena la textura para mostrar los logros void Title::createCheevosTexture() { // NOLINT(readability-convert-member-functions-to-static) // Define la zona central del menu (entre el logo y la marquesina) diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index f915f09..8ac28fd 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -17,8 +17,9 @@ class Title { Title(); ~Title(); - // --- Bucle principal --- - void run(); + // --- Frame (llamados desde Director::iterate) --- + void update(); + void render(); private: // --- Estructuras y enumeraciones --- @@ -38,8 +39,6 @@ class Title { static constexpr float CHEEVOS_SCROLL_DECELERATION = 800.0F; // Desaceleración del scroll (pixels/segundo²) // --- Métodos --- - void update(); // Actualiza las variables - void render(); // Dibuja en pantalla void handleEvents(); // Comprueba el manejador de eventos void handleMainMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu principal void handleInput(float delta_time); // Comprueba las entradas diff --git a/source/main.cpp b/source/main.cpp index 1659f45..5f56ae0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -5,14 +5,36 @@ Empezado en Castalla el 01/07/2022. */ -#include <memory> +#define SDL_MAIN_USE_CALLBACKS 1 + +#include <SDL3/SDL.h> +#include <SDL3/SDL_main.h> #include "core/system/director.hpp" +#include "core/system/event_buffer.hpp" -auto main() -> int { - // Crea el objeto Director - auto director = std::make_unique<Director>(); +SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { + (void)argc; + (void)argv; - // Bucle principal - return Director::run(); + auto* director = new Director(); + *appstate = director; + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { + (void)appstate; + EventBuffer::events.push_back(*event); + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void* appstate) { + auto* director = static_cast<Director*>(appstate); + return director->iterate(); +} + +void SDL_AppQuit(void* appstate, SDL_AppResult result) { + (void)result; + auto* director = static_cast<Director*>(appstate); + delete director; }