HUD: la GameScene crida hud_->setPyramidRoom amb els valors del
LevelManager al ctor i a cada loadRoom — el marcador deixa de
mostrar 1/1 fix i s'actualitza en avançar de sala, en saltar amb
[/] i en arrencar amb starting_level del debug.yaml.
INTRO a dues línies: substitueix la clau game.room_intro per
game.room_intro_pyramid ("Piramide {p}") i game.room_intro_room
("Sala {r}") als locale ca/en. RoomFsm::formatRoomTitle(int)
desapareix i el reemplacen formatIntroPyramidLine(int) +
formatIntroRoomLine(int). renderRoomText es refactoritza per
dibuixar les dues línies (piràmide damunt, sala davall) amb
writeDX independents — comparteixen animació ara mateix però el
disseny ja les deixa preparades per ser desacoblades en el futur.
Drive-by: elimina el membre room_index_ de GameScene; les tres
ubicacions que el sincronitzaven amb el LevelManager (ctor,
advanceToNextRoom, salt debug) ja no fan falta — renderRoomText
i el HUD pregunten directament al singleton, evitant qualsevol
mirror local desincronitzable.
Test: T9/T10 actualitzats per a les dues noves formatadores.
83 lines
3.5 KiB
C++
83 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
#include "core/ui/ui_config.hpp"
|
|
|
|
// FSM de sala (intro/outro) extreta de GameScene per a testabilitat. La
|
|
// lògica que viu aquí és pura: no toca SDL, ni Audio, ni cap singleton
|
|
// excepte `Locale::get()` (per a la formatació del text). El consumidor
|
|
// actual és `GameScene`, que cridarà `RoomFsm::advance` cada frame.
|
|
namespace RoomFsm {
|
|
|
|
enum class State : std::uint8_t {
|
|
ROOM_INTRO, // Entrada de sala: fade in + text d'entrada.
|
|
PLAYING, // Joc normal.
|
|
ROOM_OUTRO, // Sortida de sala: text de sortida + fade out.
|
|
};
|
|
|
|
// Sub-fase i temps acumulat dins de l'estat actual. Es reseteja a
|
|
// {0, 0} quan es canvia d'estat. Significat de `phase` per estat:
|
|
// ROOM_INTRO: 0=fade_in, 1=text_delay, 2=text_enter, 3=text_hold, 4=text_exit
|
|
// ROOM_OUTRO: 0=text_enter, 1=text_hold, 2=text_exit, 3=fade_out
|
|
// PLAYING: no s'usa.
|
|
struct Transition {
|
|
int phase{0};
|
|
int elapsed_ms{0};
|
|
};
|
|
|
|
// Timings i corbes carregats de `data/scenes/game.yaml`. Els valors
|
|
// per defecte coincideixen amb els del YAML versionat: si manca el
|
|
// fitxer, la FSM funciona igualment amb aquests fallbacks.
|
|
struct Config {
|
|
int intro_fade_in_ms{500};
|
|
int intro_text_delay_ms{500};
|
|
int intro_text_enter_ms{500};
|
|
int intro_text_hold_ms{1000};
|
|
int intro_text_exit_ms{500};
|
|
|
|
int outro_text_enter_ms{500};
|
|
int outro_text_hold_ms{1000};
|
|
int outro_text_exit_ms{500};
|
|
int outro_fade_out_ms{500};
|
|
|
|
// Mil·lisegons des de l'inici de ROOM_INTRO en què cau la
|
|
// cinemàtica d'spawn aeri dels jugadors actius. Independent del
|
|
// fade-in perquè el mateix valor servirà per al respawn post-mort
|
|
// (que no té fade que el sincronitze). 500 ms = típicament el
|
|
// moment en què el fade-in acaba i el text encara no ha entrat.
|
|
int player_spawn_delay_ms{500};
|
|
|
|
UiConfig::CurveFn text_enter_curve{nullptr};
|
|
UiConfig::CurveFn text_exit_curve{nullptr};
|
|
};
|
|
|
|
// Llegeix la configuració des del YAML. Si el fitxer manca o falten
|
|
// claus, els camps no presents conserven els seus fallbacks. Les
|
|
// corbes es resolen amb `UiConfig::curveByName` (mateix mecanisme
|
|
// que la pausa); si el nom és desconegut cau a `Easing::linear`.
|
|
[[nodiscard]] auto loadConfig(const std::string& yaml_path) -> Config;
|
|
|
|
// Avança la transició consumint `delta_ms` des del temps real.
|
|
// Retorna l'estat resultant (potser el mateix que l'entrant si
|
|
// encara queden sub-fases). Si retorna un estat diferent, el caller
|
|
// ha de resetejar la `Transition` a {0, 0} abans del següent frame
|
|
// (això ho fa `GameScene::setState`). Funció pura sobre l'argument.
|
|
[[nodiscard]] auto advance(State current, Transition& t, const Config& cfg, int delta_ms) -> State;
|
|
|
|
// Substitueix `{p}` de la clau "game.room_intro_pyramid" del Locale
|
|
// per l'enter passat. Pensat per a la primera línia del text d'INTRO.
|
|
// Si la clau no està traduïda, retorna la pròpia clau (fallback de
|
|
// Locale::text).
|
|
[[nodiscard]] auto formatIntroPyramidLine(int pyramid) -> std::string;
|
|
|
|
// Equivalent per a `game.room_intro_room` amb el placeholder `{r}`.
|
|
// Es renderitza com a segona línia del text d'INTRO.
|
|
[[nodiscard]] auto formatIntroRoomLine(int room) -> std::string;
|
|
|
|
// Nom textual per a logs i tests. No es fa servir per a lògica.
|
|
[[nodiscard]] auto stateName(State s) -> const char*;
|
|
|
|
} // namespace RoomFsm
|