From 5956d874c3f4d95c2b884a3361c177f4ad7b5315 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 16 Apr 2026 20:14:35 +0200 Subject: [PATCH] animacio de tancar el menu --- source/core/rendering/menu.cpp | 42 +++++++++++++++++++++++++++---- source/core/rendering/menu.hpp | 6 ++++- source/core/rendering/overlay.cpp | 4 +-- source/core/system/director.cpp | 13 ++++++---- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/source/core/rendering/menu.cpp b/source/core/rendering/menu.cpp index fbaee65..d9e5f14 100644 --- a/source/core/rendering/menu.cpp +++ b/source/core/rendering/menu.cpp @@ -44,6 +44,7 @@ namespace Menu { // --- Animació --- static constexpr float OPEN_SPEED = 8.0F; // 1.0 / 0.125s + static constexpr float CLOSE_SPEED = 10.0F; // 1.0 / 0.1s (una mica més ràpida que l'obertura) static constexpr float HEIGHT_RATE = 12.0F; // smoothing exponencial de l'alçada (~150 ms al 90%) // --- Items --- @@ -92,6 +93,7 @@ namespace Menu { static float animated_h_{0.0F}; // alçada actual animada (smoothing cap al target visible) static Uint32 last_ticks_{0}; static SDL_Scancode* capturing_{nullptr}; // != null → esperant tecla per assignar + static bool closing_{false}; // true mentre l'animació de tancament és en curs // --- Transició entre pàgines --- static constexpr float TRANSITION_SPEED = 5.5F; // ~180 ms @@ -354,36 +356,56 @@ namespace Menu { font_ = std::make_unique("fonts/8bithud.fnt", "fonts/8bithud.gif"); stack_.clear(); open_anim_ = 0.0F; + closing_ = false; last_ticks_ = SDL_GetTicks(); } void destroy() { font_.reset(); stack_.clear(); + closing_ = false; } + // "Actiu": accepta input. Durant l'animació de tancament la pila encara + // té pàgines però ja no ha de processar tecles. auto isOpen() -> bool { + return !stack_.empty() && !closing_; + } + + // "Visible": encara hi ha caixa per pintar (incloent close animation). + auto isVisible() -> bool { return !stack_.empty(); } void toggle() { + if (closing_ && !stack_.empty()) { + // Cancel·la el tancament en curs — continua l'animació cap a "obert" + // des del valor actual d'open_anim_. + closing_ = false; + last_ticks_ = SDL_GetTicks(); + return; + } if (isOpen()) { close(); } else { stack_.push_back(buildRoot()); open_anim_ = 0.0F; + closing_ = false; animated_h_ = static_cast(boxHeight(stack_.back())); last_ticks_ = SDL_GetTicks(); } } + // close() no buida la pila immediatament: marca closing_ i deixa que + // render() faça decréixer open_anim_ fins a 0. En aquell moment es neteja + // l'estat. Si es crida estant ja tancat o tancant-se, no-op. void close() { - stack_.clear(); - open_anim_ = 0.0F; - animated_h_ = 0.0F; + if (stack_.empty() || closing_) return; + closing_ = true; capturing_ = nullptr; transition_active_ = false; transition_progress_ = 1.0F; + last_ticks_ = SDL_GetTicks(); } auto isCapturing() -> bool { @@ -556,13 +578,23 @@ namespace Menu { } void render(Uint32* pixel_data) { - if (!isOpen() || !font_ || !pixel_data) return; + if (!isVisible() || !font_ || !pixel_data) return; // Delta time Uint32 now = SDL_GetTicks(); float dt = static_cast(now - last_ticks_) / 1000.0F; last_ticks_ = now; - if (open_anim_ < 1.0F) { + if (closing_) { + open_anim_ -= CLOSE_SPEED * dt; + if (open_anim_ <= 0.0F) { + // Animació de tancament completada — buida l'estat de veritat. + open_anim_ = 0.0F; + stack_.clear(); + animated_h_ = 0.0F; + closing_ = false; + return; + } + } else if (open_anim_ < 1.0F) { open_anim_ += OPEN_SPEED * dt; if (open_anim_ > 1.0F) open_anim_ = 1.0F; } diff --git a/source/core/rendering/menu.hpp b/source/core/rendering/menu.hpp index 3dd2bfb..810b3d6 100644 --- a/source/core/rendering/menu.hpp +++ b/source/core/rendering/menu.hpp @@ -6,11 +6,15 @@ namespace Menu { void init(); void destroy(); + // "Actiu": el menú accepta input. Fals durant l'animació de tancament. [[nodiscard]] auto isOpen() -> bool; + // "Visible": hi ha una caixa pintada (incloent l'animació de tancament). + // Overlay la usa per a decidir si cridar render(). + [[nodiscard]] auto isVisible() -> bool; void toggle(); void close(); - // Pinta el menú sobre el buffer ARGB — cridat des d'Overlay::render si està obert + // Pinta el menú sobre el buffer ARGB — cridat des d'Overlay::render si està visible void render(Uint32* pixel_data); // Gestió d'input — cridat des del Director en KEY_DOWN diff --git a/source/core/rendering/overlay.cpp b/source/core/rendering/overlay.cpp index e83d4a9..db8a716 100644 --- a/source/core/rendering/overlay.cpp +++ b/source/core/rendering/overlay.cpp @@ -361,8 +361,8 @@ namespace Overlay { std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }), notifications_.end()); - // Menú flotant per damunt de tot - if (Menu::isOpen()) { + // Menú flotant per damunt de tot (isVisible inclou l'animació de tancament) + if (Menu::isVisible()) { Menu::render(pixel_data); } } diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index c364d81..5e614ab 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -286,11 +286,6 @@ void Director::handleEvent(const SDL_Event& event) { Gamepad::handleEvent(event); return; } - // Salta els crèdits amb qualsevol tecla; no deixem que arribi al joc - if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat && Overlay::creditsActive()) { - Overlay::cancelCredits(); - return; - } // Empassar-se el KEY_UP de qualsevol tecla que el menú va consumir en KEY_DOWN if (event.type == SDL_EVENT_KEY_UP && event.key.scancode >= 0 && event.key.scancode < SDL_SCANCODE_COUNT && menu_keys_held_[event.key.scancode]) { @@ -340,6 +335,14 @@ void Director::handleEvent(const SDL_Event& event) { if (Menu::isOpen() && event.type == SDL_EVENT_KEY_UP) { return; // no deixem passar KEY_UP al joc tampoc } + // Salta els crèdits amb qualsevol tecla que arribe al joc. Es fa DESPRÉS + // del toggle del menú/pausa i del handling del menú obert — així F12 i + // SELECT (gamepad) obrin el menú sense cancel·lar els crèdits, i la + // navegació per dins del menú tampoc els anul·la. + if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat && Overlay::creditsActive()) { + Overlay::cancelCredits(); + return; + } // Allibera el bloqueig d'ESC quan l'usuari la deixa anar if (event.type == SDL_EVENT_KEY_UP && event.key.scancode == SDL_SCANCODE_ESCAPE && esc_swallow_until_release_) { esc_swallow_until_release_ = false;