#pragma once #include #include #include #include #include "core/scene/scene.hpp" #include "core/ui/ui_config.hpp" #include "game/entities/entity_manager.hpp" #include "game/map/paint_layer.hpp" #include "game/map/tilemap.hpp" #ifdef _DEBUG #include "game/editor/editor.hpp" #endif class Hud; class Player; class Text; class GameScene : public Scene { public: // Conjunt de rutes que defineixen una piràmide concreta (mapa + tilemap // + sprites del jugador + música). Cada piràmide serà un Config distint; // `defaultConfig()` retorna la primera (Defaults::Pyramid). struct Config { std::string map_yaml; std::string player_sprite; std::string player_yaml; std::string music_track; }; [[nodiscard]] static auto defaultConfig() -> Config; explicit GameScene(Config config = defaultConfig()); ~GameScene() override; void update(int delta_ms) override; void render() override; private: // Consumeix events d'aquest frame (F11 del KeyConfig "pause" o botó // START del gamepad primari) per disparar les transicions de pausa. // No alterna un flag binari: inicia (o inverteix mid-flight) un // "dial" de temps que frena el món amb easing. void handlePauseInput(); // Avança la transició activa, recalcula `pause_.scale` i aplica el // fade de volum de música. S'executa cada frame amb el delta real // (no escalat) perquè la transició viu en temps real. void updatePauseTransition(int delta_ms); Config config_; Tilemap tilemap_; // Gestor d'entitats del nivell (sarcòfags, porta, momia, antorxa, // etc.). Viu aquí perquè la seua vida coincideix amb la de la escena; // cada entitat del nivell es carrega al ctor via loadFromLevel. EntityManager entity_manager_; // Vector des del principi: AEE suportarà multijugador local; cada Player // té els seus propis Controls i entra al vector amb una crida extra. std::vector> players_; // Capa de "pintat" del terra. Escolta `on_tile_entered` al bus, // filtra pintabilitat (sòl transitable) i re-publica `tile_painted` // per als sarcòfags. `unique_ptr` per controlar l'ordre de // construcció/destrucció: es crea al ctor un cop `entity_manager_` i // `tilemap_` estan llestos, i es destrueix abans que `entity_manager_` // (on viu el bus al qual està subscrit). Declarat després d'aquests // dos membres per garantir l'ordre invers a la destrucció. std::unique_ptr paint_layer_; // Marcador de la franja superior (24 px). `unique_ptr` per controlar // l'ordre de construcció/destrucció igual que `paint_layer_`: es crea // al ctor un cop `entity_manager_` ja té el bus, i es destrueix abans // que `entity_manager_` (on viu el bus al qual està subscrit). // Declarat després d'`entity_manager_` per garantir l'ordre invers a // la destrucció. std::unique_ptr hud_; // Pausa de gameplay com a "dial" de temps. En lloc d'un interruptor, // `pause_.scale` va de 1 (món corrent) a 0 (món congelat) amb una // corba d'easing durant ENTERING, i al revés durant EXITING. El // `delta_ms` del món (players + EntityManager) es multiplica per // aquesta escala; HUD, Notifier i GlobalInputs reben sempre el // delta real. Les inversions mid-flight capturen la `scale` actual // com a `from_scale` i escalen la durada a la distància restant per // mantenir la sensació de velocitat. La font és la mateixa que // abans — ja cachejada al Director. std::shared_ptr pause_font_; enum class PauseState : std::uint8_t { IDLE, // Joc corrent; cap transició en marxa. scale == 1. ENTERING, // Frenant cap a la pausa. scale decreix a 0. PAUSED, // Món congelat. scale == 0. EXITING, // Accelerant de tornada. scale creix a 1. }; struct PauseTransition { PauseState state{PauseState::IDLE}; float scale{1.0F}; // 0 = parat, 1 = corrent. float from_scale{1.0F}; // Valor de `scale` al començar la transició. float to_scale{1.0F}; // Valor objectiu (0.0 o 1.0). int elapsed_ms{0}; // Temps transcorregut dins la transició. int duration_ms{0}; // Durada total (escalada a la distància). UiConfig::CurveFn curve{nullptr}; // Corba activa. } pause_; #ifdef _DEBUG // Editor modal del tilemap. Mútuament excloent amb la pausa: si la // pausa no està IDLE la tecla de toggle de l'editor s'ignora, i // viceversa. Quan `editor_.active()` és true, saltem entitats i // jugador (update i render) i deixem el tilemap visible perquè es // pugui editar. Editor editor_; #endif };