feat(audio): música només a PLAYING; so del rètol al final del fade-in d'INTRO

This commit is contained in:
JailDesigner committed 2026-04-27 08:48:01 +02:00
1 parent 7d725f99f4
commit 15a7c4e18a
6 files changed
+64 -5

No files matched your search

+42 -5
View File
@@ -423,11 +423,12 @@ GameScene::GameScene(Config config)
hud_->setPyramidRoom(mgr.currentPyramid(), mgr.currentRoom());
}
// Música de fons en bucle infinit. El track ja està al Resource::Cache
// (preload al Director), així que playMusic només mou el punter cap a
// jail_audio i obri l'stream. Audio::get() està garantit no-null:
// Director::init crida Audio::init abans d'instanciar GameScene.
Audio::get()->playMusic(config_.music_track, -1);
// La música de fons no s'arrenca ací: la sala comença a ROOM_INTRO,
// que és silenciós per disseny. La música la posa en marxa
// `setState(PLAYING)` quan la cinemàtica acaba (i la torna a aturar
// `enterRoomIntro` quan entrem a una nova sala). El track ja està
// al Resource::Cache (preload al Director), per tant la primera
// crida a playMusic és immediata.
// Font de l'overlay de pausa: reutilitzem la Surface ja cachejada al
// Director (PLACEHOLDER_NAME + ".gif"). Text només parseja el .fnt a
@@ -448,6 +449,17 @@ GameScene::GameScene(Config config)
// vegada; canvis requereixen reiniciar el joc.
transition_config_ = RoomFsm::loadConfig(Defaults::GameScene::CONFIG_YAML);
// Preload del so del rètol d'INTRO (no hi ha manifest de sons; el
// pack agafa tot `data/` automàticament i ací registrem la clau
// al Resource::Cache perquè Audio::playSound la trobe). Si el camp
// del YAML està buit, no carreguem res — el dispar consultarà el
// cache i caurà al silenci sense crash.
if (!transition_config_.intro_text_sound.empty()) {
Resource::Cache::get().loadSound(
transition_config_.intro_text_sound,
"data/sounds/" + transition_config_.intro_text_sound);
}
// Log d'estat inicial: la FSM arrenca a ROOM_INTRO. En aquesta fita
// les transicions són instantànies (sense fades ni text) i el primer
// tick d'`updateRoomTransition` ja saltarà a PLAYING.
@@ -537,6 +549,13 @@ void GameScene::enterRoomIntro() {
transition_ = {};
room_intro_elapsed_ms_ = 0;
players_spawned_in_intro_.fill(false);
intro_text_sound_played_ = false;
// La cinemàtica d'entrada és silenciosa per disseny: és INTRO qui
// posseeix l'aturada. L'OUTRO no toca la música — així el cicle
// OUTRO → INTRO transmet la sensació de "tall" en entrar a la sala
// nova, no de "fade-out" anterior. Si ja no sona res, stopMusic és
// no-op.
if (Audio::get() != nullptr) { Audio::get()->stopMusic(); }
}
void GameScene::triggerPlayerSpawn(std::size_t slot_index) {
@@ -575,6 +594,13 @@ void GameScene::setState(RoomFsm::State new_state) {
if (new_state == RoomFsm::State::ROOM_INTRO) {
room_intro_elapsed_ms_ = 0;
players_spawned_in_intro_.fill(false);
intro_text_sound_played_ = false;
}
// En sortir d'INTRO cap a PLAYING, la música arrenca: és el moment
// en què la cinemàtica d'entrada acaba i el jugador agafa control.
// L'OUTRO no atura la música; ho fa el següent `enterRoomIntro`.
if (new_state == RoomFsm::State::PLAYING && Audio::get() != nullptr) {
Audio::get()->playMusic(config_.music_track, -1);
}
// L'avanç de sala (OUTRO → INTRO) NO viu ací: el dispara
// `updateRoomTransition` quan la FSM detecta el final de l'OUTRO,
@@ -610,6 +636,17 @@ void GameScene::updateRoomTransition(int delta_ms) {
}
const auto NEXT = RoomFsm::advance(state_, transition_, transition_config_, delta_ms);
// Disparador del so del rètol: la FSM acaba d'avançar; si estem a
// INTRO i ja hem deixat enrere phase 0 (fade_in), reproduïm el so
// una sola vegada. El so es dispara al final del fade-in, anticipant
// el text que apareix a phase 2 (text_enter): així sembla que el so
// "anuncia" l'arribada del rètol enlloc de coincidir amb la seva
// entrada visual.
if (state_ == RoomFsm::State::ROOM_INTRO && transition_.phase >= 1 && !intro_text_sound_played_ && !transition_config_.intro_text_sound.empty() && Audio::get() != nullptr) {
Audio::get()->playSound(transition_config_.intro_text_sound, Audio::Group::GAME);
intro_text_sound_played_ = true;
}
if (NEXT != state_) {
// El final de l'OUTRO no es resol amb un setState normal: cal
// demanar al LevelManager el següent nivell i carregar-lo abans