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.
|
// Coreografia de la seqüència d'entrada al state MAIN.
|
||||||
// Tots els elements (logo, footer, naus, press start) entren ordenadament
|
// Tots els elements (logo, footer, naus, press start) entren ordenadament
|
||||||
// segons aquests thresholds. Vegeu title_scene.cpp/updateMainState.
|
// 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 {
|
namespace Sequence {
|
||||||
// Offsets fora-pantalla per a l'animació d'entrada (additius a la posició final).
|
// Factor d'escala inicial. >1 = sprite gran a l'inici (prop de l'usuari).
|
||||||
constexpr float LOGO_OFFSCREEN_OFFSET_Y = -240.0F; // logo entra des de dalt
|
// La posició inicial es deriva: pivot=centre, delta multiplicat per aquest factor.
|
||||||
constexpr float FOOTER_OFFSCREEN_OFFSET_Y = +160.0F; // jailgames/copyright entren des de baix
|
constexpr float LOGO_INTRO_SCALE_START = 2.5F;
|
||||||
|
constexpr float FOOTER_INTRO_SCALE_START = 2.5F;
|
||||||
|
|
||||||
// Durades de les animacions d'entrada (segons).
|
// Durades de les animacions d'entrada (segons).
|
||||||
constexpr float LOGO_ENTRY_DURATION = 1.2F;
|
constexpr float LOGO_ENTRY_DURATION = 1.2F;
|
||||||
|
|||||||
@@ -250,14 +250,21 @@ void TitleScene::inicialitzarJailgames() {
|
|||||||
void TitleScene::dibuixarPeuTitol(float spacing) const {
|
void TitleScene::dibuixarPeuTitol(float spacing) const {
|
||||||
namespace S = Defaults::Title::Sequence;
|
namespace S = Defaults::Title::Sequence;
|
||||||
|
|
||||||
const float JAILGAMES_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_jailgames_progress_)) *
|
// Pivot al centre de pantalla (= projecció VP). Cada element s'expandeix
|
||||||
S::FOOTER_OFFSCREEN_OFFSET_Y;
|
// des d'aquí mentre s_factor passa de SCALE_START (gran, prop de l'usuari)
|
||||||
const float COPYRIGHT_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_copyright_progress_)) *
|
// a 1.0 (a la mida i posició finals, "lluny" al VP).
|
||||||
S::FOOTER_OFFSCREEN_OFFSET_Y;
|
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_) {
|
for (const auto& lletra : lletres_jailgames_) {
|
||||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + JAILGAMES_Y_INTRO};
|
const Vec2 POS{
|
||||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::JAILGAMES_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::JAILGAMES_LOGO);
|
.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;
|
std::string copyright = Project::COPYRIGHT;
|
||||||
for (char& c : copyright) {
|
for (char& c : copyright) {
|
||||||
@@ -265,9 +272,11 @@ void TitleScene::dibuixarPeuTitol(float spacing) const {
|
|||||||
c = static_cast<char>(c - 32);
|
c = static_cast<char>(c - 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const float Y_COPY = (Defaults::Game::HEIGHT * Defaults::Title::Layout::COPYRIGHT1_POS) + COPYRIGHT_Y_INTRO;
|
const float Y_COPY_FINAL = Defaults::Game::HEIGHT * Defaults::Title::Layout::COPYRIGHT1_POS;
|
||||||
const float CENTRE_X = Defaults::Game::WIDTH / 2.0F;
|
const float COPY_X = SCREEN_CENTRE_X; // ja al centre
|
||||||
text_.renderCentered(copyright, {.x = CENTRE_X, .y = Y_COPY}, Defaults::Title::Layout::COPYRIGHT_SCALE, spacing, 1.0F, Defaults::Title::Colors::COPYRIGHT);
|
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 {
|
auto TitleScene::isFinished() const -> bool {
|
||||||
@@ -524,11 +533,13 @@ void TitleScene::draw() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset additiu de la intro del logo (cau des de dalt). Quan progress=1,
|
// Factor d'escala+posició per simular un moviment 3D des de l'usuari (prop,
|
||||||
// el logo està al seu lloc i aquest offset val 0 — l'oscil·lació suau
|
// sprite gran i posició projectada extrema) cap al VP (lluny, sprite a la
|
||||||
// (updateLogoAnimation) continua treballant sobre la posició base.
|
// seva mida i posició finals). Pivot: centre de pantalla (= projecció VP).
|
||||||
const float LOGO_Y_INTRO = (1.0F - Easing::easeOutQuad(intro_logo_progress_)) *
|
const float LOGO_S = std::lerp(Defaults::Title::Sequence::LOGO_INTRO_SCALE_START, 1.0F, Easing::easeOutQuad(intro_logo_progress_));
|
||||||
Defaults::Title::Sequence::LOGO_OFFSCREEN_OFFSET_Y;
|
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_) {
|
if (animacio_activa_) {
|
||||||
float temps_shadow = std::max(0.0F, temps_animacio_ - SHADOW_DELAY);
|
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;
|
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) {
|
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{
|
const Vec2 POS_SHADOW{
|
||||||
.x = posicions_originals_orni_[i].x + std::round(SHADOW_OX),
|
.x = SCREEN_CENTRE_X + (LOGO_S * (BASE_X - SCREEN_CENTRE_X)),
|
||||||
.y = posicions_originals_orni_[i].y + std::round(SHADOW_OY) + LOGO_Y_INTRO,
|
.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) {
|
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{
|
const Vec2 POS_SHADOW{
|
||||||
.x = posicions_originals_attack_[i].x + std::round(SHADOW_OX),
|
.x = SCREEN_CENTRE_X + (LOGO_S * (BASE_X - SCREEN_CENTRE_X)),
|
||||||
.y = posicions_originals_attack_[i].y + std::round(SHADOW_OY) + LOGO_Y_INTRO,
|
.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_) {
|
for (const auto& lletra : lletres_orni_) {
|
||||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + LOGO_Y_INTRO};
|
const Vec2 POS{
|
||||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
.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_) {
|
for (const auto& lletra : lletres_attack_) {
|
||||||
const Vec2 POS{.x = lletra.position.x, .y = lletra.position.y + LOGO_Y_INTRO};
|
const Vec2 POS{
|
||||||
Rendering::renderShape(sdl_.getRenderer(), lletra.shape, POS, 0.0F, Defaults::Title::Layout::LOGO_SCALE, 1.0F, 1.0F, Defaults::Title::Colors::LOGO_MAIN);
|
.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;
|
const float SPACING = Defaults::Title::Layout::TEXT_SPACING;
|
||||||
|
|||||||
Reference in New Issue
Block a user