animacio de tancar el menu
This commit is contained in:
@@ -44,6 +44,7 @@ namespace Menu {
|
|||||||
|
|
||||||
// --- Animació ---
|
// --- Animació ---
|
||||||
static constexpr float OPEN_SPEED = 8.0F; // 1.0 / 0.125s
|
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%)
|
static constexpr float HEIGHT_RATE = 12.0F; // smoothing exponencial de l'alçada (~150 ms al 90%)
|
||||||
|
|
||||||
// --- Items ---
|
// --- Items ---
|
||||||
@@ -92,6 +93,7 @@ namespace Menu {
|
|||||||
static float animated_h_{0.0F}; // alçada actual animada (smoothing cap al target visible)
|
static float animated_h_{0.0F}; // alçada actual animada (smoothing cap al target visible)
|
||||||
static Uint32 last_ticks_{0};
|
static Uint32 last_ticks_{0};
|
||||||
static SDL_Scancode* capturing_{nullptr}; // != null → esperant tecla per assignar
|
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 ---
|
// --- Transició entre pàgines ---
|
||||||
static constexpr float TRANSITION_SPEED = 5.5F; // ~180 ms
|
static constexpr float TRANSITION_SPEED = 5.5F; // ~180 ms
|
||||||
@@ -354,36 +356,56 @@ namespace Menu {
|
|||||||
font_ = std::make_unique<Text>("fonts/8bithud.fnt", "fonts/8bithud.gif");
|
font_ = std::make_unique<Text>("fonts/8bithud.fnt", "fonts/8bithud.gif");
|
||||||
stack_.clear();
|
stack_.clear();
|
||||||
open_anim_ = 0.0F;
|
open_anim_ = 0.0F;
|
||||||
|
closing_ = false;
|
||||||
last_ticks_ = SDL_GetTicks();
|
last_ticks_ = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
void destroy() {
|
||||||
font_.reset();
|
font_.reset();
|
||||||
stack_.clear();
|
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 {
|
auto isOpen() -> bool {
|
||||||
|
return !stack_.empty() && !closing_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Visible": encara hi ha caixa per pintar (incloent close animation).
|
||||||
|
auto isVisible() -> bool {
|
||||||
return !stack_.empty();
|
return !stack_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggle() {
|
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()) {
|
if (isOpen()) {
|
||||||
close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
stack_.push_back(buildRoot());
|
stack_.push_back(buildRoot());
|
||||||
open_anim_ = 0.0F;
|
open_anim_ = 0.0F;
|
||||||
|
closing_ = false;
|
||||||
animated_h_ = static_cast<float>(boxHeight(stack_.back()));
|
animated_h_ = static_cast<float>(boxHeight(stack_.back()));
|
||||||
last_ticks_ = SDL_GetTicks();
|
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() {
|
void close() {
|
||||||
stack_.clear();
|
if (stack_.empty() || closing_) return;
|
||||||
open_anim_ = 0.0F;
|
closing_ = true;
|
||||||
animated_h_ = 0.0F;
|
|
||||||
capturing_ = nullptr;
|
capturing_ = nullptr;
|
||||||
transition_active_ = false;
|
transition_active_ = false;
|
||||||
transition_progress_ = 1.0F;
|
transition_progress_ = 1.0F;
|
||||||
|
last_ticks_ = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto isCapturing() -> bool {
|
auto isCapturing() -> bool {
|
||||||
@@ -556,13 +578,23 @@ namespace Menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void render(Uint32* pixel_data) {
|
void render(Uint32* pixel_data) {
|
||||||
if (!isOpen() || !font_ || !pixel_data) return;
|
if (!isVisible() || !font_ || !pixel_data) return;
|
||||||
|
|
||||||
// Delta time
|
// Delta time
|
||||||
Uint32 now = SDL_GetTicks();
|
Uint32 now = SDL_GetTicks();
|
||||||
float dt = static_cast<float>(now - last_ticks_) / 1000.0F;
|
float dt = static_cast<float>(now - last_ticks_) / 1000.0F;
|
||||||
last_ticks_ = now;
|
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;
|
open_anim_ += OPEN_SPEED * dt;
|
||||||
if (open_anim_ > 1.0F) open_anim_ = 1.0F;
|
if (open_anim_ > 1.0F) open_anim_ = 1.0F;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,15 @@ namespace Menu {
|
|||||||
void init();
|
void init();
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
|
// "Actiu": el menú accepta input. Fals durant l'animació de tancament.
|
||||||
[[nodiscard]] auto isOpen() -> bool;
|
[[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 toggle();
|
||||||
void close();
|
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);
|
void render(Uint32* pixel_data);
|
||||||
|
|
||||||
// Gestió d'input — cridat des del Director en KEY_DOWN
|
// Gestió d'input — cridat des del Director en KEY_DOWN
|
||||||
|
|||||||
@@ -361,8 +361,8 @@ namespace Overlay {
|
|||||||
std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }),
|
std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }),
|
||||||
notifications_.end());
|
notifications_.end());
|
||||||
|
|
||||||
// Menú flotant per damunt de tot
|
// Menú flotant per damunt de tot (isVisible inclou l'animació de tancament)
|
||||||
if (Menu::isOpen()) {
|
if (Menu::isVisible()) {
|
||||||
Menu::render(pixel_data);
|
Menu::render(pixel_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,11 +286,6 @@ void Director::handleEvent(const SDL_Event& event) {
|
|||||||
Gamepad::handleEvent(event);
|
Gamepad::handleEvent(event);
|
||||||
return;
|
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
|
// 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 &&
|
if (event.type == SDL_EVENT_KEY_UP && event.key.scancode >= 0 &&
|
||||||
event.key.scancode < SDL_SCANCODE_COUNT && menu_keys_held_[event.key.scancode]) {
|
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) {
|
if (Menu::isOpen() && event.type == SDL_EVENT_KEY_UP) {
|
||||||
return; // no deixem passar KEY_UP al joc tampoc
|
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
|
// 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_) {
|
if (event.type == SDL_EVENT_KEY_UP && event.key.scancode == SDL_SCANCODE_ESCAPE && esc_swallow_until_release_) {
|
||||||
esc_swallow_until_release_ = false;
|
esc_swallow_until_release_ = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user