sdl_callbacks

This commit is contained in:
2026-04-14 12:21:00 +02:00
parent c0accd25e2
commit f5da35bfb2
20 changed files with 406 additions and 177 deletions

View File

@@ -16,6 +16,7 @@
#include "asset.hpp" // Para Asset #include "asset.hpp" // Para Asset
#include "audio.hpp" // Para Audio #include "audio.hpp" // Para Audio
#include "external/fkyaml_node.hpp" // Para fkyaml::node #include "external/fkyaml_node.hpp" // Para fkyaml::node
#include "global_events.hpp" // Para GlobalEvents::handle
#include "input.hpp" // Para Input #include "input.hpp" // Para Input
#include "lang.hpp" // Para setLanguage #include "lang.hpp" // Para setLanguage
#include "manage_hiscore_table.hpp" // Para ManageHiScoreTable #include "manage_hiscore_table.hpp" // Para ManageHiScoreTable
@@ -75,6 +76,9 @@ Director::Director(int argc, std::span<char*> argv) {
} }
Director::~Director() { Director::~Director() {
// Libera las secciones primero: sus destructores pueden tocar Audio/Resource/Screen,
// que close() destruye a continuación.
resetActiveSection();
close(); close();
Logger::put("\nBye!"); Logger::put("\nBye!");
} }
@@ -335,28 +339,48 @@ void Director::createSystemFolder(const std::string& folder) {
} }
} }
// Ejecuta la sección con el logo // Libera todos los unique_ptr de sección (solo uno tiene propiedad a la vez)
void Director::runLogo() { void Director::resetActiveSection() {
auto logo = std::make_unique<Logo>(); logo_.reset();
logo->run(); intro_.reset();
title_.reset();
game_.reset();
instructions_.reset();
hi_score_table_.reset();
credits_.reset();
} }
// Ejecuta la sección con la secuencia de introducción // Destruye la sección anterior y construye la nueva cuando Section::name cambia
void Director::runIntro() { void Director::handleSectionTransition() {
auto intro = std::make_unique<Intro>(); // RESET: recarga recursos y vuelve a LOGO (el propio reset() cambia Section::name)
intro->run(); if (Section::name == Section::Name::RESET) {
resetActiveSection(); // libera recursos actuales antes del reload
reset();
} }
// Ejecuta la sección con el título del juego if (Section::name == last_built_section_name_) {
void Director::runTitle() { return; // ya tenemos la sección correcta viva
auto title = std::make_unique<Title>();
title->run();
} }
// Ejecuta la sección donde se juega al juego // Destruye la sección anterior
void Director::runGame() { resetActiveSection();
// Construye la nueva
switch (Section::name) {
case Section::Name::LOGO:
logo_ = std::make_unique<Logo>();
break;
case Section::Name::INTRO:
intro_ = std::make_unique<Intro>();
break;
case Section::Name::TITLE:
title_ = std::make_unique<Title>();
break;
case Section::Name::GAME: {
Player::Id player_id = Player::Id::PLAYER1; Player::Id player_id = Player::Id::PLAYER1;
switch (Section::options) { switch (Section::options) {
case Section::Options::GAME_PLAY_1P: case Section::Options::GAME_PLAY_1P:
player_id = Player::Id::PLAYER1; player_id = Player::Id::PLAYER1;
@@ -370,40 +394,41 @@ void Director::runGame() {
default: default:
break; break;
} }
#ifdef _DEBUG #ifdef _DEBUG
const int CURRENT_STAGE = debug_config.initial_stage; const int CURRENT_STAGE = debug_config.initial_stage;
#else #else
constexpr int CURRENT_STAGE = 0; constexpr int CURRENT_STAGE = 0;
#endif #endif
auto game = std::make_unique<Game>(player_id, CURRENT_STAGE, Game::DEMO_OFF); game_ = std::make_unique<Game>(player_id, CURRENT_STAGE, Game::DEMO_OFF);
game->run(); break;
} }
// Ejecuta la sección donde se muestran las instrucciones case Section::Name::GAME_DEMO: {
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); const auto PLAYER_ID = static_cast<Player::Id>((rand() % 2) + 1);
constexpr auto CURRENT_STAGE = 0; constexpr auto CURRENT_STAGE = 0;
auto game = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON); game_ = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON);
game->run(); 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;
}
last_built_section_name_ = Section::name;
} }
// Reinicia objetos y vuelve a la sección inicial // Reinicia objetos y vuelve a la sección inicial
@@ -418,43 +443,58 @@ void Director::reset() {
Section::name = Section::Name::LOGO; Section::name = Section::Name::LOGO;
} }
auto Director::run() -> int { // Avanza un frame de la sección activa (llamado desde SDL_AppIterate)
// Bucle principal auto Director::iterate() -> SDL_AppResult {
while (Section::name != Section::Name::QUIT) { if (Section::name == Section::Name::QUIT) {
switch (Section::name) { return SDL_APP_SUCCESS;
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;
}
} }
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 // Apaga el sistema de forma segura

View File

@@ -1,12 +1,26 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_AppResult, SDL_Event
#include <memory> // Para unique_ptr
#include <span> // Para Span #include <span> // Para Span
#include <string> // Para string #include <string> // Para string
#include "section.hpp" // Para Section::Name
namespace Lang { namespace Lang {
enum class Code : int; 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 --- // --- Clase Director: gestor principal de la aplicación ---
class Director { class Director {
public: public:
@@ -14,8 +28,9 @@ class Director {
Director(int argc, std::span<char*> argv); Director(int argc, std::span<char*> argv);
~Director(); ~Director();
// --- Bucle principal --- // --- Callbacks para SDL_MAIN_USE_CALLBACKS ---
static auto run() -> int; 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) --- // --- Debug config (accesible desde otras clases) ---
struct DebugConfig { struct DebugConfig {
@@ -37,6 +52,16 @@ class Director {
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
std::string system_folder_; // Carpeta del sistema para almacenar datos 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 --- // --- Inicialización y cierre del sistema ---
void init(); // Inicializa la aplicación void init(); // Inicializa la aplicación
static void close(); // Cierra y libera recursos static void close(); // Cierra y libera recursos
@@ -51,15 +76,9 @@ class Director {
void loadAssets(); // Crea el índice de archivos disponibles 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) void checkProgramArguments(int argc, std::span<char*> argv); // Verifica los parámetros del programa // NOLINT(modernize-avoid-c-arrays)
// --- Secciones del programa --- // --- Gestión de secciones ---
static void runLogo(); // Ejecuta la pantalla con el logo void handleSectionTransition(); // Destruye la sección anterior y construye la nueva si Section::name ha cambiado
static void runIntro(); // Ejecuta la introducción del juego void resetActiveSection(); // Libera todos los unique_ptr de sección
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 static void reset(); // Reinicia objetos y vuelve a la sección inicial
// --- Gestión de archivos de idioma --- // --- Gestión de archivos de idioma ---

View File

@@ -306,10 +306,17 @@ void Input::addGamepadMappingsFromFile() {
} }
void Input::discoverGamepads() { void Input::discoverGamepads() {
SDL_Event event; // Enumera los gamepads ya conectados sin drenar la cola de eventos de SDL
while (SDL_PollEvent(&event)) { // (necesario con SDL_MAIN_USE_CALLBACKS, que entrega los eventos por SDL_AppEvent).
handleEvent(event); // Comprueba mandos conectados 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() { void Input::initSDLGamePad() {

View File

@@ -7,15 +7,26 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
*/ */
#include <memory> // Para make_unique, unique_ptr #define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL_main.h>
#include <span> // Para span #include <span> // Para span
#include "director.hpp" // Para Director #include "director.hpp" // Para Director
auto main(int argc, char* argv[]) -> int { SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
// Crea el objeto Director *appstate = new Director(argc, std::span<char*>(argv, argc));
auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc)); return SDL_APP_CONTINUE;
}
// Bucle principal
return Director::run(); 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);
} }

View File

@@ -467,10 +467,10 @@ void Resource::reload() {
// Carga los sonidos del juego // Carga los sonidos del juego
void Resource::loadSounds() { void Resource::loadSounds() {
Logger::info("SOUND FILES");
auto list = Asset::get()->getListByType(Asset::Type::SOUND); auto list = Asset::get()->getListByType(Asset::Type::SOUND);
sounds_.clear(); sounds_.clear();
int failed = 0;
for (const auto& l : list) { for (const auto& l : list) {
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
@@ -479,21 +479,23 @@ void Resource::loadSounds() {
if (!audio_data.data.empty()) { if (!audio_data.data.empty()) {
sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size()); sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size());
} else { } else {
// Fallback a cargar desde disco si no está en pack
sound = JA_LoadSound(l.c_str()); sound = JA_LoadSound(l.c_str());
} }
sounds_.emplace_back(name, sound); if (sound == nullptr) {
Logger::dots("Sound : ", name, "[ LOADED ]"); Logger::error(" Sound load failed: " + name);
++failed;
} }
sounds_.emplace_back(name, sound);
}
Logger::info("Sounds loaded: " + std::to_string(list.size() - failed) + "/" + std::to_string(list.size()));
} }
// Carga las músicas del juego // Carga las músicas del juego
void Resource::loadMusics() { void Resource::loadMusics() {
Logger::cr();
Logger::info("MUSIC FILES");
auto list = Asset::get()->getListByType(Asset::Type::MUSIC); auto list = Asset::get()->getListByType(Asset::Type::MUSIC);
musics_.clear(); musics_.clear();
int failed = 0;
for (const auto& l : list) { for (const auto& l : list) {
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
@@ -502,18 +504,19 @@ void Resource::loadMusics() {
if (!audio_data.data.empty()) { if (!audio_data.data.empty()) {
music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size()); music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size());
} else { } else {
// Fallback a cargar desde disco si no está en pack
music = JA_LoadMusic(l.c_str()); music = JA_LoadMusic(l.c_str());
} }
musics_.emplace_back(name, music); if (music == nullptr) {
Logger::dots("Music : ", name, "[ LOADED ]"); Logger::error(" Music load failed: " + name);
++failed;
} }
musics_.emplace_back(name, music);
}
Logger::info("Musics loaded: " + std::to_string(list.size() - failed) + "/" + std::to_string(list.size()));
} }
// Carga las texturas del juego // Carga las texturas del juego
void Resource::loadTextures() { void Resource::loadTextures() {
Logger::cr();
Logger::info("TEXTURES");
auto list = Asset::get()->getListByType(Asset::Type::BITMAP); auto list = Asset::get()->getListByType(Asset::Type::BITMAP);
textures_.clear(); textures_.clear();
@@ -522,12 +525,11 @@ void Resource::loadTextures() {
updateLoadingProgress(name); updateLoadingProgress(name);
textures_.emplace_back(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l)); 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 // Carga los ficheros de texto del juego
void Resource::loadTextFiles() { void Resource::loadTextFiles() {
Logger::cr();
Logger::info("TEXT FILES");
auto list = Asset::get()->getListByType(Asset::Type::FONT); auto list = Asset::get()->getListByType(Asset::Type::FONT);
text_files_.clear(); text_files_.clear();
@@ -536,12 +538,11 @@ void Resource::loadTextFiles() {
updateLoadingProgress(name); updateLoadingProgress(name);
text_files_.emplace_back(name, Text::loadFile(l)); text_files_.emplace_back(name, Text::loadFile(l));
} }
Logger::info("Text files loaded: " + std::to_string(list.size()));
} }
// Carga las animaciones del juego // Carga las animaciones del juego
void Resource::loadAnimations() { void Resource::loadAnimations() {
Logger::cr();
Logger::info("ANIMATIONS");
auto list = Asset::get()->getListByType(Asset::Type::ANIMATION); auto list = Asset::get()->getListByType(Asset::Type::ANIMATION);
animations_.clear(); animations_.clear();
@@ -550,12 +551,11 @@ void Resource::loadAnimations() {
updateLoadingProgress(name); updateLoadingProgress(name);
animations_.emplace_back(name, loadAnimationsFromFile(l)); animations_.emplace_back(name, loadAnimationsFromFile(l));
} }
Logger::info("Animations loaded: " + std::to_string(list.size()));
} }
// Carga los datos para el modo demostración // Carga los datos para el modo demostración
void Resource::loadDemoData() { void Resource::loadDemoData() {
Logger::cr();
Logger::info("DEMO FILES");
auto list = Asset::get()->getListByType(Asset::Type::DEMODATA); auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
demos_.clear(); demos_.clear();
@@ -564,13 +564,11 @@ void Resource::loadDemoData() {
updateLoadingProgress(name); updateLoadingProgress(name);
demos_.emplace_back(loadDemoDataFromFile(l)); 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 // Crea las texturas de jugadores con todas sus variantes de paleta
void Resource::createPlayerTextures() { void Resource::createPlayerTextures() {
Logger::cr();
Logger::info("CREATING PLAYER TEXTURES");
// Configuración de jugadores y sus paletas // Configuración de jugadores y sus paletas
struct PlayerConfig { struct PlayerConfig {
std::string base_texture; std::string base_texture;
@@ -641,9 +639,9 @@ void Resource::createPlayerTextures() {
// Guardar con nombre específico // Guardar con nombre específico
std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx); std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx);
textures_.emplace_back(texture_name, texture); 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 // Crea texturas a partir de textos para mostrar puntuaciones y mensajes
@@ -657,9 +655,6 @@ void Resource::createTextTextures() {
text(std::move(text_init)) {} text(std::move(text_init)) {}
}; };
Logger::cr();
Logger::info("CREATING TEXTURES");
// Texturas de tamaño normal con outline // Texturas de tamaño normal con outline
std::vector<NameAndText> strings1 = { std::vector<NameAndText> strings1 = {
{"game_text_1000_points", "1.000"}, {"game_text_1000_points", "1.000"},
@@ -673,7 +668,6 @@ void Resource::createTextTextures() {
auto text1 = getText("04b_25_enhanced"); auto text1 = getText("04b_25_enhanced");
for (const auto& s : strings1) { 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)); 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 // Texturas de tamaño doble
@@ -688,8 +682,9 @@ void Resource::createTextTextures() {
auto text2 = getText("04b_25_2x_enhanced"); auto text2 = getText("04b_25_2x_enhanced");
for (const auto& s : strings2) { 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)); 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 // 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)) {} white_texture_file(std::move(w_file)) {}
}; };
Logger::cr();
Logger::info("CREATING TEXT OBJECTS");
std::vector<ResourceInfo> resources = { std::vector<ResourceInfo> resources = {
{"04b_25", "04b_25.png", "04b_25.txt"}, {"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 {"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 // Crear texto normal
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file))); 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 // Vacía el vector de sonidos y libera la memoria asociada
@@ -853,23 +845,6 @@ void Resource::renderProgress() {
screen->coreRender(); 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) // Carga los datos para el modo demostración (sin mostrar progreso)
void Resource::loadDemoDataQuiet() { void Resource::loadDemoDataQuiet() {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> DEMO FILES (quiet load)"); 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}; 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) { void Resource::updateLoadingProgress(std::string name) {
loading_resource_name_ = std::move(name); loading_resource_name_ = std::move(name);
loading_count_.increase(); loading_count_.increase();
updateProgressBar(); updateProgressBar();
renderProgress(); renderProgress();
checkEvents();
} }
// Actualiza la barra de estado // Actualiza la barra de estado

View File

@@ -174,7 +174,6 @@ class Resource {
// --- Métodos internos para gestionar el progreso --- // --- Métodos internos para gestionar el progreso ---
void calculateTotalResources(); // Calcula el número de recursos para cargar void calculateTotalResources(); // Calcula el número de recursos para cargar
void renderProgress(); // Muestra el progreso de carga 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 updateLoadingProgress(std::string name); // Actualiza el progreso de carga
void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso
void updateProgressBar(); // Actualiza la barra de estado void updateProgressBar(); // Actualiza la barra de estado

View File

@@ -28,6 +28,7 @@
#include "text.hpp" // Para Text #include "text.hpp" // Para Text
#include "texture.hpp" // Para Texture #include "texture.hpp" // Para Texture
#include "tiled_bg.hpp" // Para TiledBG, TiledBGMode #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode
#include "ui/logger.hpp" // Para section
#include "ui/service_menu.hpp" // Para ServiceMenu #include "ui/service_menu.hpp" // Para ServiceMenu
#include "utils.hpp" // Para Zone #include "utils.hpp" // Para Zone
@@ -47,6 +48,11 @@ Credits::Credits()
} }
initVars(); initVars();
startCredits(); startCredits();
Logger::section("CREDITS");
// Inicializa el timer de delta time para el primer frame del callback
last_time_ = SDL_GetTicks();
} }
// Destructor // Destructor
@@ -69,7 +75,20 @@ auto Credits::calculateDeltaTime() -> float {
return DELTA_TIME; 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() { void Credits::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();

View File

@@ -22,7 +22,11 @@ class Credits {
Credits(); 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(); void run();
private: private:

View File

@@ -41,6 +41,7 @@
#include "smart_sprite.hpp" // Para SmartSprite #include "smart_sprite.hpp" // Para SmartSprite
#include "stage.hpp" // Para StageManager, StageData #include "stage.hpp" // Para StageManager, StageData
#include "tabe.hpp" // Para Tabe #include "tabe.hpp" // Para Tabe
#include "ui/logger.hpp" // Para section
#include "text.hpp" // Para Text #include "text.hpp" // Para Text
#include "texture.hpp" // Para Texture #include "texture.hpp" // Para Texture
#include "ui/service_menu.hpp" // Para ServiceMenu #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 #ifdef RECORDING
setState(State::PLAYING); setState(State::PLAYING);
#endif #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() { Game::~Game() {
@@ -978,7 +984,33 @@ auto Game::calculateDeltaTime() -> float {
return DELTA_TIME_MS / 1000.0F; // Convertir de milisegundos a segundos 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() { void Game::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();

View File

@@ -60,7 +60,11 @@ class Game {
Game(Player::Id player_id, int current_stage, bool demo_enabled); // Constructor principal Game(Player::Id player_id, int current_stage, bool demo_enabled); // Constructor principal
~Game(); // Destructor ~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 void run(); // Ejecuta el bucle principal del juego
private: private:

View File

@@ -23,6 +23,7 @@
#include "resource.hpp" // Para Resource #include "resource.hpp" // Para Resource
#include "screen.hpp" // Para Screen #include "screen.hpp" // Para Screen
#include "section.hpp" // Para Name, name, Options, options #include "section.hpp" // Para Name, name, Options, options
#include "ui/logger.hpp" // Para section
#include "sprite.hpp" // Para Sprite #include "sprite.hpp" // Para Sprite
#include "text.hpp" // Para Text, Text::SHADOW, Text::COLOR #include "text.hpp" // Para Text, Text::SHADOW, Text::COLOR
#include "texture.hpp" // Para Texture #include "texture.hpp" // Para Texture
@@ -45,6 +46,12 @@ HiScoreTable::HiScoreTable()
initBackground(); initBackground();
iniEntryColors(); iniEntryColors();
createSprites(); 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 // Destructor
@@ -126,7 +133,20 @@ auto HiScoreTable::calculateDeltaTime() -> float {
return DELTA_TIME; 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() { void HiScoreTable::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();
Audio::get()->playMusic("title.ogg"); Audio::get()->playMusic("title.ogg");

View File

@@ -27,7 +27,11 @@ class HiScoreTable {
HiScoreTable(); 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(); void run();
private: private:

View File

@@ -23,6 +23,7 @@
#include "sprite.hpp" // Para Sprite #include "sprite.hpp" // Para Sprite
#include "text.hpp" // Para Text, Text::CENTER, Text::COLOR, Text::SHADOW #include "text.hpp" // Para Text, Text::CENTER, Text::COLOR, Text::SHADOW
#include "tiled_bg.hpp" // Para TiledBG, TiledBGMode #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode
#include "ui/logger.hpp" // Para section
#include "utils.hpp" #include "utils.hpp"
// Constructor // Constructor
@@ -57,6 +58,12 @@ Instructions::Instructions()
// Inicializa los sprites de los items // Inicializa los sprites de los items
iniSprites(); 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 // Destructor
@@ -262,7 +269,20 @@ auto Instructions::calculateDeltaTime() -> float {
return DELTA_TIME; 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() { void Instructions::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();
Audio::get()->playMusic("title.ogg"); Audio::get()->playMusic("title.ogg");

View File

@@ -48,7 +48,11 @@ class Instructions {
Instructions(); 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(); void run();
private: private:

View File

@@ -20,6 +20,7 @@
#include "text.hpp" // Para Text #include "text.hpp" // Para Text
#include "texture.hpp" // Para Texture #include "texture.hpp" // Para Texture
#include "tiled_bg.hpp" // Para TiledBG, TiledBGMode #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode
#include "ui/logger.hpp" // Para section
#include "utils.hpp" // Para easeOutBounce #include "utils.hpp" // Para easeOutBounce
#include "writer.hpp" // Para Writer #include "writer.hpp" // Para Writer
@@ -39,6 +40,12 @@ Intro::Intro()
// Configura el fondo // Configura el fondo
tiled_bg_->setSpeed(TILED_BG_SPEED); tiled_bg_->setSpeed(TILED_BG_SPEED);
tiled_bg_->setColor(bg_color_); 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 // Comprueba los eventos
@@ -265,7 +272,20 @@ auto Intro::calculateDeltaTime() -> float {
return DELTA_TIME; 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() { void Intro::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();
Audio::get()->playMusic("intro.ogg", 0); Audio::get()->playMusic("intro.ogg", 0);

View File

@@ -30,7 +30,11 @@ class Intro {
Intro(); Intro();
~Intro() = default; ~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(); void run();
private: private:

View File

@@ -9,6 +9,7 @@
#include "audio.hpp" // Para Audio #include "audio.hpp" // Para Audio
#include "color.hpp" // Para Color #include "color.hpp" // Para Color
#include "global_events.hpp" // Para handle #include "global_events.hpp" // Para handle
#include "ui/logger.hpp" // Para section
#include "global_inputs.hpp" // Para check #include "global_inputs.hpp" // Para check
#include "input.hpp" // Para Input #include "input.hpp" // Para Input
#include "param.hpp" // Para Param, ParamGame, param #include "param.hpp" // Para Param, ParamGame, param
@@ -47,6 +48,11 @@ Logo::Logo()
jail_sprite_.push_back(std::move(temp)); 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 // Inicializa el vector de colores con la paleta ZX Spectrum
color_.emplace_back(SPECTRUM_BLACK); color_.emplace_back(SPECTRUM_BLACK);
color_.emplace_back(SPECTRUM_BLUE); color_.emplace_back(SPECTRUM_BLUE);
@@ -169,7 +175,20 @@ auto Logo::calculateDeltaTime() -> float {
return DELTA_TIME; 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() { void Logo::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();

View File

@@ -31,7 +31,11 @@ class Logo {
Logo(); 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(); void run();
private: private:

View File

@@ -24,6 +24,7 @@
#include "sprite.hpp" // Para Sprite #include "sprite.hpp" // Para Sprite
#include "text.hpp" // Para Text #include "text.hpp" // Para Text
#include "tiled_bg.hpp" // Para TiledBG, TiledBGMode #include "tiled_bg.hpp" // Para TiledBG, TiledBGMode
#include "ui/logger.hpp" // Para section
#include "ui/notifier.hpp" // Para Notifier #include "ui/notifier.hpp" // Para Notifier
#include "ui/service_menu.hpp" // Para ServiceMenu #include "ui/service_menu.hpp" // Para ServiceMenu
#include "utils.hpp" // Para Zone, BLOCK #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; anchor_.mini_logo = (param.game.height / MINI_LOGO_Y_DIVISOR * MINI_LOGO_Y_FACTOR) + BLOCK;
mini_logo_sprite_->setY(anchor_.mini_logo); mini_logo_sprite_->setY(anchor_.mini_logo);
anchor_.copyright_text = anchor_.mini_logo + mini_logo_sprite_->getHeight() + COPYRIGHT_TEXT_SPACING; 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 // Destructor
@@ -213,7 +219,22 @@ void Title::activatePlayerAndSetState(Player::Id player_id) {
counter_time_ = 0.0F; 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() { void Title::run() {
last_time_ = SDL_GetTicks(); last_time_ = SDL_GetTicks();

View File

@@ -40,7 +40,11 @@ class Title {
Title(); 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(); void run();
private: private: