From f5da35bfb2f7b09d657a5dfb39529871e8957526 Mon Sep 17 00:00:00 2001 From: Sergio Date: Tue, 14 Apr 2026 12:21:00 +0200 Subject: [PATCH] sdl_callbacks --- source/director.cpp | 224 ++++++++++++++++++------------ source/director.hpp | 43 ++++-- source/input.cpp | 13 +- source/main.cpp | 27 ++-- source/resource.cpp | 68 +++------ source/resource.hpp | 1 - source/sections/credits.cpp | 21 ++- source/sections/credits.hpp | 6 +- source/sections/game.cpp | 34 ++++- source/sections/game.hpp | 6 +- source/sections/hiscore_table.cpp | 22 ++- source/sections/hiscore_table.hpp | 6 +- source/sections/instructions.cpp | 22 ++- source/sections/instructions.hpp | 6 +- source/sections/intro.cpp | 22 ++- source/sections/intro.hpp | 6 +- source/sections/logo.cpp | 21 ++- source/sections/logo.hpp | 6 +- source/sections/title.cpp | 23 ++- source/sections/title.hpp | 6 +- 20 files changed, 406 insertions(+), 177 deletions(-) diff --git a/source/director.cpp b/source/director.cpp index 79db6a2..8593820 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -16,6 +16,7 @@ #include "asset.hpp" // Para Asset #include "audio.hpp" // Para Audio #include "external/fkyaml_node.hpp" // Para fkyaml::node +#include "global_events.hpp" // Para GlobalEvents::handle #include "input.hpp" // Para Input #include "lang.hpp" // Para setLanguage #include "manage_hiscore_table.hpp" // Para ManageHiScoreTable @@ -75,6 +76,9 @@ Director::Director(int argc, std::span argv) { } Director::~Director() { + // Libera las secciones primero: sus destructores pueden tocar Audio/Resource/Screen, + // que close() destruye a continuación. + resetActiveSection(); close(); Logger::put("\nBye!"); } @@ -335,75 +339,96 @@ void Director::createSystemFolder(const std::string& folder) { } } -// Ejecuta la sección con el logo -void Director::runLogo() { - auto logo = std::make_unique(); - logo->run(); +// Libera todos los unique_ptr de sección (solo uno tiene propiedad a la vez) +void Director::resetActiveSection() { + logo_.reset(); + intro_.reset(); + title_.reset(); + game_.reset(); + instructions_.reset(); + hi_score_table_.reset(); + credits_.reset(); } -// Ejecuta la sección con la secuencia de introducción -void Director::runIntro() { - auto intro = std::make_unique(); - intro->run(); -} +// Destruye la sección anterior y construye la nueva cuando Section::name cambia +void Director::handleSectionTransition() { + // RESET: recarga recursos y vuelve a LOGO (el propio reset() cambia Section::name) + if (Section::name == Section::Name::RESET) { + resetActiveSection(); // libera recursos actuales antes del reload + reset(); + } -// Ejecuta la sección con el título del juego -void Director::runTitle() { - auto title = std::make_unique(); - title->run(); -} + if (Section::name == last_built_section_name_) { + return; // ya tenemos la sección correcta viva + } -// Ejecuta la sección donde se juega al juego -void Director::runGame() { - Player::Id player_id = Player::Id::PLAYER1; + // Destruye la sección anterior + resetActiveSection(); - switch (Section::options) { - case Section::Options::GAME_PLAY_1P: - player_id = Player::Id::PLAYER1; + // Construye la nueva + switch (Section::name) { + case Section::Name::LOGO: + logo_ = std::make_unique<Logo>(); break; - case Section::Options::GAME_PLAY_2P: - player_id = Player::Id::PLAYER2; + + case Section::Name::INTRO: + intro_ = std::make_unique<Intro>(); break; - case Section::Options::GAME_PLAY_BOTH: - player_id = Player::Id::BOTH_PLAYERS; + + case Section::Name::TITLE: + title_ = std::make_unique<Title>(); break; + + case Section::Name::GAME: { + Player::Id player_id = Player::Id::PLAYER1; + switch (Section::options) { + case Section::Options::GAME_PLAY_1P: + player_id = Player::Id::PLAYER1; + break; + case Section::Options::GAME_PLAY_2P: + player_id = Player::Id::PLAYER2; + break; + case Section::Options::GAME_PLAY_BOTH: + player_id = Player::Id::BOTH_PLAYERS; + break; + default: + break; + } +#ifdef _DEBUG + const int CURRENT_STAGE = debug_config.initial_stage; +#else + constexpr int CURRENT_STAGE = 0; +#endif + game_ = std::make_unique<Game>(player_id, CURRENT_STAGE, Game::DEMO_OFF); + break; + } + + case Section::Name::GAME_DEMO: { + const auto PLAYER_ID = static_cast<Player::Id>((rand() % 2) + 1); + constexpr auto CURRENT_STAGE = 0; + game_ = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON); + break; + } + + case Section::Name::INSTRUCTIONS: + instructions_ = std::make_unique<Instructions>(); + break; + + case Section::Name::CREDITS: + credits_ = std::make_unique<Credits>(); + break; + + case Section::Name::HI_SCORE_TABLE: + hi_score_table_ = std::make_unique<HiScoreTable>(); + break; + + case Section::Name::RESET: + case Section::Name::QUIT: default: break; } -#ifdef _DEBUG - const int CURRENT_STAGE = debug_config.initial_stage; -#else - constexpr int CURRENT_STAGE = 0; -#endif - auto game = std::make_unique<Game>(player_id, CURRENT_STAGE, Game::DEMO_OFF); - game->run(); -} - -// Ejecuta la sección donde se muestran las instrucciones -void Director::runInstructions() { - auto instructions = std::make_unique<Instructions>(); - instructions->run(); -} - -// Ejecuta la sección donde se muestran los creditos del programa -void Director::runCredits() { - auto credits = std::make_unique<Credits>(); - credits->run(); -} - -// Ejecuta la sección donde se muestra la tabla de puntuaciones -void Director::runHiScoreTable() { - auto hi_score_table = std::make_unique<HiScoreTable>(); - hi_score_table->run(); -} - -// Ejecuta el juego en modo demo -void Director::runDemoGame() { - const auto PLAYER_ID = static_cast<Player::Id>((rand() % 2) + 1); - constexpr auto CURRENT_STAGE = 0; - auto game = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON); - game->run(); + last_built_section_name_ = Section::name; } // Reinicia objetos y vuelve a la sección inicial @@ -418,43 +443,58 @@ void Director::reset() { Section::name = Section::Name::LOGO; } -auto Director::run() -> int { - // Bucle principal - while (Section::name != Section::Name::QUIT) { - switch (Section::name) { - case Section::Name::RESET: - reset(); - break; - case Section::Name::LOGO: - runLogo(); - break; - case Section::Name::INTRO: - runIntro(); - break; - case Section::Name::TITLE: - runTitle(); - break; - case Section::Name::GAME: - runGame(); - break; - case Section::Name::HI_SCORE_TABLE: - runHiScoreTable(); - break; - case Section::Name::GAME_DEMO: - runDemoGame(); - break; - case Section::Name::INSTRUCTIONS: - runInstructions(); - break; - case Section::Name::CREDITS: - runCredits(); - break; - default: - break; - } +// Avanza un frame de la sección activa (llamado desde SDL_AppIterate) +auto Director::iterate() -> SDL_AppResult { + if (Section::name == Section::Name::QUIT) { + return SDL_APP_SUCCESS; } - return 0; + // Gestiona las transiciones entre secciones (destruye la anterior y construye la nueva) + handleSectionTransition(); + + // Ejecuta un frame de la sección activa + if (logo_) { + logo_->iterate(); + } else if (intro_) { + intro_->iterate(); + } else if (title_) { + title_->iterate(); + } else if (game_) { + game_->iterate(); + } else if (instructions_) { + instructions_->iterate(); + } else if (hi_score_table_) { + hi_score_table_->iterate(); + } else if (credits_) { + credits_->iterate(); + } + + return (Section::name == Section::Name::QUIT) ? SDL_APP_SUCCESS : SDL_APP_CONTINUE; +} + +// Procesa un evento SDL (llamado desde SDL_AppEvent) +auto Director::handleEvent(SDL_Event& event) -> SDL_AppResult { + // Eventos globales (SDL_EVENT_QUIT, resize, render target reset, hotplug, service menu, ratón) + GlobalEvents::handle(event); + + // Reenvía a la sección activa + if (logo_) { + logo_->handleEvent(event); + } else if (intro_) { + intro_->handleEvent(event); + } else if (title_) { + title_->handleEvent(event); + } else if (game_) { + game_->handleEvent(event); + } else if (instructions_) { + instructions_->handleEvent(event); + } else if (hi_score_table_) { + hi_score_table_->handleEvent(event); + } else if (credits_) { + credits_->handleEvent(event); + } + + return (Section::name == Section::Name::QUIT) ? SDL_APP_SUCCESS : SDL_APP_CONTINUE; } // Apaga el sistema de forma segura diff --git a/source/director.hpp b/source/director.hpp index ddd549e..be0789c 100644 --- a/source/director.hpp +++ b/source/director.hpp @@ -1,12 +1,26 @@ #pragma once +#include <SDL3/SDL.h> // Para SDL_AppResult, SDL_Event + +#include <memory> // Para unique_ptr #include <span> // Para Span #include <string> // Para string +#include "section.hpp" // Para Section::Name + namespace Lang { enum class Code : int; } +// Declaraciones adelantadas de las secciones +class Logo; +class Intro; +class Title; +class Game; +class Instructions; +class HiScoreTable; +class Credits; + // --- Clase Director: gestor principal de la aplicación --- class Director { public: @@ -14,8 +28,9 @@ class Director { Director(int argc, std::span<char*> argv); ~Director(); - // --- Bucle principal --- - static auto run() -> int; + // --- Callbacks para SDL_MAIN_USE_CALLBACKS --- + auto iterate() -> SDL_AppResult; // Avanza un frame de la sección activa + auto handleEvent(SDL_Event& event) -> SDL_AppResult; // Procesa un evento SDL // --- Debug config (accesible desde otras clases) --- struct DebugConfig { @@ -37,6 +52,16 @@ class Director { std::string executable_path_; // Ruta del ejecutable std::string system_folder_; // Carpeta del sistema para almacenar datos + // --- Sección activa (una y sólo una viva en cada momento) --- + std::unique_ptr<Logo> logo_; + std::unique_ptr<Intro> intro_; + std::unique_ptr<Title> title_; + std::unique_ptr<Game> game_; + std::unique_ptr<Instructions> instructions_; + std::unique_ptr<HiScoreTable> hi_score_table_; + std::unique_ptr<Credits> credits_; + Section::Name last_built_section_name_ = Section::Name::RESET; + // --- Inicialización y cierre del sistema --- void init(); // Inicializa la aplicación static void close(); // Cierra y libera recursos @@ -51,16 +76,10 @@ class Director { void loadAssets(); // Crea el índice de archivos disponibles void checkProgramArguments(int argc, std::span<char*> argv); // Verifica los parámetros del programa // NOLINT(modernize-avoid-c-arrays) - // --- Secciones del programa --- - static void runLogo(); // Ejecuta la pantalla con el logo - static void runIntro(); // Ejecuta la introducción del juego - static void runTitle(); // Ejecuta la pantalla de título - static void runGame(); // Inicia el juego - static void runInstructions(); // Muestra las instrucciones - static void runCredits(); // Muestra los créditos del juego - static void runHiScoreTable(); // Muestra la tabla de puntuaciones - static void runDemoGame(); // Ejecuta el modo demo - static void reset(); // Reinicia objetos y vuelve a la sección inicial + // --- Gestión de secciones --- + void handleSectionTransition(); // Destruye la sección anterior y construye la nueva si Section::name ha cambiado + void resetActiveSection(); // Libera todos los unique_ptr de sección + static void reset(); // Reinicia objetos y vuelve a la sección inicial // --- Gestión de archivos de idioma --- auto getLangFile(Lang::Code code) -> std::string; // Obtiene un fichero de idioma según el código diff --git a/source/input.cpp b/source/input.cpp index 847f755..01e5333 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -306,10 +306,17 @@ void Input::addGamepadMappingsFromFile() { } void Input::discoverGamepads() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - handleEvent(event); // Comprueba mandos conectados + // Enumera los gamepads ya conectados sin drenar la cola de eventos de SDL + // (necesario con SDL_MAIN_USE_CALLBACKS, que entrega los eventos por SDL_AppEvent). + int count = 0; + SDL_JoystickID* joysticks = SDL_GetGamepads(&count); + if (joysticks == nullptr) { + return; } + for (int i = 0; i < count; ++i) { + addGamepad(joysticks[i]); + } + SDL_free(joysticks); } void Input::initSDLGamePad() { diff --git a/source/main.cpp b/source/main.cpp index 229210e..0d07f11 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -7,15 +7,26 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024 */ -#include <memory> // Para make_unique, unique_ptr -#include <span> // Para span +#define SDL_MAIN_USE_CALLBACKS 1 +#include <SDL3/SDL_main.h> + +#include <span> // Para span #include "director.hpp" // Para Director -auto main(int argc, char* argv[]) -> int { - // Crea el objeto Director - auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc)); - - // Bucle principal - return Director::run(); +SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { + *appstate = new Director(argc, std::span<char*>(argv, argc)); + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void* appstate) { + return static_cast<Director*>(appstate)->iterate(); +} + +SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { + return static_cast<Director*>(appstate)->handleEvent(*event); +} + +void SDL_AppQuit(void* appstate, SDL_AppResult /*result*/) { + delete static_cast<Director*>(appstate); } diff --git a/source/resource.cpp b/source/resource.cpp index 20558ac..953d212 100644 --- a/source/resource.cpp +++ b/source/resource.cpp @@ -467,10 +467,10 @@ void Resource::reload() { // Carga los sonidos del juego void Resource::loadSounds() { - Logger::info("SOUND FILES"); auto list = Asset::get()->getListByType(Asset::Type::SOUND); sounds_.clear(); + int failed = 0; for (const auto& l : list) { auto name = getFileName(l); updateLoadingProgress(name); @@ -479,21 +479,23 @@ void Resource::loadSounds() { if (!audio_data.data.empty()) { sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size()); } else { - // Fallback a cargar desde disco si no está en pack sound = JA_LoadSound(l.c_str()); } + if (sound == nullptr) { + Logger::error(" Sound load failed: " + name); + ++failed; + } sounds_.emplace_back(name, sound); - Logger::dots("Sound : ", name, "[ LOADED ]"); } + Logger::info("Sounds loaded: " + std::to_string(list.size() - failed) + "/" + std::to_string(list.size())); } // Carga las músicas del juego void Resource::loadMusics() { - Logger::cr(); - Logger::info("MUSIC FILES"); auto list = Asset::get()->getListByType(Asset::Type::MUSIC); musics_.clear(); + int failed = 0; for (const auto& l : list) { auto name = getFileName(l); updateLoadingProgress(name); @@ -502,18 +504,19 @@ void Resource::loadMusics() { if (!audio_data.data.empty()) { music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size()); } else { - // Fallback a cargar desde disco si no está en pack music = JA_LoadMusic(l.c_str()); } + if (music == nullptr) { + Logger::error(" Music load failed: " + name); + ++failed; + } musics_.emplace_back(name, music); - Logger::dots("Music : ", name, "[ LOADED ]"); } + Logger::info("Musics loaded: " + std::to_string(list.size() - failed) + "/" + std::to_string(list.size())); } // Carga las texturas del juego void Resource::loadTextures() { - Logger::cr(); - Logger::info("TEXTURES"); auto list = Asset::get()->getListByType(Asset::Type::BITMAP); textures_.clear(); @@ -522,12 +525,11 @@ void Resource::loadTextures() { updateLoadingProgress(name); textures_.emplace_back(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l)); } + Logger::info("Textures loaded: " + std::to_string(list.size())); } // Carga los ficheros de texto del juego void Resource::loadTextFiles() { - Logger::cr(); - Logger::info("TEXT FILES"); auto list = Asset::get()->getListByType(Asset::Type::FONT); text_files_.clear(); @@ -536,12 +538,11 @@ void Resource::loadTextFiles() { updateLoadingProgress(name); text_files_.emplace_back(name, Text::loadFile(l)); } + Logger::info("Text files loaded: " + std::to_string(list.size())); } // Carga las animaciones del juego void Resource::loadAnimations() { - Logger::cr(); - Logger::info("ANIMATIONS"); auto list = Asset::get()->getListByType(Asset::Type::ANIMATION); animations_.clear(); @@ -550,12 +551,11 @@ void Resource::loadAnimations() { updateLoadingProgress(name); animations_.emplace_back(name, loadAnimationsFromFile(l)); } + Logger::info("Animations loaded: " + std::to_string(list.size())); } // Carga los datos para el modo demostración void Resource::loadDemoData() { - Logger::cr(); - Logger::info("DEMO FILES"); auto list = Asset::get()->getListByType(Asset::Type::DEMODATA); demos_.clear(); @@ -564,13 +564,11 @@ void Resource::loadDemoData() { updateLoadingProgress(name); demos_.emplace_back(loadDemoDataFromFile(l)); } + Logger::info("Demo files loaded: " + std::to_string(list.size())); } // Crea las texturas de jugadores con todas sus variantes de paleta void Resource::createPlayerTextures() { - Logger::cr(); - Logger::info("CREATING PLAYER TEXTURES"); - // Configuración de jugadores y sus paletas struct PlayerConfig { std::string base_texture; @@ -641,9 +639,9 @@ void Resource::createPlayerTextures() { // Guardar con nombre específico std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx); textures_.emplace_back(texture_name, texture); - Logger::dots("Player Texture : ", texture_name, "[ DONE ]"); } } + Logger::info("Player textures created: " + std::to_string(players.size() * 4)); } // Crea texturas a partir de textos para mostrar puntuaciones y mensajes @@ -657,9 +655,6 @@ void Resource::createTextTextures() { text(std::move(text_init)) {} }; - Logger::cr(); - Logger::info("CREATING TEXTURES"); - // Texturas de tamaño normal con outline std::vector<NameAndText> strings1 = { {"game_text_1000_points", "1.000"}, @@ -673,7 +668,6 @@ void Resource::createTextTextures() { auto text1 = getText("04b_25_enhanced"); for (const auto& s : strings1) { textures_.emplace_back(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color)); - Logger::dots("Texture : ", s.name, "[ DONE ]"); } // Texturas de tamaño doble @@ -688,8 +682,9 @@ void Resource::createTextTextures() { auto text2 = getText("04b_25_2x_enhanced"); for (const auto& s : strings2) { textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -4, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color)); - Logger::dots("Texture : ", s.name, "[ DONE ]"); } + + Logger::info("Text textures created: " + std::to_string(strings1.size() + strings2.size())); } // Crea los objetos de texto a partir de los archivos de textura y texto @@ -707,9 +702,6 @@ void Resource::createText() { white_texture_file(std::move(w_file)) {} }; - Logger::cr(); - Logger::info("CREATING TEXT OBJECTS"); - std::vector<ResourceInfo> resources = { {"04b_25", "04b_25.png", "04b_25.txt"}, {"04b_25_enhanced", "04b_25.png", "04b_25.txt", "04b_25_white.png"}, // Nueva fuente con textura blanca @@ -735,8 +727,8 @@ void Resource::createText() { // Crear texto normal texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file))); } - Logger::dots("Text : ", resource.key, "[ DONE ]"); } + Logger::info("Text objects created: " + std::to_string(resources.size())); } // Vacía el vector de sonidos y libera la memoria asociada @@ -853,23 +845,6 @@ void Resource::renderProgress() { screen->coreRender(); } -// Comprueba los eventos durante la carga (permite salir con ESC o cerrar ventana) -void Resource::checkEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_EVENT_QUIT: - exit(0); - break; - case SDL_EVENT_KEY_DOWN: - if (event.key.key == SDLK_ESCAPE) { - exit(0); - } - break; - } - } -} - // Carga los datos para el modo demostración (sin mostrar progreso) void Resource::loadDemoDataQuiet() { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> DEMO FILES (quiet load)"); @@ -892,13 +867,12 @@ void Resource::initProgressBar() { loading_full_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT}; } -// Actualiza el progreso de carga, muestra la barra y procesa eventos +// Actualiza el progreso de carga y muestra la barra void Resource::updateLoadingProgress(std::string name) { loading_resource_name_ = std::move(name); loading_count_.increase(); updateProgressBar(); renderProgress(); - checkEvents(); } // Actualiza la barra de estado diff --git a/source/resource.hpp b/source/resource.hpp index cb22f76..dd3894e 100644 --- a/source/resource.hpp +++ b/source/resource.hpp @@ -174,7 +174,6 @@ class Resource { // --- Métodos internos para gestionar el progreso --- void calculateTotalResources(); // Calcula el número de recursos para cargar void renderProgress(); // Muestra el progreso de carga - static void checkEvents(); // Comprueba los eventos durante la carga void updateLoadingProgress(std::string name); // Actualiza el progreso de carga void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso void updateProgressBar(); // Actualiza la barra de estado diff --git a/source/sections/credits.cpp b/source/sections/credits.cpp index ef674b0..68d4cc8 100644 --- a/source/sections/credits.cpp +++ b/source/sections/credits.cpp @@ -28,6 +28,7 @@ #include "text.hpp" // Para Text #include "texture.hpp" // Para Texture #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode +#include "ui/logger.hpp" // Para section #include "ui/service_menu.hpp" // Para ServiceMenu #include "utils.hpp" // Para Zone @@ -47,6 +48,11 @@ Credits::Credits() } initVars(); startCredits(); + + Logger::section("CREDITS"); + + // Inicializa el timer de delta time para el primer frame del callback + last_time_ = SDL_GetTicks(); } // Destructor @@ -69,7 +75,20 @@ auto Credits::calculateDeltaTime() -> float { return DELTA_TIME; } -// Bucle principal +// Avanza un frame (llamado desde Director::iterate) +void Credits::iterate() { + checkInput(); + const float DELTA_TIME = calculateDeltaTime(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void Credits::handleEvent(const SDL_Event& /*event*/) { + // Eventos globales ya gestionados por Director::handleEvent +} + +// Bucle principal legacy (fallback) void Credits::run() { last_time_ = SDL_GetTicks(); diff --git a/source/sections/credits.hpp b/source/sections/credits.hpp index f0338a2..e71c262 100644 --- a/source/sections/credits.hpp +++ b/source/sections/credits.hpp @@ -22,7 +22,11 @@ class Credits { Credits(); ~Credits(); - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: diff --git a/source/sections/game.cpp b/source/sections/game.cpp index f7f707b..57ff4ab 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -41,6 +41,7 @@ #include "smart_sprite.hpp" // Para SmartSprite #include "stage.hpp" // Para StageManager, StageData #include "tabe.hpp" // Para Tabe +#include "ui/logger.hpp" // Para section #include "text.hpp" // Para Text #include "texture.hpp" // Para Texture #include "ui/service_menu.hpp" // Para ServiceMenu @@ -131,6 +132,11 @@ Game::Game(Player::Id player_id, int current_stage, bool demo_enabled) #ifdef RECORDING setState(State::PLAYING); #endif + + Logger::section(demo_.enabled ? "GAME (DEMO)" : "GAME"); + + // Inicializa el timer de delta time para el primer frame del callback + last_time_ = SDL_GetTicks(); } Game::~Game() { @@ -978,7 +984,33 @@ auto Game::calculateDeltaTime() -> float { return DELTA_TIME_MS / 1000.0F; // Convertir de milisegundos a segundos } -// Bucle para el juego +// Avanza un frame del juego (llamado desde Director::iterate) +void Game::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento del juego (llamado desde Director::handleEvent) +void Game::handleEvent(const SDL_Event& event) { + switch (event.type) { + case SDL_EVENT_WINDOW_FOCUS_LOST: + pause_manager_->setFocusLossPause(!demo_.enabled); + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + pause_manager_->setFocusLossPause(false); + break; + default: + break; + } + +#ifdef _DEBUG + handleDebugEvents(event); +#endif +} + +// Bucle para el juego (fallback legacy) void Game::run() { last_time_ = SDL_GetTicks(); diff --git a/source/sections/game.hpp b/source/sections/game.hpp index 20d9b51..d69ef83 100644 --- a/source/sections/game.hpp +++ b/source/sections/game.hpp @@ -60,7 +60,11 @@ class Game { Game(Player::Id player_id, int current_stage, bool demo_enabled); // Constructor principal ~Game(); // Destructor - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); // Ejecuta el bucle principal del juego private: diff --git a/source/sections/hiscore_table.cpp b/source/sections/hiscore_table.cpp index 7803d94..d6e4c0f 100644 --- a/source/sections/hiscore_table.cpp +++ b/source/sections/hiscore_table.cpp @@ -23,6 +23,7 @@ #include "resource.hpp" // Para Resource #include "screen.hpp" // Para Screen #include "section.hpp" // Para Name, name, Options, options +#include "ui/logger.hpp" // Para section #include "sprite.hpp" // Para Sprite #include "text.hpp" // Para Text, Text::SHADOW, Text::COLOR #include "texture.hpp" // Para Texture @@ -45,6 +46,12 @@ HiScoreTable::HiScoreTable() initBackground(); iniEntryColors(); createSprites(); + + Logger::section("HI-SCORE TABLE"); + + // Inicializa el timer de delta time y arranca la música + last_time_ = SDL_GetTicks(); + Audio::get()->playMusic("title.ogg"); } // Destructor @@ -126,7 +133,20 @@ auto HiScoreTable::calculateDeltaTime() -> float { return DELTA_TIME; } -// Bucle para la pantalla de instrucciones +// Avanza un frame (llamado desde Director::iterate) +void HiScoreTable::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void HiScoreTable::handleEvent(const SDL_Event& /*event*/) { + // Eventos globales ya gestionados por Director::handleEvent +} + +// Bucle para la pantalla de puntuaciones (fallback legacy) void HiScoreTable::run() { last_time_ = SDL_GetTicks(); Audio::get()->playMusic("title.ogg"); diff --git a/source/sections/hiscore_table.hpp b/source/sections/hiscore_table.hpp index 05c9e66..90ad0f9 100644 --- a/source/sections/hiscore_table.hpp +++ b/source/sections/hiscore_table.hpp @@ -27,7 +27,11 @@ class HiScoreTable { HiScoreTable(); ~HiScoreTable(); - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: diff --git a/source/sections/instructions.cpp b/source/sections/instructions.cpp index 6154beb..47c253e 100644 --- a/source/sections/instructions.cpp +++ b/source/sections/instructions.cpp @@ -23,6 +23,7 @@ #include "sprite.hpp" // Para Sprite #include "text.hpp" // Para Text, Text::CENTER, Text::COLOR, Text::SHADOW #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode +#include "ui/logger.hpp" // Para section #include "utils.hpp" // Constructor @@ -57,6 +58,12 @@ Instructions::Instructions() // Inicializa los sprites de los items iniSprites(); + + Logger::section("INSTRUCTIONS"); + + // Inicializa el timer de delta time y arranca la música + last_time_ = SDL_GetTicks(); + Audio::get()->playMusic("title.ogg"); } // Destructor @@ -262,7 +269,20 @@ auto Instructions::calculateDeltaTime() -> float { return DELTA_TIME; } -// Bucle para la pantalla de instrucciones +// Avanza un frame (llamado desde Director::iterate) +void Instructions::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void Instructions::handleEvent(const SDL_Event& /*event*/) { + // Eventos globales ya gestionados por Director::handleEvent +} + +// Bucle para la pantalla de instrucciones (fallback legacy) void Instructions::run() { last_time_ = SDL_GetTicks(); Audio::get()->playMusic("title.ogg"); diff --git a/source/sections/instructions.hpp b/source/sections/instructions.hpp index 7684b8b..5c489a4 100644 --- a/source/sections/instructions.hpp +++ b/source/sections/instructions.hpp @@ -48,7 +48,11 @@ class Instructions { Instructions(); ~Instructions(); - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: diff --git a/source/sections/intro.cpp b/source/sections/intro.cpp index 4c22baa..92cc975 100644 --- a/source/sections/intro.cpp +++ b/source/sections/intro.cpp @@ -20,6 +20,7 @@ #include "text.hpp" // Para Text #include "texture.hpp" // Para Texture #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode +#include "ui/logger.hpp" // Para section #include "utils.hpp" // Para easeOutBounce #include "writer.hpp" // Para Writer @@ -39,6 +40,12 @@ Intro::Intro() // Configura el fondo tiled_bg_->setSpeed(TILED_BG_SPEED); tiled_bg_->setColor(bg_color_); + + Logger::section("INTRO"); + + // Inicializa el timer de delta time y arranca la música + last_time_ = SDL_GetTicks(); + Audio::get()->playMusic("intro.ogg", 0); } // Comprueba los eventos @@ -265,7 +272,20 @@ auto Intro::calculateDeltaTime() -> float { return DELTA_TIME; } -// Bucle principal +// Avanza un frame (llamado desde Director::iterate) +void Intro::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void Intro::handleEvent(const SDL_Event& /*event*/) { + // Eventos globales ya gestionados por Director::handleEvent +} + +// Bucle principal legacy (fallback) void Intro::run() { last_time_ = SDL_GetTicks(); Audio::get()->playMusic("intro.ogg", 0); diff --git a/source/sections/intro.hpp b/source/sections/intro.hpp index d841658..27ab0e3 100644 --- a/source/sections/intro.hpp +++ b/source/sections/intro.hpp @@ -30,7 +30,11 @@ class Intro { Intro(); ~Intro() = default; - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: diff --git a/source/sections/logo.cpp b/source/sections/logo.cpp index 4c8a99b..7aeedfe 100644 --- a/source/sections/logo.cpp +++ b/source/sections/logo.cpp @@ -9,6 +9,7 @@ #include "audio.hpp" // Para Audio #include "color.hpp" // Para Color #include "global_events.hpp" // Para handle +#include "ui/logger.hpp" // Para section #include "global_inputs.hpp" // Para check #include "input.hpp" // Para Input #include "param.hpp" // Para Param, ParamGame, param @@ -47,6 +48,11 @@ Logo::Logo() jail_sprite_.push_back(std::move(temp)); } + Logger::section("LOGO"); + + // Inicializa el timer de delta time para el primer frame del callback + last_time_ = SDL_GetTicks(); + // Inicializa el vector de colores con la paleta ZX Spectrum color_.emplace_back(SPECTRUM_BLACK); color_.emplace_back(SPECTRUM_BLUE); @@ -169,7 +175,20 @@ auto Logo::calculateDeltaTime() -> float { return DELTA_TIME; } -// Bucle para el logo del juego +// Avanza un frame del logo (llamado desde Director::iterate) +void Logo::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void Logo::handleEvent(const SDL_Event& /*event*/) { + // Eventos globales (QUIT, resize, hotplug) ya gestionados por Director::handleEvent +} + +// Bucle para el logo del juego (fallback legacy) void Logo::run() { last_time_ = SDL_GetTicks(); diff --git a/source/sections/logo.hpp b/source/sections/logo.hpp index 49320ee..dc6898c 100644 --- a/source/sections/logo.hpp +++ b/source/sections/logo.hpp @@ -31,7 +31,11 @@ class Logo { Logo(); ~Logo(); - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: diff --git a/source/sections/title.cpp b/source/sections/title.cpp index 07f4c1f..4560078 100644 --- a/source/sections/title.cpp +++ b/source/sections/title.cpp @@ -24,6 +24,7 @@ #include "sprite.hpp" // Para Sprite #include "text.hpp" // Para Text #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode +#include "ui/logger.hpp" // Para section #include "ui/notifier.hpp" // Para Notifier #include "ui/service_menu.hpp" // Para ServiceMenu #include "utils.hpp" // Para Zone, BLOCK @@ -59,6 +60,11 @@ Title::Title() anchor_.mini_logo = (param.game.height / MINI_LOGO_Y_DIVISOR * MINI_LOGO_Y_FACTOR) + BLOCK; mini_logo_sprite_->setY(anchor_.mini_logo); anchor_.copyright_text = anchor_.mini_logo + mini_logo_sprite_->getHeight() + COPYRIGHT_TEXT_SPACING; + + Logger::section("TITLE"); + + // Inicializa el timer de delta time para el primer frame del callback + last_time_ = SDL_GetTicks(); } // Destructor @@ -213,7 +219,22 @@ void Title::activatePlayerAndSetState(Player::Id player_id) { counter_time_ = 0.0F; } -// Bucle para el titulo del juego +// Avanza un frame (llamado desde Director::iterate) +void Title::iterate() { + const float DELTA_TIME = calculateDeltaTime(); + checkInput(); + update(DELTA_TIME); + render(); +} + +// Procesa un evento (llamado desde Director::handleEvent) +void Title::handleEvent(const SDL_Event& event) { + if (event.type == SDL_EVENT_KEY_DOWN) { + handleKeyDownEvent(event); + } +} + +// Bucle para el titulo del juego (fallback legacy) void Title::run() { last_time_ = SDL_GetTicks(); diff --git a/source/sections/title.hpp b/source/sections/title.hpp index 4683508..88ca72b 100644 --- a/source/sections/title.hpp +++ b/source/sections/title.hpp @@ -40,7 +40,11 @@ class Title { Title(); ~Title(); - // --- Bucle principal --- + // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS --- + void iterate(); // Ejecuta un frame + void handleEvent(const SDL_Event& event); // Procesa un evento + + // --- Bucle principal legacy (fallback) --- void run(); private: