feat(title): intro amb path Z (zoom+pivot al VP) en lloc d'offset Y
El logo i el footer ara entren simulant un moviment 3D des de l'usuari cap al VP: arrenquen grans i a la posició projectada extrema (factor d'escala SCALE_START > 1, pivot al centre de pantalla) i convergeixen a la seva mida i posició finals. Substitueix l'offset Y lineal anterior.
This commit is contained in:
@@ -128,10 +128,17 @@ namespace Defaults::Title {
|
||||
// Coreografia de la seqüència d'entrada al state MAIN.
|
||||
// Tots els elements (logo, footer, naus, press start) entren ordenadament
|
||||
// segons aquests thresholds. Vegeu title_scene.cpp/updateMainState.
|
||||
//
|
||||
// Per al logo i el footer, l'efecte simula un moviment 3D des de l'usuari
|
||||
// cap al VP: el text arrenca gran i a la posició projectada extrema (com
|
||||
// si estigués prop de la càmera, fora de pantalla) i acaba a la seva
|
||||
// posició final amb escala normal (com si hagués aterrat al VP). Pivot:
|
||||
// centre de pantalla (= projecció del VP 3D).
|
||||
namespace Sequence {
|
||||
// Offsets fora-pantalla per a l'animació d'entrada (additius a la posició final).
|
||||
constexpr float LOGO_OFFSCREEN_OFFSET_Y = -240.0F; // logo entra des de dalt
|
||||
constexpr float FOOTER_OFFSCREEN_OFFSET_Y = +160.0F; // jailgames/copyright entren des de baix
|
||||
// Factor d'escala inicial. >1 = sprite gran a l'inici (prop de l'usuari).
|
||||
// La posició inicial es deriva: pivot=centre, delta multiplicat per aquest factor.
|
||||
constexpr float LOGO_INTRO_SCALE_START = 2.5F;
|
||||
constexpr float FOOTER_INTRO_SCALE_START = 2.5F;
|
||||
|
||||
// Durades de les animacions d'entrada (segons).
|
||||
constexpr float LOGO_ENTRY_DURATION = 1.2F;
|
||||
|
||||
@@ -250,14 +250,21 @@ void TitleScene::inicialitzarJailgames() {
|
||||
void TitleScene::dibuixarPeuTitol(float spacing) const {
|
||||
namespace S = Defaults::Title::Sequence;
|
||||
|
||||
const float JAILGAMES_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_jailgames_progress_)) *
|
||||
S::FOOTER_OFFSCREEN_OFFSET_Y;
|
||||
const float COPYRIGHT_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_copyright_progress_)) *
|
||||
S::FOOTER_OFFSCREEN_OFFSET_Y;
|
||||
// Pivot al centre de pantalla (= projecció VP). Cada element s'expandeix
|
||||
// des d'aquí mentre s_factor passa de SCALE_START (gran, prop de l'usuari)
|
||||
// a 1.0 (a la mida i posició finals, "lluny" al VP).
|
||||
const float SCREEN_CENTRE_X = Defaults::Game::WIDTH / 2.0F;
|
||||
const float SCREEN_CENTRE_Y = Defaults::Game::HEIGHT / 2.0F;
|
||||
const float JAILGAMES_S = std::lerp(S::FOOTER_INTRO_SCALE_START, 1.0F, Easing::easeOutQuad(intro_jailgames_progress_));
|
||||
const float COPYRIGHT_S = std::lerp(S::FOOTER_INTRO_SCALE_START, 1.0F, Easing::easeOutQuad(intro_copyright_progress_));
|
||||
|
||||
const float JAILGAMES_RENDER_SCALE = Defaults::Title::Layout::JAILGAMES_SCALE * JAILGAMES_S;
|
||||
for (const auto& lletra : lletres_jailgames_) {
|
||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + JAILGAMES_Y_INTRO};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::JAILGAMES_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::JAILGAMES_LOGO);
|
||||
const Vec2 POS{
|
||||
.x = SCREEN_CENTRE_X + (JAILGAMES_S * (lletra.position.x - SCREEN_CENTRE_X)),
|
||||
.y = SCREEN_CENTRE_Y + (JAILGAMES_S * (lletra.position.y - SCREEN_CENTRE_Y)),
|
||||
};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, JAILGAMES_RENDER_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::JAILGAMES_LOGO);
|
||||
}
|
||||
std::string copyright = Project::COPYRIGHT;
|
||||
for (char& c : copyright) {
|
||||
@@ -265,9 +272,11 @@ void TitleScene::dibuixarPeuTitol(float spacing) const {
|
||||
c = static_cast<char>(c - 32);
|
||||
}
|
||||
}
|
||||
const float Y_COPY = (Defaults::Game::HEIGHT * Defaults::Title::Layout::COPYRIGHT1_POS) + COPYRIGHT_Y_INTRO;
|
||||
const float CENTRE_X = Defaults::Game::WIDTH / 2.0F;
|
||||
text_.renderCentered(copyright, {.x = CENTRE_X, .y = Y_COPY}, Defaults::Title::Layout::COPYRIGHT_SCALE, spacing, 1.0F, Defaults::Title::Colors::COPYRIGHT);
|
||||
const float Y_COPY_FINAL = Defaults::Game::HEIGHT * Defaults::Title::Layout::COPYRIGHT1_POS;
|
||||
const float COPY_X = SCREEN_CENTRE_X; // ja al centre
|
||||
const float COPY_Y = SCREEN_CENTRE_Y + (COPYRIGHT_S * (Y_COPY_FINAL - SCREEN_CENTRE_Y));
|
||||
const float COPY_RENDER_SCALE = Defaults::Title::Layout::COPYRIGHT_SCALE * COPYRIGHT_S;
|
||||
text_.renderCentered(copyright, {.x = COPY_X, .y = COPY_Y}, COPY_RENDER_SCALE, spacing, 1.0F, Defaults::Title::Colors::COPYRIGHT);
|
||||
}
|
||||
|
||||
auto TitleScene::isFinished() const -> bool {
|
||||
@@ -524,11 +533,13 @@ void TitleScene::draw() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Offset additiu de la intro del logo (cau des de dalt). Quan progress=1,
|
||||
// el logo està al seu lloc i aquest offset val 0 — l'oscil·lació suau
|
||||
// (updateLogoAnimation) continua treballant sobre la posició base.
|
||||
const float LOGO_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_logo_progress_)) *
|
||||
Defaults::Title::Sequence::LOGO_OFFSCREEN_OFFSET_Y;
|
||||
// Factor d'escala+posició per simular un moviment 3D des de l'usuari (prop,
|
||||
// sprite gran i posició projectada extrema) cap al VP (lluny, sprite a la
|
||||
// seva mida i posició finals). Pivot: centre de pantalla (= projecció VP).
|
||||
const float LOGO_S = std::lerp(Defaults::Title::Sequence::LOGO_INTRO_SCALE_START, 1.0F, Easing::easeOutQuad(intro_logo_progress_));
|
||||
const float SCREEN_CENTRE_X = Defaults::Game::WIDTH / 2.0F;
|
||||
const float SCREEN_CENTRE_Y = Defaults::Game::HEIGHT / 2.0F;
|
||||
const float LOGO_RENDER_SCALE = Defaults::Title::Layout::LOGO_SCALE * LOGO_S;
|
||||
|
||||
if (animacio_activa_) {
|
||||
float temps_shadow = std::max(0.0F, temps_animacio_ - SHADOW_DELAY);
|
||||
@@ -537,28 +548,38 @@ void TitleScene::draw() {
|
||||
const float SHADOW_OY = (ORBIT_AMPLITUDE_Y * std::sin((TWO_PI * ORBIT_FREQUENCY_Y * temps_shadow) + ORBIT_PHASE_OFFSET)) + SHADOW_OFFSET_Y;
|
||||
|
||||
for (std::size_t i = 0; i < lletres_orni_.size(); ++i) {
|
||||
const float BASE_X = posicions_originals_orni_[i].x + std::round(SHADOW_OX);
|
||||
const float BASE_Y = posicions_originals_orni_[i].y + std::round(SHADOW_OY);
|
||||
const Vec2 POS_SHADOW{
|
||||
.x = posicions_originals_orni_[i].x + std::round(SHADOW_OX),
|
||||
.y = posicions_originals_orni_[i].y + std::round(SHADOW_OY) + LOGO_Y_INTRO,
|
||||
.x = SCREEN_CENTRE_X + (LOGO_S * (BASE_X - SCREEN_CENTRE_X)),
|
||||
.y = SCREEN_CENTRE_Y + (LOGO_S * (BASE_Y - SCREEN_CENTRE_Y)),
|
||||
};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletres_orni_[i].shape, POS_SHADOW, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, SHADOW_BRIGHTNESS, Defaults::Title::Colors::LOGO_SHADOW);
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletres_orni_[i].shape, POS_SHADOW, 0.0F, LOGO_RENDER_SCALE, 1.0F, SHADOW_BRIGHTNESS, Defaults::Title::Colors::LOGO_SHADOW);
|
||||
}
|
||||
for (std::size_t i = 0; i < lletres_attack_.size(); ++i) {
|
||||
const float BASE_X = posicions_originals_attack_[i].x + std::round(SHADOW_OX);
|
||||
const float BASE_Y = posicions_originals_attack_[i].y + std::round(SHADOW_OY);
|
||||
const Vec2 POS_SHADOW{
|
||||
.x = posicions_originals_attack_[i].x + std::round(SHADOW_OX),
|
||||
.y = posicions_originals_attack_[i].y + std::round(SHADOW_OY) + LOGO_Y_INTRO,
|
||||
.x = SCREEN_CENTRE_X + (LOGO_S * (BASE_X - SCREEN_CENTRE_X)),
|
||||
.y = SCREEN_CENTRE_Y + (LOGO_S * (BASE_Y - SCREEN_CENTRE_Y)),
|
||||
};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletres_attack_[i].shape, POS_SHADOW, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, SHADOW_BRIGHTNESS, Defaults::Title::Colors::LOGO_SHADOW);
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletres_attack_[i].shape, POS_SHADOW, 0.0F, LOGO_RENDER_SCALE, 1.0F, SHADOW_BRIGHTNESS, Defaults::Title::Colors::LOGO_SHADOW);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& lletra : lletres_orni_) {
|
||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + LOGO_Y_INTRO};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
||||
const Vec2 POS{
|
||||
.x = SCREEN_CENTRE_X + (LOGO_S * (lletra.position.x - SCREEN_CENTRE_X)),
|
||||
.y = SCREEN_CENTRE_Y + (LOGO_S * (lletra.position.y - SCREEN_CENTRE_Y)),
|
||||
};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, LOGO_RENDER_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
||||
}
|
||||
for (const auto& lletra : lletres_attack_) {
|
||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + LOGO_Y_INTRO};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
||||
const Vec2 POS{
|
||||
.x = SCREEN_CENTRE_X + (LOGO_S * (lletra.position.x - SCREEN_CENTRE_X)),
|
||||
.y = SCREEN_CENTRE_Y + (LOGO_S * (lletra.position.y - SCREEN_CENTRE_Y)),
|
||||
};
|
||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, LOGO_RENDER_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
||||
}
|
||||
|
||||
const float SPACING = Defaults::Title::Layout::TEXT_SPACING;
|
||||
|
||||
Reference in New Issue
Block a user