refactor(scenes): flux centralitzat amb SceneId+ExitRequest; TitleScene attract → LOGO amb fade-to-black
This commit is contained in:
1 parent
25ce524470
commit
b6d6ee471c
17 files changed
+368
-121
No files matched your search
@@ -17,6 +17,7 @@
|
||||
#include "core/ui/ui_config.hpp"
|
||||
#include "game/options.hpp"
|
||||
#include "game/scenes/placeholder_input.hpp"
|
||||
#include "game/scenes/scene_flow.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
|
||||
@@ -30,10 +31,9 @@ namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
IntroScene::IntroScene(std::shared_ptr<Text> font, DebugConfig::StartingPlayers starting_players, SceneFactory next_factory)
|
||||
IntroScene::IntroScene(std::shared_ptr<Text> font, DebugConfig::StartingPlayers starting_players)
|
||||
: font_(std::move(font)),
|
||||
starting_players_(starting_players),
|
||||
next_factory_(std::move(next_factory)) {
|
||||
starting_players_(starting_players) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " start (players=" << DebugConfig::toString(starting_players_) << ")\n";
|
||||
}
|
||||
|
||||
@@ -52,8 +52,11 @@ void IntroScene::update(int delta_ms) {
|
||||
return ev.type == SDL_EVENT_KEY_DOWN && !Placeholder::isReservedScancode(ev.key.scancode);
|
||||
});
|
||||
|
||||
if ((timer_ms_ <= 0 || SKIPPED) && next_factory_) {
|
||||
next_scene_ = next_factory_(starting_players_);
|
||||
if (timer_ms_ <= 0 || SKIPPED) {
|
||||
exit_request_ = ExitRequest{
|
||||
.next = SceneId::GAME,
|
||||
.params = GameParams{.starting_players = starting_players_},
|
||||
};
|
||||
}
|
||||
|
||||
Notifier::get().update(delta_ms);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "core/scene/scene.hpp"
|
||||
@@ -9,19 +8,17 @@
|
||||
class Text;
|
||||
|
||||
// Escena placeholder de la introducció. Com la resta de placeholders, durada
|
||||
// fixa i skip amb tecla no reservada; quan expira encadena a la factory
|
||||
// injectada (en producció: GameScene).
|
||||
// fixa i skip amb tecla no reservada; quan expira publica un `ExitRequest`
|
||||
// cap a GAME amb el `starting_players` rebut de TitleScene.
|
||||
//
|
||||
// `starting_players` és el resultat triat a la TitleScene (P1, P2 o BOTH).
|
||||
// L'IntroScene només el guarda i el reenvia a la seva factory; quan demà
|
||||
// L'IntroScene només el guarda i el reenvia per `ExitRequest`; quan demà
|
||||
// l'intro tinga contingut real podrà variar segons qui jugue.
|
||||
class IntroScene : public Scene {
|
||||
public:
|
||||
using SceneFactory = std::function<std::unique_ptr<Scene>(DebugConfig::StartingPlayers)>;
|
||||
|
||||
static constexpr int DURATION_MS = 5000;
|
||||
|
||||
IntroScene(std::shared_ptr<Text> font, DebugConfig::StartingPlayers starting_players, SceneFactory next_factory);
|
||||
IntroScene(std::shared_ptr<Text> font, DebugConfig::StartingPlayers starting_players);
|
||||
~IntroScene() override;
|
||||
|
||||
void update(int delta_ms) override;
|
||||
@@ -30,6 +27,5 @@ class IntroScene : public Scene {
|
||||
private:
|
||||
std::shared_ptr<Text> font_;
|
||||
DebugConfig::StartingPlayers starting_players_;
|
||||
SceneFactory next_factory_;
|
||||
int timer_ms_{DURATION_MS};
|
||||
};
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "core/ui/ui_config.hpp"
|
||||
#include "game/options.hpp"
|
||||
#include "game/scenes/placeholder_input.hpp"
|
||||
#include "game/scenes/scene_flow.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
|
||||
@@ -31,9 +32,8 @@ namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
LogoScene::LogoScene(std::shared_ptr<Text> font, SceneFactory next_factory)
|
||||
: font_(std::move(font)),
|
||||
next_factory_(std::move(next_factory)) {
|
||||
LogoScene::LogoScene(std::shared_ptr<Text> font)
|
||||
: font_(std::move(font)) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " start\n";
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ void LogoScene::update(int delta_ms) {
|
||||
return ev.type == SDL_EVENT_KEY_DOWN && !Placeholder::isReservedScancode(ev.key.scancode);
|
||||
});
|
||||
|
||||
if ((timer_ms_ <= 0 || SKIPPED) && next_factory_) {
|
||||
next_scene_ = next_factory_();
|
||||
if (timer_ms_ <= 0 || SKIPPED) {
|
||||
exit_request_ = ExitRequest{.next = SceneId::TITLE, .params = TitleParams{}};
|
||||
}
|
||||
|
||||
Notifier::get().update(delta_ms);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "core/scene/scene.hpp"
|
||||
@@ -8,16 +7,14 @@
|
||||
class Text;
|
||||
|
||||
// Escena placeholder del logotip. Durada fixa (5 s) o skip amb qualsevol tecla
|
||||
// no reservada. Quan expira, encadena amb la `SceneFactory` que se li injecta
|
||||
// al ctor — així l'escena no coneix el tipus concret de la següent, i es pot
|
||||
// exercir en tests sense arrossegar GameScene.
|
||||
// no reservada. Quan expira, publica un `ExitRequest` cap a TITLE; Director
|
||||
// és qui construeix la nova escena (l'escena no coneix els altres tipus i
|
||||
// es pot exercir en tests sense arrossegar dependències).
|
||||
class LogoScene : public Scene {
|
||||
public:
|
||||
using SceneFactory = std::function<std::unique_ptr<Scene>()>;
|
||||
|
||||
static constexpr int DURATION_MS = 5000;
|
||||
|
||||
LogoScene(std::shared_ptr<Text> font, SceneFactory next_factory);
|
||||
explicit LogoScene(std::shared_ptr<Text> font);
|
||||
~LogoScene() override;
|
||||
|
||||
void update(int delta_ms) override;
|
||||
@@ -25,6 +22,5 @@ class LogoScene : public Scene {
|
||||
|
||||
private:
|
||||
std::shared_ptr<Text> font_;
|
||||
SceneFactory next_factory_;
|
||||
int timer_ms_{DURATION_MS};
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
|
||||
#include "game/debug_config.hpp"
|
||||
|
||||
// Sistema centralitzat de transicions entre escenes. Cada escena, en lloc
|
||||
// de construir directament la següent, declara una `ExitRequest` amb un
|
||||
// identificador i els paràmetres que la nova escena necessite per
|
||||
// arrencar; `Director::buildScene` és l'únic punt que sap com instanciar
|
||||
// cada tipus i té tots els recursos a mà.
|
||||
//
|
||||
// Afegir una escena nova:
|
||||
// 1. Una entrada al `enum SceneId`.
|
||||
// 2. Si necessita paràmetres, un struct `*Params` i afegir-lo al variant.
|
||||
// 3. Un cas a `Director::buildScene` que el construïsca.
|
||||
//
|
||||
// Una escena només pot demanar transicionar a un altre `SceneId` que
|
||||
// haja estat enregistrat al variant — el compilador ja descarta noms
|
||||
// erronis.
|
||||
enum class SceneId : std::uint8_t {
|
||||
LOGO,
|
||||
TITLE,
|
||||
INTRO,
|
||||
GAME,
|
||||
};
|
||||
|
||||
// Estructures de paràmetres per escena. Buides quan la nova escena no
|
||||
// rep cap dada de l'anterior; en cas contrari, només els camps que
|
||||
// fluixen pel canal de transició (els recursos, defaults i config
|
||||
// interna els resol Director quan construeix).
|
||||
struct LogoParams {};
|
||||
struct TitleParams {};
|
||||
struct IntroParams {
|
||||
DebugConfig::StartingPlayers starting_players{DebugConfig::StartingPlayers::BOTH};
|
||||
};
|
||||
struct GameParams {
|
||||
DebugConfig::StartingPlayers starting_players{DebugConfig::StartingPlayers::BOTH};
|
||||
};
|
||||
|
||||
using SceneParams = std::variant<LogoParams, TitleParams, IntroParams, GameParams>;
|
||||
|
||||
struct ExitRequest {
|
||||
SceneId next;
|
||||
SceneParams params;
|
||||
};
|
||||
|
||||
// Helper per a logs / debug. Implementat inline per evitar un .cpp per a
|
||||
// una funció de tres línies.
|
||||
[[nodiscard]] inline auto toString(SceneId id) -> const char* {
|
||||
switch (id) {
|
||||
case SceneId::LOGO:
|
||||
return "LOGO";
|
||||
case SceneId::TITLE:
|
||||
return "TITLE";
|
||||
case SceneId::INTRO:
|
||||
return "INTRO";
|
||||
case SceneId::GAME:
|
||||
return "GAME";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core/system/event_buffer.hpp"
|
||||
#include "core/ui/ui_config.hpp"
|
||||
#include "game/options.hpp"
|
||||
#include "game/scenes/scene_flow.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
|
||||
@@ -81,12 +82,11 @@ namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
TitleScene::TitleScene(std::shared_ptr<Text> display_font, std::shared_ptr<Text> condensed_font, std::shared_ptr<Surface> background, std::shared_ptr<Surface> mini_logo, SceneFactory next_factory)
|
||||
TitleScene::TitleScene(std::shared_ptr<Text> display_font, std::shared_ptr<Text> condensed_font, std::shared_ptr<Surface> background, std::shared_ptr<Surface> mini_logo)
|
||||
: display_font_(std::move(display_font)),
|
||||
condensed_font_(std::move(condensed_font)),
|
||||
background_(std::move(background)),
|
||||
mini_logo_(std::move(mini_logo)),
|
||||
next_factory_(std::move(next_factory)),
|
||||
timer_ms_(UiConfig::get().titleDurationMs()) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " start\n";
|
||||
const auto& hh = UiConfig::get().titleHeatHaze();
|
||||
@@ -100,10 +100,12 @@ TitleScene::TitleScene(std::shared_ptr<Text> display_font, std::shared_ptr<Text>
|
||||
fade_out_.emplace(Transitions::Mosaic::Params{
|
||||
.max_block_size = UiConfig::get().titleFadeOutMaxBlock(),
|
||||
});
|
||||
attract_fade_.emplace();
|
||||
|
||||
// Música de fons en bucle. Es preloda al Director, així que la
|
||||
// primera crida és immediata. El fade-out arrenca en entrar a
|
||||
// STARTING (vore enterStarting).
|
||||
// STARTING (vore enterStarting); en ATTRACT_OUT NO es toca, la
|
||||
// música segueix sonant cap a LOGO.
|
||||
if (auto* audio = Audio::get(); audio != nullptr) {
|
||||
audio->playMusic("title.ogg", -1);
|
||||
}
|
||||
@@ -131,53 +133,15 @@ void TitleScene::update(int delta_ms) {
|
||||
const bool P2_START = pressedStart(1);
|
||||
|
||||
switch (phase_) {
|
||||
case Phase::IDLE: {
|
||||
timer_ms_ -= delta_ms;
|
||||
if (P1_START) {
|
||||
playStartSound();
|
||||
enterStarting(DebugConfig::StartingPlayers::P1);
|
||||
} else if (P2_START) {
|
||||
playStartSound();
|
||||
enterStarting(DebugConfig::StartingPlayers::P2);
|
||||
} else if (timer_ms_ <= 0) {
|
||||
// Attract: ningú ha premut. Entrem a STARTING amb BOTH
|
||||
// perquè el fade-out de transició també hi compti.
|
||||
// Demà, quan tinguem una DemoScene, ací anirà la
|
||||
// transició a demo en lloc de a intro.
|
||||
enterStarting(DebugConfig::StartingPlayers::BOTH);
|
||||
}
|
||||
case Phase::IDLE:
|
||||
tickIdle(delta_ms, P1_START, P2_START);
|
||||
break;
|
||||
}
|
||||
case Phase::STARTING: {
|
||||
starting_timer_ms_ -= delta_ms;
|
||||
// Si l'altre jugador prem START dins de la finestra (i el
|
||||
// fade encara no ha arrencat), pugem a BOTH i resetegem el
|
||||
// comptador. Una vegada el fade ja està actiu, ignorem
|
||||
// pulsacions per no saltar visualment la transició.
|
||||
const bool OTHER_PRESSED =
|
||||
(pending_players_ == DebugConfig::StartingPlayers::P1 && P2_START) ||
|
||||
(pending_players_ == DebugConfig::StartingPlayers::P2 && P1_START);
|
||||
const bool FADE_LOCKED = fade_out_ && (fade_out_->isActive() || fade_out_->isFinished());
|
||||
if (OTHER_PRESSED && !FADE_LOCKED) {
|
||||
playStartSound();
|
||||
pending_players_ = DebugConfig::StartingPlayers::BOTH;
|
||||
starting_timer_ms_ = UiConfig::get().titleStartingMs();
|
||||
}
|
||||
|
||||
// Arrenca el fade quan al comptador li queden <= fade_out_ms,
|
||||
// i només una vegada (ni en repeticions ni si l'altre jugador
|
||||
// ha resetejat el timer).
|
||||
const int FADE_MS = UiConfig::get().titleFadeOutMs();
|
||||
if (fade_out_ && !fade_out_->isActive() && !fade_out_->isFinished() && starting_timer_ms_ <= FADE_MS && FADE_MS > 0) {
|
||||
fade_out_->begin(FADE_MS);
|
||||
}
|
||||
if (fade_out_ && fade_out_->isActive()) { fade_out_->tick(delta_ms); }
|
||||
|
||||
if (starting_timer_ms_ <= 0) {
|
||||
advanceTo(pending_players_);
|
||||
}
|
||||
case Phase::STARTING:
|
||||
tickStarting(delta_ms, P1_START, P2_START);
|
||||
break;
|
||||
case Phase::ATTRACT_OUT:
|
||||
tickAttract(delta_ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Notifier::get().update(delta_ms);
|
||||
@@ -201,12 +165,85 @@ void TitleScene::enterStarting(DebugConfig::StartingPlayers players) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " STARTING (players=" << DebugConfig::toString(players) << ")\n";
|
||||
}
|
||||
|
||||
void TitleScene::advanceTo(DebugConfig::StartingPlayers players) {
|
||||
if (next_factory_) {
|
||||
next_scene_ = next_factory_(players);
|
||||
void TitleScene::tickIdle(int delta_ms, bool p1_start, bool p2_start) {
|
||||
timer_ms_ -= delta_ms;
|
||||
if (p1_start) {
|
||||
playStartSound();
|
||||
enterStarting(DebugConfig::StartingPlayers::P1);
|
||||
} else if (p2_start) {
|
||||
playStartSound();
|
||||
enterStarting(DebugConfig::StartingPlayers::P2);
|
||||
} else if (timer_ms_ <= 0) {
|
||||
// Attract timeout: ningú ha premut. Sortida silenciosa cap a
|
||||
// LOGO amb fade-to-black; música i parpadeig intactes.
|
||||
enterAttract();
|
||||
}
|
||||
}
|
||||
|
||||
void TitleScene::tickStarting(int delta_ms, bool p1_start, bool p2_start) {
|
||||
starting_timer_ms_ -= delta_ms;
|
||||
// Si l'altre jugador prem START dins de la finestra (i el fade
|
||||
// encara no ha arrencat), pugem a BOTH i resetegem el comptador.
|
||||
// Una vegada el fade ja està actiu, ignorem pulsacions per no
|
||||
// saltar visualment la transició.
|
||||
const bool OTHER_PRESSED =
|
||||
(pending_players_ == DebugConfig::StartingPlayers::P1 && p2_start) ||
|
||||
(pending_players_ == DebugConfig::StartingPlayers::P2 && p1_start);
|
||||
const bool FADE_LOCKED = fade_out_ && (fade_out_->isActive() || fade_out_->isFinished());
|
||||
if (OTHER_PRESSED && !FADE_LOCKED) {
|
||||
playStartSound();
|
||||
pending_players_ = DebugConfig::StartingPlayers::BOTH;
|
||||
starting_timer_ms_ = UiConfig::get().titleStartingMs();
|
||||
}
|
||||
|
||||
// Arrenca el fade quan al comptador li queden <= fade_out_ms, i
|
||||
// només una vegada (ni en repeticions ni si l'altre jugador ha
|
||||
// resetejat el timer).
|
||||
const int FADE_MS = UiConfig::get().titleFadeOutMs();
|
||||
if (fade_out_ && !fade_out_->isActive() && !fade_out_->isFinished() && starting_timer_ms_ <= FADE_MS && FADE_MS > 0) {
|
||||
fade_out_->begin(FADE_MS);
|
||||
}
|
||||
if (fade_out_ && fade_out_->isActive()) { fade_out_->tick(delta_ms); }
|
||||
|
||||
if (starting_timer_ms_ <= 0) {
|
||||
advanceToIntro(pending_players_);
|
||||
}
|
||||
}
|
||||
|
||||
void TitleScene::tickAttract(int delta_ms) {
|
||||
// Sortida d'attract: només avancem el fade-to-black. Quan s'acaba
|
||||
// demanem transició a LOGO. Cap input ni música ni canvi de
|
||||
// freqüència de parpadeig — el text "press start" segueix amb el
|
||||
// cicle d'IDLE per damunt del fade.
|
||||
if (!attract_fade_) { return; }
|
||||
attract_fade_->tick(delta_ms);
|
||||
if (attract_fade_->isFinished()) {
|
||||
advanceToLogo();
|
||||
}
|
||||
}
|
||||
|
||||
void TitleScene::enterAttract() {
|
||||
phase_ = Phase::ATTRACT_OUT;
|
||||
if (attract_fade_) {
|
||||
attract_fade_->begin(UiConfig::get().titleAttractFadeToBlackMs());
|
||||
}
|
||||
std::cout << "[scene] " << SCENE_NAME << " ATTRACT_OUT\n";
|
||||
}
|
||||
|
||||
void TitleScene::advanceToIntro(DebugConfig::StartingPlayers players) {
|
||||
exit_request_ = ExitRequest{
|
||||
.next = SceneId::INTRO,
|
||||
.params = IntroParams{.starting_players = players},
|
||||
};
|
||||
}
|
||||
|
||||
void TitleScene::advanceToLogo() {
|
||||
exit_request_ = ExitRequest{
|
||||
.next = SceneId::LOGO,
|
||||
.params = LogoParams{},
|
||||
};
|
||||
}
|
||||
|
||||
void TitleScene::render() {
|
||||
const auto& ui_config = UiConfig::get();
|
||||
const auto& palette = Resource::Cache::get().getPalette("ui");
|
||||
@@ -299,10 +336,14 @@ void TitleScene::render() {
|
||||
|
||||
Notifier::get().render();
|
||||
|
||||
// El fade-out cobreix l'escena i el Notifier (forma part de la
|
||||
// transició), però NO el RenderInfo (overlay de debug, sempre
|
||||
// visible).
|
||||
if (fade_out_ && (fade_out_->isActive() || fade_out_->isFinished())) {
|
||||
// Capa de transició final segons la fase. Sempre cobreix l'escena
|
||||
// i el Notifier, mai el RenderInfo (overlay de debug, sempre
|
||||
// visible). STARTING usa mosaic dissolve; ATTRACT_OUT, fade-to-black
|
||||
// lineal (sense efecte chunky perquè la sortida silenciosa s'integre
|
||||
// amb la pista visual del LOGO).
|
||||
if (phase_ == Phase::ATTRACT_OUT && attract_fade_) {
|
||||
attract_fade_->render();
|
||||
} else if (fade_out_ && (fade_out_->isActive() || fade_out_->isFinished())) {
|
||||
fade_out_->render();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "core/rendering/effects/heat_haze.hpp"
|
||||
#include "core/rendering/transitions/fade_to_black.hpp"
|
||||
#include "core/rendering/transitions/mosaic.hpp"
|
||||
#include "core/scene/scene.hpp"
|
||||
#include "game/debug_config.hpp"
|
||||
@@ -19,33 +19,40 @@ class Text;
|
||||
// data/ui.yaml secció `title:` per poder afinar-la sense recompilar.
|
||||
class TitleScene : public Scene {
|
||||
public:
|
||||
using SceneFactory = std::function<std::unique_ptr<Scene>(DebugConfig::StartingPlayers)>;
|
||||
|
||||
// Fases de l'escena.
|
||||
// - IDLE: animació atràctil. Cap tecla salta; només P1 START o
|
||||
// P2 START fan transició. El timeout (`title.duration_ms`)
|
||||
// salta a la següent escena amb BOTH (modus attract).
|
||||
// - IDLE: animació atràctil. Només P1 START o P2 START hi fan
|
||||
// transició; un timeout `title.duration_ms` porta a ATTRACT_OUT.
|
||||
// - STARTING: comptador fix entre la primera pulsació de START i
|
||||
// la transició. Si l'altre jugador prem START dins d'aquesta
|
||||
// finestra, el comptador es reseteja amb `pending_players_=BOTH`.
|
||||
// la transició cap a INTRO. Si l'altre jugador prem START dins
|
||||
// d'aquesta finestra, el comptador es reseteja amb
|
||||
// `pending_players_=BOTH`. Visual: mosaic dissolve + fade-out
|
||||
// de música.
|
||||
// - ATTRACT_OUT: fase de sortida silenciosa cap a LOGO quan
|
||||
// expira el timeout sense pulsacions. Visual: fade-to-black net.
|
||||
// NO toca la música ni canvia la freqüència del parpadeig.
|
||||
enum class Phase : std::uint8_t { IDLE,
|
||||
STARTING };
|
||||
STARTING,
|
||||
ATTRACT_OUT };
|
||||
|
||||
TitleScene(std::shared_ptr<Text> display_font, std::shared_ptr<Text> condensed_font, std::shared_ptr<Surface> background, std::shared_ptr<Surface> mini_logo, SceneFactory next_factory);
|
||||
TitleScene(std::shared_ptr<Text> display_font, std::shared_ptr<Text> condensed_font, std::shared_ptr<Surface> background, std::shared_ptr<Surface> mini_logo);
|
||||
~TitleScene() override;
|
||||
|
||||
void update(int delta_ms) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
void tickIdle(int delta_ms, bool p1_start, bool p2_start);
|
||||
void tickStarting(int delta_ms, bool p1_start, bool p2_start);
|
||||
void tickAttract(int delta_ms);
|
||||
void enterStarting(DebugConfig::StartingPlayers players);
|
||||
void advanceTo(DebugConfig::StartingPlayers players);
|
||||
void enterAttract();
|
||||
void advanceToIntro(DebugConfig::StartingPlayers players);
|
||||
void advanceToLogo();
|
||||
|
||||
std::shared_ptr<Text> display_font_;
|
||||
std::shared_ptr<Text> condensed_font_;
|
||||
std::shared_ptr<Surface> background_;
|
||||
std::shared_ptr<Surface> mini_logo_;
|
||||
SceneFactory next_factory_;
|
||||
int timer_ms_;
|
||||
int blink_elapsed_ms_{0};
|
||||
std::optional<Effects::HeatHaze> heat_haze_;
|
||||
@@ -53,4 +60,5 @@ class TitleScene : public Scene {
|
||||
int starting_timer_ms_{0};
|
||||
DebugConfig::StartingPlayers pending_players_{DebugConfig::StartingPlayers::BOTH};
|
||||
std::optional<Transitions::Mosaic> fade_out_;
|
||||
std::optional<Transitions::FadeToBlack> attract_fade_;
|
||||
};
|
||||
Reference in new issue
Block a user