feat(audio): cicle de música per estat (INTRO/PLAYING/OUTRO) amb callback de fi i spawn escalonat

This commit is contained in:
JailDesigner committed 2026-04-28 19:41:38 +02:00
1 parent 91f664c4d5
commit 404db74889
13 files changed
+199 -128

No files matched your search

+47 -24
View File
@@ -104,30 +104,52 @@ class GameScene : public Scene {
// queda DISABLED tot el cicle de sala.
std::array<bool, 2> players_starts_active_{false, false};
// Mil·lisegons des de l'entrada en ROOM_INTRO, per disparar la
// cinemàtica de spawn aeri quan s'arriba al delay corresponent al
// slot. Es reseteja a `setState(ROOM_INTRO)`. Cada slot té el seu
// propi flag de "ja he caigut" — així podem caure en moments
// distints en mode BOTH (`player_spawn_delay_ms` per a P1 i
// `player2_spawn_delay_ms` per a P2).
int room_intro_elapsed_ms_{0};
std::array<bool, 2> players_spawned_in_intro_{false, false};
// One-shot del so del rètol d'INTRO (`text_sound` a game.yaml).
// Es disparen quan la FSM passa a phase 2 (text_enter); el flag
// evita repeticions si phase 2 s'estén multi-frame. Es reseteja a
// `enterRoomIntro` / `setState(ROOM_INTRO)`. Si la clau del so és
// buida o el cache no l'ha carregat, queda inutilitzat.
bool intro_text_sound_played_{false};
// Cinemàtica de spawn d'un slot concret. Posa el slot indicat en
// AIRBORNE des d'una altura fora de pantalla. Cridat per
// `updateRoomTransition` quan `room_intro_elapsed_ms_` supera el
// delay específic de l'slot. Idempotent (consulta el flag corresponent
// a `players_spawned_in_intro_`). També és el punt al qual es
// connectarà el respawn post-mort en el futur.
// `spawnDuePlayers` quan el timer post-callback supera el delay
// del slot. Idempotent (consulta `players_spawned_in_intro_`).
// També és el punt al qual es connectarà el respawn post-mort en
// el futur.
void triggerPlayerSpawn(std::size_t slot_index);
// Cos del callback de fi de música d'INTRO. Idempotent: si ja s'ha
// disparat aquest cicle (`intro_completed_`), no fa res. Marca el
// flag, reseteja el timer post-callback i intenta spawn dels slots
// actius amb delay <= 0 ara mateix; els altres cauen frame a frame
// dins `updateRoomTransition` quan el timer els assoleix. Finalment
// commuta a PLAYING — la música del joc arrenca amb el primer slot.
void completeIntro();
// Itera els slots actius i, si el delay configurat ha expirat des
// del callback de fi de música d'INTRO, dispara `triggerPlayerSpawn`.
// Cridada cada frame durant la fase d'spawn escalonat (entre el
// callback i la caiguda de l'últim slot). No fa res si ja han
// caigut tots o si encara no estem dins la finestra (intro_completed_).
void spawnDuePlayers();
// Hi ha un únic slot global de callback de fi de música a `Ja::Engine`.
// Cada estat (INTRO, OUTRO) ha de registrar el seu en entrar i pot
// sobreescriure'l amb el del següent estat. Aquests flags marquen
// si el callback corresponent ja ha disparat: són la frontera entre
// el thread d'audio (que invoca el callback dins `Engine::update`)
// i la lògica de transició (`updateRoomTransition`).
bool intro_completed_{false};
bool outro_music_ended_{false};
// Mil·lisegons acumulats des del callback de fi de música d'INTRO,
// per gatejar l'spawn aeri escalonat dels slots actius. P1 fa
// servir `player_spawn_delay_ms` (típicament 0); P2 en mode BOTH
// fa servir `player2_spawn_delay_ms` (offset respecte P1). Es
// reseteja a 0 dins `completeIntro` i no torna a córrer fins al
// següent cicle d'INTRO.
int intro_spawn_elapsed_ms_{0};
// Per slot: ja ha caigut aquest cicle d'INTRO? Garanteix
// idempotència de `triggerPlayerSpawn` davant múltiples ticks del
// timer mentre el delay no s'ha mogut. Es reseteja a `enterRoomIntro`
// i a `setState(ROOM_INTRO)` (camí defensiu no canònic).
std::array<bool, 2> players_spawned_in_intro_{false, false};
// Vista plana de punters crus — la fa servir Player com a llista
// d'obstacles mòbils a la callback de col·lisió. Es construeix un sol
// cop al ctor (els punters són estables perquè `players_` no es
@@ -252,10 +274,11 @@ class GameScene : public Scene {
void advanceToNextRoom();
// Inicia (o reinicia) el cicle d'entrada de sala: posa l'estat a
// ROOM_INTRO i reseteja `transition_`, `room_intro_elapsed_ms_` i el
// flag d'spawn aeri. Idempotent quan ja s'estava a INTRO (els
// timers tornen a començar des de zero — útil per als salts debug
// que recarreguen la sala estant ja en INTRO).
// ROOM_INTRO, reseteja `transition_` i `intro_completed_`, i comença
// la pista `room_intro.ogg` amb un callback de fi que dispararà
// `completeIntro()`. Si la càrrega de la música falla, dispara
// `completeIntro()` síncronament perquè la sala no quedi bloquejada.
// Idempotent quan ja s'estava a INTRO — útil per als salts debug.
void enterRoomIntro();
#ifdef _DEBUG