feat(demo): transició per fosa a/desde negre en el salt títol→demo

This commit is contained in:
2026-05-29 09:21:02 +02:00
parent 472c543c7b
commit 068f42782b
7 changed files with 158 additions and 5 deletions
+10 -1
View File
@@ -55,7 +55,8 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
text_(sdl.getRenderer()),
starfield_parallax_(sdl.getRenderer()),
playfield_(sdl.getRenderer()),
border_(sdl.getRenderer()) {
border_(sdl.getRenderer()),
fade_(sdl.getRenderer()) {
// Recuperar configuración de match des del context
match_config_ = context_.getMatchConfig();
@@ -170,6 +171,8 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
Audio::get()->enableSound(false);
// El fons (graella) ha d'aparèixer ja muntat: la demo és una partida en marxa.
playfield_.completeBuild();
// Fosa des de negre sobre el joc ja en marxa (transició suau des del títol).
fade_.start(1.0F, 0.0F, Defaults::Game::Fade::DEMO_IN_DURATION);
} else {
stage_manager_->init();
}
@@ -363,6 +366,8 @@ void GameScene::updateShipsControl(float delta_time) {
}
auto GameScene::stepDemo(float delta_time) -> bool {
fade_.update(delta_time); // fosa d'entrada des de negre
// Qualsevol input trenca la demo i torna al títol (música intacta).
if (Input::get()->checkAnyPlayerAction(DEMO_EXIT_ACTIONS)) {
context_.setNextScene(SceneType::TITLE, Option::JUMP_TO_TITLE_MAIN);
@@ -708,6 +713,10 @@ void GameScene::draw() {
drawLevelCompletedState();
break;
}
// Fosa d'entrada de la demo: per damunt de tot. No-op fora del mode DEMO
// (fade_ mai s'arrenca) i quan ja ha acabat (alpha 0).
fade_.draw();
}
void GameScene::drawEnemies() const {
+4
View File
@@ -10,6 +10,7 @@
#include "core/graphics/border.hpp"
#include "core/graphics/playfield.hpp"
#include "core/graphics/screen_fade.hpp"
#include "core/graphics/starfield_parallax.hpp"
#include "core/graphics/vector_text.hpp"
#include "core/physics/physics_world.hpp"
@@ -95,6 +96,9 @@ class GameScene final : public Scene {
// Border del playfield (4 línies amb desplaçaments i flash per impactes)
Graphics::Border border_;
// Fosa des de negre en entrar a la demo (només mode DEMO; inactiu en partida normal).
Graphics::ScreenFade fade_;
// [NEW] Stage system
std::unique_ptr<StageSystem::StageSystemConfig> stage_config_;
std::unique_ptr<StageSystem::StageManager> stage_manager_;
+29 -4
View File
@@ -37,7 +37,8 @@ namespace {
TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
: sdl_(sdl),
context_(context),
text_(sdl.getRenderer()) {
text_(sdl.getRenderer()),
fade_(sdl.getRenderer()) {
std::cout << "SceneType Titol: Inicialitzant...\n";
match_config_.player1_active = false;
@@ -333,6 +334,9 @@ void TitleScene::update(float delta_time) {
case TitleState::BLACK_SCREEN:
updateBlackScreenState(delta_time);
break;
case TitleState::DEMO_FADE_OUT:
updateDemoFadeOutState(delta_time);
break;
}
// Les animacions segueixen pero els inputs es bloquegen mentre el menu
@@ -368,7 +372,12 @@ void TitleScene::update(float delta_time) {
demo_cfg.player2_active = (SC.players >= 2);
demo_cfg.mode = GameConfig::Mode::DEMO;
context_.setMatchConfig(demo_cfg);
context_.setNextScene(SceneType::GAME);
// No saltem en sec: fosa a negre i, en acabar, canvi a GAME (el salt
// real el fa updateDemoFadeOutState). L'estat deixa de ser MAIN, així
// que ni es re-dispara la demo ni s'accepta START durant la fosa.
current_state_ = TitleState::DEMO_FADE_OUT;
fade_.start(0.0F, 1.0F, Defaults::Game::Fade::DEMO_OUT_DURATION);
temps_acumulat_ = 0.0F;
}
}
}
@@ -473,6 +482,13 @@ void TitleScene::updateBlackScreenState(float delta_time) {
}
}
void TitleScene::updateDemoFadeOutState(float delta_time) {
fade_.update(delta_time);
if (fade_.isDone()) {
context_.setNextScene(SceneType::GAME);
}
}
void TitleScene::handleSkipInput() {
if (current_state_ != TitleState::STARFIELD_FADE_IN && current_state_ != TitleState::STARFIELD) {
return;
@@ -577,7 +593,8 @@ void TitleScene::draw() {
(current_state_ == TitleState::STARFIELD_FADE_IN ||
current_state_ == TitleState::STARFIELD ||
current_state_ == TitleState::MAIN ||
current_state_ == TitleState::PLAYER_JOIN_PHASE)) {
current_state_ == TitleState::PLAYER_JOIN_PHASE ||
current_state_ == TitleState::DEMO_FADE_OUT)) {
ship_animator_->draw();
}
drawFlashes();
@@ -586,7 +603,12 @@ void TitleScene::draw() {
return;
}
if (current_state_ != TitleState::MAIN && current_state_ != TitleState::PLAYER_JOIN_PHASE) {
// DEMO_FADE_OUT es pinta com MAIN (logo + text) perquè el títol segueixi
// visible sota la fosa a negre.
if (current_state_ != TitleState::MAIN &&
current_state_ != TitleState::PLAYER_JOIN_PHASE &&
current_state_ != TitleState::DEMO_FADE_OUT) {
fade_.draw(); // BLACK_SCREEN i altres: només la fosa (si activa)
return;
}
@@ -657,6 +679,9 @@ void TitleScene::draw() {
}
dibuixarPeuTitol(SPACING);
// Fosa a negre (attract): per damunt de tot. No-op si no està activa.
fade_.draw();
}
auto TitleScene::checkSkipButtonPressed() -> bool {
+4
View File
@@ -18,6 +18,7 @@
#include <vector>
#include "core/graphics/camera3d.hpp"
#include "core/graphics/screen_fade.hpp"
#include "core/graphics/shape.hpp"
#include "core/graphics/starfield.hpp"
#include "core/graphics/vector_text.hpp"
@@ -46,6 +47,7 @@ class TitleScene final : public Scene {
MAIN,
PLAYER_JOIN_PHASE,
BLACK_SCREEN,
DEMO_FADE_OUT, // Attract: fosa a negre abans de saltar a la demo
};
struct LogoLetter {
@@ -60,6 +62,7 @@ class TitleScene final : public Scene {
SceneManager::SceneContext& context_;
GameConfig::MatchConfig match_config_;
Graphics::VectorText text_;
Graphics::ScreenFade fade_; // Fosa a negre en saltar a la demo (attract)
std::unique_ptr<Graphics::Camera3D> camera_;
std::unique_ptr<Graphics::Starfield> starfield_;
std::unique_ptr<Title::ShipAnimator> ship_animator_;
@@ -143,6 +146,7 @@ class TitleScene final : public Scene {
void updateMainState(float delta_time);
void updatePlayerJoinPhaseState(float delta_time);
void updateBlackScreenState(float delta_time);
void updateDemoFadeOutState(float delta_time);
void handleSkipInput();
void handleStartInput();
void triggerExitForJoinedPlayers(bool p1_was_active, bool p2_was_active, const char* log_prefix);