feat(demo): transició títol→demo amb dive de càmera + cortinilla negra (substitueix el fundido)

This commit is contained in:
2026-05-29 10:03:17 +02:00
parent 068f42782b
commit 2f6d6c405f
9 changed files with 204 additions and 145 deletions
+71
View File
@@ -0,0 +1,71 @@
// curtain.cpp - Implementació de la cortinilla negra
// © 2026 JailDesigner
#include "core/graphics/curtain.hpp"
#include <algorithm>
#include "core/defaults/game.hpp"
#include "core/math/easing.hpp"
namespace Graphics {
namespace {
constexpr float SCREEN_H = static_cast<float>(Defaults::Game::HEIGHT);
constexpr float SCREEN_W = static_cast<float>(Defaults::Game::WIDTH);
} // namespace
Curtain::Curtain(Rendering::Renderer* renderer)
: renderer_(renderer) {}
void Curtain::cover(float duration) {
// Caire superior de -H (fora, a dalt) fins a 0 (tela tapant tota la pantalla).
from_ = -SCREEN_H;
to_ = 0.0F;
duration_ = duration;
elapsed_ = 0.0F;
active_ = true;
}
void Curtain::reveal(float duration) {
// Caire superior de 0 (tapant) fins a +H (tela fora per baix).
from_ = 0.0F;
to_ = SCREEN_H;
duration_ = duration;
elapsed_ = 0.0F;
active_ = true;
}
void Curtain::update(float delta_time) {
if (!active_) {
return;
}
elapsed_ += delta_time;
}
auto Curtain::topY() const -> float {
if (duration_ <= 0.0F) {
return to_;
}
const float T = std::clamp(elapsed_ / duration_, 0.0F, 1.0F);
// Ease-in: la tela "cau" accelerant, com per gravetat.
return Easing::lerp(from_, to_, Easing::easeInQuad(T));
}
auto Curtain::isDone() const -> bool {
return !active_ || elapsed_ >= duration_;
}
void Curtain::draw() const {
if (!active_) {
return;
}
const float TOP = topY();
// Si la tela ja ha sortit completament per baix, no hi ha res a pintar.
if (TOP >= SCREEN_H) {
return;
}
renderer_->pushRect(0.0F, TOP, SCREEN_W, SCREEN_H, 0.0F, 0.0F, 0.0F, 1.0F);
}
} // namespace Graphics
+48
View File
@@ -0,0 +1,48 @@
// curtain.hpp - Cortinilla negra per a transicions d'escena
// © 2026 JailDesigner
//
// Tela negra a pantalla completa que es mou SEMPRE cap avall:
// - cover(): cau des de dalt fins a tapar-ho tot (queda negre).
// - reveal(): segueix caient i surt per baix, deixant veure l'escena.
// Una escena la posseeix, l'actualitza cada frame i la dibuixa l'ÚLTIM (per
// damunt de tot). En repòs (no arrencada o reveal acabada) el draw() és no-op.
#pragma once
#include "core/rendering/render_context.hpp"
namespace Graphics {
class Curtain {
public:
explicit Curtain(Rendering::Renderer* renderer);
// Tela que cau des de dalt fins a tapar tota la pantalla en 'duration' s.
void cover(float duration);
// Tela que segueix caient i surt per baix (destapa) en 'duration' s.
void reveal(float duration);
// Avança el temporitzador intern.
void update(float delta_time);
// Dibuixa la tela negra a la seva posició vertical actual. No-op si no
// queda res visible.
void draw() const;
// Cert quan el moviment actual ha acabat (o no s'ha arrencat mai).
[[nodiscard]] auto isDone() const -> bool;
private:
// Posició actual del caire superior de la tela (píxels lògics).
[[nodiscard]] auto topY() const -> float;
Rendering::Renderer* renderer_;
float from_{0.0F};
float to_{0.0F};
float duration_{0.0F};
float elapsed_{0.0F};
bool active_{false};
};
} // namespace Graphics
-62
View File
@@ -1,62 +0,0 @@
// screen_fade.cpp - Implementació de la fosa a/desde negre
// © 2026 JailDesigner
#include "core/graphics/screen_fade.hpp"
#include <algorithm>
#include <cmath>
#include "core/defaults/game.hpp"
namespace Graphics {
ScreenFade::ScreenFade(Rendering::Renderer* renderer)
: renderer_(renderer) {}
void ScreenFade::start(float from, float to, float duration) {
from_ = from;
to_ = to;
duration_ = duration;
elapsed_ = 0.0F;
active_ = true;
}
void ScreenFade::update(float delta_time) {
if (!active_) {
return;
}
elapsed_ += delta_time;
}
auto ScreenFade::alpha() const -> float {
if (!active_) {
return 0.0F;
}
if (duration_ <= 0.0F) {
return to_;
}
const float T = std::clamp(elapsed_ / duration_, 0.0F, 1.0F);
return std::lerp(from_, to_, T);
}
auto ScreenFade::isDone() const -> bool {
return !active_ || elapsed_ >= duration_;
}
void ScreenFade::draw() const {
const float A = alpha();
if (A <= 0.0F) {
return;
}
renderer_->pushRect(
0.0F,
0.0F,
static_cast<float>(Defaults::Game::WIDTH),
static_cast<float>(Defaults::Game::HEIGHT),
0.0F,
0.0F,
0.0F,
A);
}
} // namespace Graphics
-43
View File
@@ -1,43 +0,0 @@
// screen_fade.hpp - Fosa a/desde negre per a transicions d'escena
// © 2026 JailDesigner
//
// Rect negre a pantalla completa amb l'alpha animat linealment. L'escena que el
// posseeix l'actualitza cada frame i el dibuixa l'ÚLTIM (per damunt de tot). En
// repòs (default-construït o fosa acabada amb alpha 0) el draw() és un no-op.
#pragma once
#include "core/rendering/render_context.hpp"
namespace Graphics {
class ScreenFade {
public:
explicit ScreenFade(Rendering::Renderer* renderer);
// Arrenca una fosa lineal d'alpha 'from' a 'to' en 'duration' segons.
void start(float from, float to, float duration);
// Avança el temporitzador intern.
void update(float delta_time);
// Dibuixa el rect negre a pantalla completa amb l'alpha actual.
// No fa res si l'alpha és ~0 (estalvia el pushRect).
void draw() const;
// Cert quan la fosa ha acabat (o no s'ha arrencat mai).
[[nodiscard]] auto isDone() const -> bool;
// Alpha actual ∈ [0, 1].
[[nodiscard]] auto alpha() const -> float;
private:
Rendering::Renderer* renderer_;
float from_{0.0F};
float to_{0.0F};
float duration_{0.0F};
float elapsed_{0.0F};
bool active_{false};
};
} // namespace Graphics