From 63a03ae632a3523da12cae0d06be0acf725d4264 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Tue, 12 May 2026 10:52:46 +0200 Subject: [PATCH] =?UTF-8?q?refactor(pause):=20elimina=20pausa=20F11=20(cob?= =?UTF-8?q?reix-la=20el=20men=C3=BA=20de=20servei)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/config/input.yaml | 3 - data/config/ui.yaml | 11 -- data/locale/ca.yaml | 1 - data/locale/en.yaml | 1 - data/scenes/game/game.yaml | 2 +- source/core/rendering/screen.hpp | 2 +- source/core/ui/ui_config.cpp | 12 -- source/core/ui/ui_config.hpp | 11 -- source/game/scenes/game_scene.cpp | 175 ++++-------------------------- source/game/scenes/game_scene.hpp | 62 ++--------- source/utils/defaults.hpp | 11 -- 11 files changed, 34 insertions(+), 257 deletions(-) diff --git a/data/config/input.yaml b/data/config/input.yaml index 96a65f8..5bdb9bb 100644 --- a/data/config/input.yaml +++ b/data/config/input.yaml @@ -35,9 +35,6 @@ keys: - id: toggle_render_info code: "F10" desc: "Cicle de l'overlay de debug: apagat / dalt / baix" - - id: pause - code: "F11" - desc: "Pausa el joc (o botó START del mando)" - id: menu_toggle code: "F12" desc: "Obri / tanca el menú de servei" diff --git a/data/config/ui.yaml b/data/config/ui.yaml index a490fc9..8eb2af3 100644 --- a/data/config/ui.yaml +++ b/data/config/ui.yaml @@ -114,17 +114,6 @@ notifier: slide_in_curve: outCubic slide_out_curve: inCubic -# Pausa graduada de la GameScene: el món no para d'un colp, s'atura amb -# easing i torna a arrancar amb una altra corba. Els timings es poden -# afinar independentment, i les corbes permeten estils diferents entrant -# i sortint (p.ex. frenar suau i arrancar seca). Corbes disponibles: -# linear, outQuad, inQuad, inOutQuad, outCubic, inCubic. -pause: - enter_ms: 400 - exit_ms: 250 - enter_curve: outCubic - exit_curve: inCubic - # Sons del menú de servei. Els fitxers viuen a data/audio/sounds/. SELECT # acompanya navegació (amunt/avall) i back; ACCEPT acompanya modificació # d'opció (esquerra/dreta/retorn) o entrada a un submenú. diff --git a/data/locale/ca.yaml b/data/locale/ca.yaml index cd5afa9..5eb3d81 100644 --- a/data/locale/ca.yaml +++ b/data/locale/ca.yaml @@ -23,7 +23,6 @@ input: scaling_overscan: "Escalat overscan" scaling_integer: "Escalat enter" press_again_exit: "Prem una altra volta per eixir" - paused: "Pausa" editor_on: "Editor ON" editor_off: "Editor OFF" editor_save_error: "Editor: error guardant el mapa" diff --git a/data/locale/en.yaml b/data/locale/en.yaml index fcea27f..575f5cf 100644 --- a/data/locale/en.yaml +++ b/data/locale/en.yaml @@ -23,7 +23,6 @@ input: scaling_overscan: "Scaling overscan" scaling_integer: "Scaling integer" press_again_exit: "Press again to exit" - paused: "Paused" editor_on: "Editor ON" editor_off: "Editor OFF" editor_save_error: "Editor: map save failed" diff --git a/data/scenes/game/game.yaml b/data/scenes/game/game.yaml index d2ca56c..3c2c38a 100644 --- a/data/scenes/game/game.yaml +++ b/data/scenes/game/game.yaml @@ -1,6 +1,6 @@ # Configuració de la GameScene: timings i corbes de la FSM de sala # (ROOM_INTRO i ROOM_OUTRO). Tots els valors són ms i tota la geometria -# i font del text es reutilitzen del tema UI (data/config/ui.yaml > pause + +# i font del text es reutilitzen del tema UI (data/config/ui.yaml > # notification). Si manca el fitxer o alguna clau, GameScene cau als # fallbacks compilats; veure `readSceneConfig` a game_scene.cpp. diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 2bb8726..3c4debe 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -72,7 +72,7 @@ class Screen { // Alpha-blend sobre el canvas: `alpha=0` no fa res, `alpha=255` equival // a fillRect. El color entra com a ARGB little-endian; `alpha` és el // factor de mescla amb el que ja hi ha al canvas. Pensat per a overlays - // (menú, pauses) que volen veure's a través el joc atenuat. + // (menú de servei) que volen veure's a través el joc atenuat. void blendRect(int x, int y, int w, int h, std::uint32_t argb, std::uint8_t alpha); // Hook invocat al principi de `present()`, abans de pujar els píxels al // backend. Serveix per a pintar overlays que han de quedar per damunt diff --git a/source/core/ui/ui_config.cpp b/source/core/ui/ui_config.cpp index 1fee001..4067a44 100644 --- a/source/core/ui/ui_config.cpp +++ b/source/core/ui/ui_config.cpp @@ -101,10 +101,6 @@ UiConfig::UiConfig() hud_shake_ms_(Defaults::UI::HUD_SHAKE_MS), hud_blink_cycle_ms_(Defaults::UI::HUD_BLINK_CYCLE_MS), hud_blink_visible_ratio_(Defaults::UI::HUD_BLINK_VISIBLE_RATIO), - pause_enter_ms_(Defaults::UI::PAUSE_ENTER_MS), - pause_exit_ms_(Defaults::UI::PAUSE_EXIT_MS), - pause_enter_curve_(curveByName(Defaults::UI::PAUSE_ENTER_CURVE)), - pause_exit_curve_(curveByName(Defaults::UI::PAUSE_EXIT_CURVE)), title_duration_ms_(Defaults::UI::Title::DURATION_MS), title_bg_color_(Defaults::UI::Title::BG_COLOR), title_text_color_(Defaults::UI::Title::TEXT_COLOR), @@ -273,14 +269,6 @@ void UiConfig::load(const std::string& file_path) { readField(h, "blink_visible_ratio", hud_blink_visible_ratio_); } - if (yaml.contains("pause")) { - const auto& p = yaml["pause"]; - readField(p, "enter_ms", pause_enter_ms_); - readField(p, "exit_ms", pause_exit_ms_); - readCurve(p, "enter_curve", pause_enter_curve_); - readCurve(p, "exit_curve", pause_exit_curve_); - } - if (yaml.contains("sounds")) { const auto& s = yaml["sounds"]; readField(s, "menu_select", menu_select_sound_); diff --git a/source/core/ui/ui_config.hpp b/source/core/ui/ui_config.hpp index f2e3029..d4a0bc0 100644 --- a/source/core/ui/ui_config.hpp +++ b/source/core/ui/ui_config.hpp @@ -91,8 +91,6 @@ class UiConfig { [[nodiscard]] auto hudShakeMs() const -> int { return hud_shake_ms_; } [[nodiscard]] auto hudBlinkCycleMs() const -> int { return hud_blink_cycle_ms_; } [[nodiscard]] auto hudBlinkVisibleRatio() const -> float { return hud_blink_visible_ratio_; } - [[nodiscard]] auto pauseEnterMs() const -> int { return pause_enter_ms_; } - [[nodiscard]] auto pauseExitMs() const -> int { return pause_exit_ms_; } // Escena TITLE (placeholder visual fins que tinguem artwork). struct TitleHeatHaze { @@ -171,11 +169,6 @@ class UiConfig { [[nodiscard]] auto logoTimeline() const -> const LogoTimeline& { return logo_timeline_; } - // Corbes d'easing triades al YAML. Si el nom no és conegut, s'usa - // Easing::linear com a fallback. - [[nodiscard]] auto pauseEnterCurve() const -> CurveFn { return pause_enter_curve_; } - [[nodiscard]] auto pauseExitCurve() const -> CurveFn { return pause_exit_curve_; } - // Resol un nom de corba a la seua funció. Pública per permetre a // futurs camps d'UI triar corbes pel mateix mecanisme (ex.: HUD // entry, notifications slide...). Si el nom no està registrat, @@ -242,10 +235,6 @@ class UiConfig { int hud_shake_ms_; int hud_blink_cycle_ms_; float hud_blink_visible_ratio_; - int pause_enter_ms_; - int pause_exit_ms_; - CurveFn pause_enter_curve_; - CurveFn pause_exit_curve_; int title_duration_ms_; Uint8 title_bg_color_; diff --git a/source/game/scenes/game_scene.cpp b/source/game/scenes/game_scene.cpp index ffacac8..fe85cdf 100644 --- a/source/game/scenes/game_scene.cpp +++ b/source/game/scenes/game_scene.cpp @@ -484,16 +484,8 @@ GameScene::GameScene(Config config) // al Resource::Cache (preload al Director), per tant la primera // crida a playMusic és immediata. - // Font de l'overlay de pausa: reutilitzem la Surface ja cachejada al - // Director (PLACEHOLDER_NAME + ".gif"). Text només parseja el .fnt a - // l'arrencada de l'escena, un sol cop. - const std::string PAUSE_FONT_KEY = UiConfig::get().placeholderFont().name + ".gif"; - auto pause_surface = Resource::Cache::get().getSurface(PAUSE_FONT_KEY); - pause_font_ = std::make_shared(pause_surface, UiConfig::get().placeholderFont().fnt); - pause_font_->setDefaultKerning(UiConfig::get().placeholderFont().kerning); - - // Font del rètol de transició de sala. Mateixa convenció que la pausa - // (Surface preloaded pel Director, només construïm el `Text` ací). + // Font del rètol de transició de sala. Reutilitzem la Surface ja + // cachejada al Director; només construïm el `Text` ací. const std::string ROOM_TEXT_FONT_KEY = UiConfig::get().roomTextFont().name + ".gif"; auto room_text_surface = Resource::Cache::get().getSurface(ROOM_TEXT_FONT_KEY); room_text_font_ = std::make_shared(room_text_surface, UiConfig::get().roomTextFont().fnt); @@ -1413,81 +1405,6 @@ void GameScene::spawnWhip(const WhipSpawnPayload& payload) { entity_manager_.add(std::move(whip)); } -void GameScene::handlePauseInput() { -#ifdef _DEBUG - // Mutex amb l'editor: si està actiu, ignorem la tecla de pausa. - if (editor_.active()) { return; } -#endif - const SDL_Scancode PAUSE_SC = KeyConfig::get().scancode("pause"); - for (const auto& event : EventBuffer::events) { - const bool KEY_HIT = (event.type == SDL_EVENT_KEY_DOWN && PAUSE_SC != SDL_SCANCODE_UNKNOWN && event.key.scancode == PAUSE_SC); - if (!KEY_HIT) { continue; } - - // Determinem cap a quin estat anem. Si estem quiets (IDLE o - // PAUSED) arranquem la transició contrària. Si estem en marxa - // (ENTERING o EXITING) invertim: la `scale` actual es manté com - // a `from_scale` nou i la durada es recalcula proporcional a la - // distància restant — així mai es produeix un salt de velocitat. - const bool GOING_TO_PAUSE = (pause_.state == PauseState::IDLE || pause_.state == PauseState::EXITING); - - // Reprenem l'stream ABANS de començar a pujar el volum: quan - // venim de PAUSED l'àudio està aturat de debò (ho fem al final - // d'ENTERING, veure updatePauseTransition); reprenem just al - // moment de començar EXITING per no perdre el primer frame - // d'stream. A les inversions mid-flight (ENTERING → EXITING - // sense tocar PAUSED) l'stream no s'ha aturat mai, així que no - // cal reprendre. - if (!GOING_TO_PAUSE && pause_.state == PauseState::PAUSED) { - Audio::get()->resumeMusic(); - } - - pause_.from_scale = pause_.scale; - pause_.to_scale = GOING_TO_PAUSE ? 0.0F : 1.0F; - const int TARGET_MS = GOING_TO_PAUSE ? UiConfig::get().pauseEnterMs() : UiConfig::get().pauseExitMs(); - const float DISTANCE = std::fabs(pause_.to_scale - pause_.from_scale); - pause_.duration_ms = std::max(1, static_cast(static_cast(TARGET_MS) * DISTANCE)); - pause_.elapsed_ms = 0; - pause_.curve = GOING_TO_PAUSE ? UiConfig::get().pauseEnterCurve() : UiConfig::get().pauseExitCurve(); - pause_.state = GOING_TO_PAUSE ? PauseState::ENTERING : PauseState::EXITING; - - Log::info("PAUSE", "{} from_scale={} duration_ms={}", GOING_TO_PAUSE ? "entering" : "exiting", pause_.from_scale, pause_.duration_ms); - } -} - -void GameScene::updatePauseTransition(int delta_ms) { - if (pause_.state != PauseState::ENTERING && pause_.state != PauseState::EXITING) { return; } - - pause_.elapsed_ms += delta_ms; - bool just_reached_pause = false; - if (pause_.elapsed_ms >= pause_.duration_ms) { - // Transició completa: enganxem al valor objectiu exacte i - // promocionem l'estat al terminal corresponent. - pause_.scale = pause_.to_scale; - const PauseState NEXT = (pause_.to_scale == 0.0F) ? PauseState::PAUSED : PauseState::IDLE; - just_reached_pause = (NEXT == PauseState::PAUSED); - pause_.state = NEXT; - } else { - const float T = static_cast(pause_.elapsed_ms) / static_cast(pause_.duration_ms); - const auto CURVE = (pause_.curve != nullptr) ? pause_.curve : &Easing::linear; - pause_.scale = std::lerp(pause_.from_scale, pause_.to_scale, CURVE(T)); - } - - // Fade del volum de música durant la transició. La base és el que - // l'usuari ha configurat a Options; multipliquem per la `scale` per - // obtenir el volum efectiu aquest frame. - const float BASE_VOLUME = Options::audio().music.volume; - Audio::get()->setMusicVolume(BASE_VOLUME * pause_.scale); - - // En arribar a PAUSED aturem l'stream: així quan despausem la música - // tornarà des d'on s'ha quedat, no des d'on hauria anat a parar - // durant el temps que el joc ha estat en pausa. El `resumeMusic` es - // fa a `handlePauseInput` al començar l'EXITING, perquè la música - // sone ja mentre el volum puja des de 0. - if (just_reached_pause) { - Audio::get()->pauseMusic(); - } -} - #ifdef _DEBUG namespace { auto detectEditorToggle() -> bool { @@ -1523,33 +1440,19 @@ namespace { #endif void GameScene::update(int delta_ms) { - handlePauseInput(); - - // Congelació instantània mentre el menú de servei està obert. A - // diferència de la pausa de gameplay (que és un dial amb easing i - // fade de música), aquesta és binària: el món no avança gens i la - // música no es toca. També posem en pausa el dial de la pausa - // regular si estava a mig camí, perquè no continui mentre l'usuari - // navega el menú. + // Congelació instantània mentre el menú de servei està obert: el + // món no avança gens. La música segueix sonant perquè el menú serveix + // entre altres coses per calibrar les opcions d'àudio. const bool MENU_FROZEN = ServiceMenu::get().isOpen(); - if (!MENU_FROZEN) { - updatePauseTransition(delta_ms); - } - // Transició de sala: viu en temps real (no escalada per la pausa) - // perquè és UI. Avança avans del bloc de món perquè quan PLAYING + // Transició de sala i sub-FSM de game over: viuen en temps real + // perquè són UI. Avancen abans del bloc de món perquè quan PLAYING // arrenque ja sigui efectiu en el mateix frame. updateRoomTransition(delta_ms); - - // Sub-FSM de game over (CONTINUE? + GAME OVER + fade-to-LOGO). - // També en temps real: el countdown de CONTINUE? no es congela - // amb la pausa de gameplay. La detecció de "tots fora de partida" - // s'arma dins quan estem a PLAYING. updateGameOverFlow(delta_ms); #ifdef _DEBUG - // Toggle de l'editor: només si no hi ha cap transició de pausa ni - // pausa consolidada. L'editor mateix no consumeix la tecla — la + // Toggle de l'editor. L'editor mateix no consumeix la tecla — la // llegim ací per decidir la coexistència. Tant a l'entrada com a la // sortida fem `loadRoom` complet per partir sempre del YAML del // disc: les entitats tornen a la posició inicial (momies, sarcs), @@ -1557,7 +1460,7 @@ void GameScene::update(int delta_ms) { // l'editor sempre veu l'estat-base de la sala (no el d'una partida // a meitat) i el joc, en sortir, arrenca fresc amb les edicions ja // persistides al YAML. - if (pause_.state == PauseState::IDLE && detectEditorToggle()) { + if (!MENU_FROZEN && detectEditorToggle()) { const bool WAS_ACTIVE = editor_.active(); editor_.toggle(tilemap_, entity_manager_); const bool NOW_ACTIVE = editor_.active(); @@ -1575,10 +1478,10 @@ void GameScene::update(int delta_ms) { } } - // Salts debug entre sales (`[` / `]`). Mútuament excloents amb la - // pausa i amb l'editor: si qualsevol està actiu, ignorem la tecla - // perquè el salt recarrega entitats i invalidaria l'estat editat. - if (pause_.state == PauseState::IDLE && !editor_.active()) { + // Salts debug entre sales (`[` / `]`). Mútuament excloents amb el + // menú de servei i amb l'editor: si qualsevol està actiu, ignorem la + // tecla perquè el salt recarrega entitats i invalidaria l'estat editat. + if (!MENU_FROZEN && !editor_.active()) { const int DELTA = detectRoomJump(); if (DELTA != 0) { auto& mgr = Levels::LevelManager::get(); @@ -1592,7 +1495,7 @@ void GameScene::update(int delta_ms) { // pintat/sarcs durant proves de progressió. La resta del flux // (creuar → player_exited → level_complete → OUTRO) es manté. // Mateixos gates que el salt entre sales. - if (pause_.state == PauseState::IDLE && !editor_.active() && detectOpenDoor()) { + if (!MENU_FROZEN && !editor_.active() && detectOpenDoor()) { Log::info("DEBUG", "força obertura de la porta"); entity_manager_.forceOpenDoor(); } @@ -1601,33 +1504,31 @@ void GameScene::update(int delta_ms) { // Join in progress (regla 1): un slot DISABLED pot entrar a partida // pulsant START durant PLAYING. Es processa abans del bloc de món // per que el spawn aeri ja sigui efectiu en aquest mateix frame. - // Gateat per pausa/menú/editor: no es vol que un START accidental - // mentre l'usuari navega per un menú trigueri un join. + // Gateat per menú/editor: no es vol que un START accidental mentre + // l'usuari navega per un menú trigueri un join. #ifdef _DEBUG const bool EDITOR_OPEN = editor_.active(); #else constexpr bool EDITOR_OPEN = false; #endif - if (pause_.state == PauseState::IDLE && !MENU_FROZEN && !EDITOR_OPEN) { + if (!MENU_FROZEN && !EDITOR_OPEN) { handleJoinInput(); } GlobalInputs::update(delta_ms); if (GlobalInputs::wantsQuit()) { wants_quit_ = true; } - // El món avança amb `delta_ms * pause_.scale`: scale=1 corre a velocitat - // real, scale=0 el congela. Quan l'editor de debug està actiu també - // es salta completament (no l'escalem, el saltem). Notifier, - // RenderInfo i HUD reben el delta real, per això viuen fora d'aquest - // bloc i no es ralenteixen amb el dial de pausa. + // El bloc de món no s'executa si el menú de servei o l'editor de + // debug estan oberts: tots dos congelen el joc instantàniament. + // Notifier, RenderInfo i HUD viuen fora d'aquest bloc perquè s'han + // de seguir actualitzant en aquests casos. #ifdef _DEBUG const bool EDITOR_FROZEN = editor_.active(); #else constexpr bool EDITOR_FROZEN = false; #endif - const int SCALED_DELTA_MS = static_cast(static_cast(delta_ms) * pause_.scale); - if (!EDITOR_FROZEN && !MENU_FROZEN && SCALED_DELTA_MS > 0) { - const float DT = static_cast(SCALED_DELTA_MS) / 1000.0F; + if (!EDITOR_FROZEN && !MENU_FROZEN && delta_ms > 0) { + const float DT = static_cast(delta_ms) / 1000.0F; // Pipeline de moviment en tres passes per poder intercalar la // resolució de contactes jugador↔jugador entre input i posició: @@ -1791,36 +1692,6 @@ void GameScene::render() { editor_.render(tilemap_, entity_manager_); #endif - // Overlay de pausa: text amb stroke blanc (índex 255) centrat amb X - // depenent de l'estat del dial. Entra lliscant des de l'esquerra - // (ENTERING), es queda al centre (PAUSED) i surt cap a la dreta - // (EXITING). La X es deriva directament de `pause_.scale`, que ja - // porta la corba aplicada — així text i món frenen alhora. - if (pause_.state != PauseState::IDLE && pause_font_) { - constexpr Uint8 OUTLINE_WHITE = 255; - constexpr Uint8 STROKE_DIST = 1; - constexpr int PAUSE_KERNING = 0; - const std::string TEXT = Locale::get().text("input.paused"); - const int TEXT_WIDTH = pause_font_->length(TEXT, PAUSE_KERNING); - const int OFF_LEFT = -TEXT_WIDTH; - const int OFF_RIGHT = GameCanvas::WIDTH + TEXT_WIDTH; - int x = GameCanvas::CENTER_X; - if (pause_.state == PauseState::ENTERING) { - x = Easing::lerpInt(OFF_LEFT, GameCanvas::CENTER_X, 1.0F - pause_.scale); - } else if (pause_.state == PauseState::EXITING) { - x = Easing::lerpInt(GameCanvas::CENTER_X, OFF_RIGHT, pause_.scale); - } - const int Y = GameCanvas::CENTER_Y - (pause_font_->getLineHeight() / 2); - pause_font_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG | Text::STROKE4_FLAG, - x, - Y, - TEXT, - PAUSE_KERNING, - UiConfig::get().notificationText(), - STROKE_DIST, - OUTLINE_WHITE); - } - Notifier::get().render(); RenderInfo::get().render(); Screen::get().present(); diff --git a/source/game/scenes/game_scene.hpp b/source/game/scenes/game_scene.hpp index ab9b496..9c1f333 100644 --- a/source/game/scenes/game_scene.hpp +++ b/source/game/scenes/game_scene.hpp @@ -55,24 +55,11 @@ class GameScene : public Scene { void setState(RoomFsm::State new_state); // Avança la transició activa via `RoomFsm::advance`. S'executa cada - // frame amb delta real (no escalat per la pausa) perquè la transició - // viu en temps de UI. Si l'estat retornat és diferent de l'actual, - // crida `setState` (que reseteja la `Transition`). + // frame amb delta real perquè la transició viu en temps de UI. Si + // l'estat retornat és diferent de l'actual, crida `setState` (que + // reseteja la `Transition`). void updateRoomTransition(int delta_ms); - // Consumeix events d'aquest frame (F11 del KeyConfig "pause") per - // disparar les transicions de pausa. El mando ja no participa: el - // botó START és ara una acció remapeable per dispositiu i el menú - // de servei fa de pausa quan cal. 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); - // Spawna un Dust transitori centrat a (`feet_x_center`, `feet_y`). // Cridat per la subscripció del bus a `player_jumped` / // `player_landed` per pintar el polvet de despegue / aterratge. @@ -239,41 +226,11 @@ class GameScene : public Scene { // 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_; - // Font del rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO). - // Distinta de `pause_font_` perquè el rètol de fase té estètica - // pròpia (CaesarDressing per defecte, configurable via - // `data/config/ui.yaml > fonts.room_text`). La pausa segueix amb la - // placeholder. + // Té estètica pròpia (CaesarDressing per defecte, configurable via + // `data/config/ui.yaml > fonts.room_text`). std::shared_ptr room_text_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_; - // Configuració de la FSM de sala (intro/outro). Carregada al ctor des // de `data/scenes/game/game.yaml`; valors per defecte si manca el YAML. RoomFsm::Config transition_config_{}; @@ -445,11 +402,10 @@ class GameScene : public Scene { #endif #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 modal del tilemap. Mútuament excloent amb el menú de servei: + // si el menú està obert, la tecla de toggle de l'editor s'ignora. + // Quan `editor_.active()` és true, saltem entitats i jugador (update + // i render) i deixem el tilemap visible perquè es pugui editar. Editor editor_; #endif }; diff --git a/source/utils/defaults.hpp b/source/utils/defaults.hpp index f07f7f2..a81fee9 100644 --- a/source/utils/defaults.hpp +++ b/source/utils/defaults.hpp @@ -252,17 +252,6 @@ namespace Defaults { constexpr int HUD_BLINK_CYCLE_MS = 1000; constexpr float HUD_BLINK_VISIBLE_RATIO = 0.8F; - // Pausa graduada de la GameScene: el món no para d'un colp, es - // frena amb una corba i torna a arrancar amb una altra. Els noms - // de corba han de coincidir amb els registrats a - // UiConfig::curveByName (linear / outQuad / inQuad / inOutQuad / - // outCubic / inCubic). Si un nom no es reconeix, es cau a - // Easing::linear. - constexpr int PAUSE_ENTER_MS = 400; - constexpr int PAUSE_EXIT_MS = 250; - constexpr const char* PAUSE_ENTER_CURVE = "outCubic"; - constexpr const char* PAUSE_EXIT_CURVE = "inCubic"; - // Sons del menú de servei. SELECT acompanya navegació (amunt/avall) // i back; ACCEPT acompanya modificació d'opció (esq/dret/retorn). // Els fitxers viuen a `data/audio/sounds/`; només es referencia el nom.