From 330044e10fd26d032088d34f1b0b2c36873462b4 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 4 Dec 2025 11:51:41 +0100 Subject: [PATCH] millorada la gestio d'escenes i opcions --- source/core/rendering/sdl_manager.hpp | 6 +-- source/core/system/context_escenes.hpp | 70 ++++++++++++++++++++++++++ source/core/system/director.cpp | 33 ++++++++---- source/core/system/gestor_escenes.hpp | 17 ------- source/core/system/global_events.cpp | 14 ++++-- source/core/system/global_events.hpp | 5 +- source/game/escenes/escena_joc.cpp | 23 ++++++--- source/game/escenes/escena_joc.hpp | 4 +- source/game/escenes/escena_logo.cpp | 32 +++++++++--- source/game/escenes/escena_logo.hpp | 4 +- source/game/escenes/escena_titol.cpp | 42 +++++++++++++--- source/game/escenes/escena_titol.hpp | 4 +- 12 files changed, 195 insertions(+), 59 deletions(-) create mode 100644 source/core/system/context_escenes.hpp delete mode 100644 source/core/system/gestor_escenes.hpp diff --git a/source/core/rendering/sdl_manager.hpp b/source/core/rendering/sdl_manager.hpp index 0ac402c..1ebec68 100644 --- a/source/core/rendering/sdl_manager.hpp +++ b/source/core/rendering/sdl_manager.hpp @@ -14,8 +14,7 @@ class SDLManager { public: SDLManager(); // Constructor per defecte (usa Defaults::) - SDLManager(int width, int height, - bool fullscreen); // Constructor amb configuració + SDLManager(int width, int height, bool fullscreen); // Constructor amb configuració ~SDLManager(); // No permetre còpia ni assignació @@ -27,8 +26,7 @@ class SDLManager { void decreaseWindowSize(); // F1: -100px void toggleFullscreen(); // F3 void toggleVSync(); // F4 - bool - handleWindowEvent(const SDL_Event& event); // Per a SDL_EVENT_WINDOW_RESIZED + bool handleWindowEvent(const SDL_Event& event); // Per a SDL_EVENT_WINDOW_RESIZED // Funcions principals (renderitzat) void neteja(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0); diff --git a/source/core/system/context_escenes.hpp b/source/core/system/context_escenes.hpp new file mode 100644 index 0000000..c82b024 --- /dev/null +++ b/source/core/system/context_escenes.hpp @@ -0,0 +1,70 @@ +// context_escenes.hpp - Sistema de gestió d'escenes i context de transicions +// © 2025 Port a C++20 + +#pragma once + +namespace GestorEscenes { + +// Context de transició entre escenes +// Conté l'escena destinació i opcions específiques per aquella escena +class ContextEscenes { +public: + // Tipus d'escena del joc + enum class Escena { + LOGO, // Pantalla d'inici (logo JAILGAMES) + TITOL, // Pantalla de títol amb menú + JOC, // Joc principal (Asteroids) + EIXIR // Sortir del programa + }; + + // Opcions específiques per a cada escena + enum class Opcio { + NONE, // Sense opcions especials (comportament per defecte) + JUMP_TO_TITLE_MAIN, // TITOL: Saltar directament a MAIN (starfield instantani) + // MODE_DEMO, // JOC: Mode demostració amb IA (futur) + }; + + // Constructor inicial amb escena LOGO i sense opcions + ContextEscenes() + : escena_desti_(Escena::LOGO), + opcio_(Opcio::NONE) {} + + // Canviar escena amb opció específica + void canviar_escena(Escena nova_escena, Opcio opcio = Opcio::NONE) { + escena_desti_ = nova_escena; + opcio_ = opcio; + } + + // Consultar escena destinació + [[nodiscard]] auto escena_desti() const -> Escena { + return escena_desti_; + } + + // Consultar opció actual + [[nodiscard]] auto opcio() const -> Opcio { + return opcio_; + } + + // Consumir opció (retorna valor i reseteja a NONE) + // Utilitzar quan l'escena processa l'opció + [[nodiscard]] auto consumir_opcio() -> Opcio { + Opcio valor = opcio_; + opcio_ = Opcio::NONE; + return valor; + } + + // Reset opció a NONE (sense retornar valor) + void reset_opcio() { + opcio_ = Opcio::NONE; + } + +private: + Escena escena_desti_; // Escena a la qual transicionar + Opcio opcio_; // Opció específica per l'escena +}; + +// Variable global inline per gestionar l'escena actual (backward compatibility) +// Sincronitzada amb context.escena_desti() pel Director +inline ContextEscenes::Escena actual = ContextEscenes::Escena::LOGO; + +} // namespace GestorEscenes diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 688ba7c..15b33a2 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -15,7 +15,7 @@ #include "game/escenes/escena_logo.hpp" #include "game/escenes/escena_titol.hpp" #include "game/options.hpp" -#include "gestor_escenes.hpp" +#include "context_escenes.hpp" #include "project.h" #ifndef _WIN32 @@ -23,6 +23,10 @@ #include #endif +// Using declarations per simplificar el codi +using GestorEscenes::ContextEscenes; +using Escena = ContextEscenes::Escena; + // Constructor Director::Director(std::vector const& args) { std::cout << "Orni Attack - Inici\n"; @@ -169,23 +173,31 @@ auto Director::run() -> int { << AudioCache::getMusicCacheSize() << " fitxers\n"; } + // Crear context d'escenes + ContextEscenes context; + context.canviar_escena(Escena::LOGO); + // Bucle principal de gestió d'escenes - while (GestorEscenes::actual != GestorEscenes::Escena::EIXIR) { - switch (GestorEscenes::actual) { - case GestorEscenes::Escena::LOGO: { - EscenaLogo logo(sdl); + while (context.escena_desti() != Escena::EIXIR) { + // Sincronitzar GestorEscenes::actual amb context + // (altres sistemes encara poden llegir GestorEscenes::actual) + GestorEscenes::actual = context.escena_desti(); + + switch (context.escena_desti()) { + case Escena::LOGO: { + EscenaLogo logo(sdl, context); logo.executar(); break; } - case GestorEscenes::Escena::TITOL: { - EscenaTitol titol(sdl); + case Escena::TITOL: { + EscenaTitol titol(sdl, context); titol.executar(); break; } - case GestorEscenes::Escena::JOC: { - EscenaJoc joc(sdl); + case Escena::JOC: { + EscenaJoc joc(sdl, context); joc.executar(); break; } @@ -195,5 +207,8 @@ auto Director::run() -> int { } } + // Sincronitzar final amb GestorEscenes::actual + GestorEscenes::actual = Escena::EIXIR; + return 0; } diff --git a/source/core/system/gestor_escenes.hpp b/source/core/system/gestor_escenes.hpp deleted file mode 100644 index 63e6ec4..0000000 --- a/source/core/system/gestor_escenes.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// gestor_escenes.hpp - Sistema de gestió d'escenes -// Basat en el patró del projecte "pollo" -// © 2025 Port a C++20 - -#pragma once - -namespace GestorEscenes { -enum class Escena { - LOGO, // Pantalla d'inici (2 segons negre) - TITOL, // Pantalla de títol amb menú - JOC, // Joc principal - EIXIR // Sortir del programa -}; - -// Variable global inline per gestionar l'escena actual -inline Escena actual = Escena::LOGO; -} // namespace GestorEscenes diff --git a/source/core/system/global_events.cpp b/source/core/system/global_events.cpp index 26a801c..edf29d2 100644 --- a/source/core/system/global_events.cpp +++ b/source/core/system/global_events.cpp @@ -5,11 +5,15 @@ #include "core/input/mouse.hpp" #include "core/rendering/sdl_manager.hpp" -#include "gestor_escenes.hpp" +#include "context_escenes.hpp" + +// Using declarations per simplificar el codi +using GestorEscenes::ContextEscenes; +using Escena = ContextEscenes::Escena; namespace GlobalEvents { -bool handle(const SDL_Event& event, SDLManager& sdl) { +bool handle(const SDL_Event& event, SDLManager& sdl, ContextEscenes& context) { // Tecles globals de finestra (F1/F2/F3) if (event.type == SDL_EVENT_KEY_DOWN) { switch (event.key.key) { @@ -26,7 +30,8 @@ bool handle(const SDL_Event& event, SDLManager& sdl) { sdl.toggleVSync(); return true; case SDLK_ESCAPE: - GestorEscenes::actual = GestorEscenes::Escena::EIXIR; + context.canviar_escena(Escena::EIXIR); + GestorEscenes::actual = Escena::EIXIR; return true; default: break; @@ -35,7 +40,8 @@ bool handle(const SDL_Event& event, SDLManager& sdl) { // Tancar finestra if (event.type == SDL_EVENT_QUIT) { - GestorEscenes::actual = GestorEscenes::Escena::EIXIR; + context.canviar_escena(Escena::EIXIR); + GestorEscenes::actual = Escena::EIXIR; return true; } diff --git a/source/core/system/global_events.hpp b/source/core/system/global_events.hpp index d972090..70b1e24 100644 --- a/source/core/system/global_events.hpp +++ b/source/core/system/global_events.hpp @@ -6,11 +6,12 @@ #include -// Forward declaration +// Forward declarations class SDLManager; +namespace GestorEscenes { class ContextEscenes; } namespace GlobalEvents { // Processa events globals (F1/F2/F3/ESC/QUIT) // Retorna true si l'event ha estat processat i no cal seguir processant-lo -bool handle(const SDL_Event& event, SDLManager& sdl); +bool handle(const SDL_Event& event, SDLManager& sdl, GestorEscenes::ContextEscenes& context); } // namespace GlobalEvents diff --git a/source/game/escenes/escena_joc.cpp b/source/game/escenes/escena_joc.cpp index 88561f3..e26849a 100644 --- a/source/game/escenes/escena_joc.cpp +++ b/source/game/escenes/escena_joc.cpp @@ -13,16 +13,26 @@ #include "core/audio/audio.hpp" #include "core/input/mouse.hpp" #include "core/rendering/line_renderer.hpp" -#include "core/system/gestor_escenes.hpp" +#include "core/system/context_escenes.hpp" #include "core/system/global_events.hpp" #include "game/stage_system/stage_loader.hpp" -EscenaJoc::EscenaJoc(SDLManager& sdl) +// Using declarations per simplificar el codi +using GestorEscenes::ContextEscenes; +using Escena = ContextEscenes::Escena; +using Opcio = ContextEscenes::Opcio; + +EscenaJoc::EscenaJoc(SDLManager& sdl, ContextEscenes& context) : sdl_(sdl), + context_(context), debris_manager_(sdl.obte_renderer()), nau_(sdl.obte_renderer()), itocado_(0), text_(sdl.obte_renderer()) { + // Consumir opcions (preparació per MODE_DEMO futur) + auto opcio = context_.consumir_opcio(); + (void)opcio; // Suprimir warning de variable no usada + // Inicialitzar bales amb renderer for (auto& bala : bales_) { bala = Bala(sdl.obte_renderer()); @@ -43,7 +53,7 @@ void EscenaJoc::executar() { SDL_Event event; Uint64 last_time = SDL_GetTicks(); - while (GestorEscenes::actual == GestorEscenes::Escena::JOC) { + while (GestorEscenes::actual == Escena::JOC) { // Calcular delta_time real Uint64 current_time = SDL_GetTicks(); float delta_time = (current_time - last_time) / 1000.0f; @@ -68,7 +78,7 @@ void EscenaJoc::executar() { } // Events globals (F1/F2/F3/ESC/QUIT) - if (GlobalEvents::handle(event, sdl_)) { + if (GlobalEvents::handle(event, sdl_, context_)) { continue; } @@ -158,8 +168,9 @@ void EscenaJoc::actualitzar(float delta_time) { if (game_over_timer_ <= 0.0f) { // Aturar música de joc abans de tornar al títol Audio::get()->stopMusic(); - // Auto-transition to title screen - GestorEscenes::actual = GestorEscenes::Escena::TITOL; + // Transició a pantalla de títol + context_.canviar_escena(Escena::TITOL); + GestorEscenes::actual = Escena::TITOL; return; } diff --git a/source/game/escenes/escena_joc.hpp b/source/game/escenes/escena_joc.hpp index bcb6ad9..c8b69f5 100644 --- a/source/game/escenes/escena_joc.hpp +++ b/source/game/escenes/escena_joc.hpp @@ -18,6 +18,7 @@ #include "../stage_system/stage_manager.hpp" #include "core/graphics/vector_text.hpp" #include "core/rendering/sdl_manager.hpp" +#include "core/system/context_escenes.hpp" #include "core/types.hpp" #include @@ -25,7 +26,7 @@ // Classe principal del joc (escena) class EscenaJoc { public: - explicit EscenaJoc(SDLManager& sdl); + explicit EscenaJoc(SDLManager& sdl, GestorEscenes::ContextEscenes& context); ~EscenaJoc() = default; void executar(); // Bucle principal de l'escena @@ -36,6 +37,7 @@ class EscenaJoc { private: SDLManager& sdl_; + GestorEscenes::ContextEscenes& context_; // Efectes visuals Effects::DebrisManager debris_manager_; diff --git a/source/game/escenes/escena_logo.cpp b/source/game/escenes/escena_logo.cpp index 08abc86..2f159ad 100644 --- a/source/game/escenes/escena_logo.cpp +++ b/source/game/escenes/escena_logo.cpp @@ -13,9 +13,14 @@ #include "core/graphics/shape_loader.hpp" #include "core/input/mouse.hpp" #include "core/rendering/shape_renderer.hpp" -#include "core/system/gestor_escenes.hpp" +#include "core/system/context_escenes.hpp" #include "core/system/global_events.hpp" +// Using declarations per simplificar el codi +using GestorEscenes::ContextEscenes; +using Escena = ContextEscenes::Escena; +using Opcio = ContextEscenes::Opcio; + // Helper: calcular el progrés individual d'una lletra // en funció del progrés global (efecte seqüencial) static float calcular_progress_letra(size_t letra_index, size_t num_letras, float global_progress, float threshold) { @@ -38,14 +43,20 @@ static float calcular_progress_letra(size_t letra_index, size_t num_letras, floa } } -EscenaLogo::EscenaLogo(SDLManager& sdl) +EscenaLogo::EscenaLogo(SDLManager& sdl, ContextEscenes& context) : sdl_(sdl), + context_(context), estat_actual_(EstatAnimacio::PRE_ANIMATION), temps_estat_actual_(0.0f), debris_manager_(std::make_unique(sdl.obte_renderer())), lletra_explosio_index_(0), temps_des_ultima_explosio_(0.0f) { std::cout << "Escena Logo: Inicialitzant...\n"; + + // Consumir opcions (LOGO no processa opcions actualment) + auto opcio = context_.consumir_opcio(); + (void)opcio; // Suprimir warning + so_reproduit_.fill(false); // Inicialitzar seguiment de sons inicialitzar_lletres(); } @@ -54,7 +65,7 @@ void EscenaLogo::executar() { SDL_Event event; Uint64 last_time = SDL_GetTicks(); - while (GestorEscenes::actual == GestorEscenes::Escena::LOGO) { + while (GestorEscenes::actual == Escena::LOGO) { // Calcular delta_time real Uint64 current_time = SDL_GetTicks(); float delta_time = (current_time - last_time) / 1000.0f; @@ -79,7 +90,7 @@ void EscenaLogo::executar() { } // Events globals (F1/F2/F3/ESC/QUIT) - if (GlobalEvents::handle(event, sdl_)) { + if (GlobalEvents::handle(event, sdl_, context_)) { continue; } @@ -292,8 +303,9 @@ void EscenaLogo::actualitzar(float delta_time) { case EstatAnimacio::POST_EXPLOSION: if (temps_estat_actual_ >= DURACIO_POST_EXPLOSION) { - // Iniciar música de títol abans de la transició - GestorEscenes::actual = GestorEscenes::Escena::TITOL; + // Transició a pantalla de títol + context_.canviar_escena(Escena::TITOL); + GestorEscenes::actual = Escena::TITOL; } break; } @@ -394,6 +406,12 @@ void EscenaLogo::processar_events(const SDL_Event& event) { // Qualsevol tecla o clic de ratolí salta a la pantalla de títol if (event.type == SDL_EVENT_KEY_DOWN || event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { - GestorEscenes::actual = GestorEscenes::Escena::TITOL; + // Utilitzar context per especificar escena i opció + context_.canviar_escena( + Escena::TITOL, + Opcio::JUMP_TO_TITLE_MAIN + ); + // Backward compatibility: També actualitzar GestorEscenes::actual + GestorEscenes::actual = Escena::TITOL; } } diff --git a/source/game/escenes/escena_logo.hpp b/source/game/escenes/escena_logo.hpp index e208072..88f5213 100644 --- a/source/game/escenes/escena_logo.hpp +++ b/source/game/escenes/escena_logo.hpp @@ -13,11 +13,12 @@ #include "core/defaults.hpp" #include "core/graphics/shape.hpp" #include "core/rendering/sdl_manager.hpp" +#include "core/system/context_escenes.hpp" #include "core/types.hpp" class EscenaLogo { public: - explicit EscenaLogo(SDLManager& sdl); + explicit EscenaLogo(SDLManager& sdl, GestorEscenes::ContextEscenes& context); void executar(); // Bucle principal de l'escena private: @@ -31,6 +32,7 @@ class EscenaLogo { }; SDLManager& sdl_; + GestorEscenes::ContextEscenes& context_; EstatAnimacio estat_actual_; // Estat actual de la màquina float temps_estat_actual_; // Temps en l'estat actual (reset en cada transició) diff --git a/source/game/escenes/escena_titol.cpp b/source/game/escenes/escena_titol.cpp index 3765f28..c2a4d1e 100644 --- a/source/game/escenes/escena_titol.cpp +++ b/source/game/escenes/escena_titol.cpp @@ -12,12 +12,18 @@ #include "core/graphics/shape_loader.hpp" #include "core/input/mouse.hpp" #include "core/rendering/shape_renderer.hpp" -#include "core/system/gestor_escenes.hpp" +#include "core/system/context_escenes.hpp" #include "core/system/global_events.hpp" #include "project.h" -EscenaTitol::EscenaTitol(SDLManager& sdl) +// Using declarations per simplificar el codi +using GestorEscenes::ContextEscenes; +using Escena = ContextEscenes::Escena; +using Opcio = ContextEscenes::Opcio; + +EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context) : sdl_(sdl), + context_(context), text_(sdl.obte_renderer()), estat_actual_(EstatTitol::STARFIELD_FADE_IN), temps_acumulat_(0.0f), @@ -27,6 +33,15 @@ EscenaTitol::EscenaTitol(SDLManager& sdl) factor_lerp_(0.0f) { std::cout << "Escena Titol: Inicialitzant...\n"; + // Processar opció del context + auto opcio = context_.consumir_opcio(); + + if (opcio == Opcio::JUMP_TO_TITLE_MAIN) { + std::cout << "Escena Titol: Opció JUMP_TO_TITLE_MAIN activada\n"; + estat_actual_ = EstatTitol::MAIN; + temps_estat_main_ = 0.0f; + } + // Crear starfield de fons Punt centre_pantalla{ Defaults::Game::WIDTH / 2.0f, @@ -45,8 +60,14 @@ EscenaTitol::EscenaTitol(SDLManager& sdl) 150 // densitat: 150 estrelles (50 per capa) ); - // Iniciar amb brightness 0.0 per al fade-in - starfield_->set_brightness(0.0f); + // Brightness depèn de l'opció + if (estat_actual_ == EstatTitol::MAIN) { + // Si saltem a MAIN, starfield instantàniament brillant + starfield_->set_brightness(BRIGHTNESS_STARFIELD); + } else { + // Flux normal: comença amb brightness 0.0 per fade-in + starfield_->set_brightness(0.0f); + } // Inicialitzar lletres del títol "ORNI ATTACK!" inicialitzar_titol(); @@ -216,7 +237,7 @@ void EscenaTitol::executar() { SDL_Event event; Uint64 last_time = SDL_GetTicks(); - while (GestorEscenes::actual == GestorEscenes::Escena::TITOL) { + while (GestorEscenes::actual == Escena::TITOL) { // Calcular delta_time real Uint64 current_time = SDL_GetTicks(); float delta_time = (current_time - last_time) / 1000.0f; @@ -241,7 +262,7 @@ void EscenaTitol::executar() { } // Events globals (F1/F2/F3/F4/ESC/QUIT) - if (GlobalEvents::handle(event, sdl_)) { + if (GlobalEvents::handle(event, sdl_, context_)) { continue; } @@ -365,7 +386,7 @@ void EscenaTitol::actualitzar(float delta_time) { temps_acumulat_ += delta_time; if (temps_acumulat_ >= DURACIO_TRANSITION) { // Transició a JOC (la música ja s'ha parat en el fade) - GestorEscenes::actual = GestorEscenes::Escena::JOC; + GestorEscenes::actual = Escena::JOC; } break; } @@ -520,14 +541,21 @@ void EscenaTitol::processar_events(const SDL_Event& event) { // Saltar directament a MAIN (ometre fade-in i starfield) estat_actual_ = EstatTitol::MAIN; starfield_->set_brightness(BRIGHTNESS_STARFIELD); // Assegurar brightness final + temps_estat_main_ = 0.0f; // Reset timer per animació de títol break; case EstatTitol::STARFIELD: // Saltar a MAIN estat_actual_ = EstatTitol::MAIN; + temps_estat_main_ = 0.0f; // Reset timer break; case EstatTitol::MAIN: + // Utilitzar context per transició a JOC + context_.canviar_escena(Escena::JOC); + // NO actualitzar GestorEscenes::actual aquí! + // La transició es fa en l'estat TRANSITION_TO_GAME + // Iniciar transició amb fade-out de música estat_actual_ = EstatTitol::TRANSITION_TO_GAME; temps_acumulat_ = 0.0f; // Reset del comptador diff --git a/source/game/escenes/escena_titol.hpp b/source/game/escenes/escena_titol.hpp index becd0e1..6549281 100644 --- a/source/game/escenes/escena_titol.hpp +++ b/source/game/escenes/escena_titol.hpp @@ -14,11 +14,12 @@ #include "core/graphics/starfield.hpp" #include "core/graphics/vector_text.hpp" #include "core/rendering/sdl_manager.hpp" +#include "core/system/context_escenes.hpp" #include "core/types.hpp" class EscenaTitol { public: - explicit EscenaTitol(SDLManager& sdl); + explicit EscenaTitol(SDLManager& sdl, GestorEscenes::ContextEscenes& context); ~EscenaTitol(); // Destructor per aturar música void executar(); // Bucle principal de l'escena @@ -41,6 +42,7 @@ class EscenaTitol { }; SDLManager& sdl_; + GestorEscenes::ContextEscenes& context_; Graphics::VectorText text_; // Sistema de text vectorial std::unique_ptr starfield_; // Camp d'estrelles de fons EstatTitol estat_actual_; // Estat actual de la màquina