Skip to content
第09回 音声の管理と再生

2 / 4 状態遷移とBGMの切り替え ​

このステップの目的

ゲーム画面の遷移に合わせてBGMを切り替え、古い曲を停止して新しい曲をループ再生する仕組みを実装します。

BGMの二重再生を防ぐ制御 ​

BGMは通常、画面の雰囲気に合わせて1曲だけがループ再生されます。
前のBGMを止めずに次の曲を再生すると、2曲が同時に鳴ります。不快な音割れや不協和音の原因になります。

SoundManager::PlayBgm()では、現在の曲を必ず止めてから新しい曲を再生します。

SoundManager.cppcpp
void SoundManager::PlayBgm(Id id)
{
    // BGMは同時に1曲だけ再生する
    StopBgm();
    currentBgm = handles[ToIndex(id)];
    PlaySoundMem(currentBgm, DX_PLAYTYPE_LOOP);
}

void SoundManager::StopBgm()
{
    if (currentBgm == -1)
        return;

    StopSoundMem(currentBgm);
    currentBgm = -1;
}

未再生や停止中は-1で表します。この仕組みによって、いつPlayBgm()を呼んでも曲は重複しません。

ChangeState() によるBGM切り替えの一元化 ​

第07回で画面遷移をGame::ChangeState()へまとめたため、BGMの切り替えもこの関数に書けます。

Game.cppcpp
void Game::ChangeState(State nextState)
{
    state = nextState;

    // Stateに入ったときのBGMをここで切り替える
    switch (state)
    {
    case State::Title:
        sounds.PlayBgm(SoundId::TitleBgm);
        break;

    case State::Playing:
        sounds.PlayBgm(SoundId::PlayingBgm);
        break;

    case State::GameClear:
        sounds.StopBgm();
        sounds.PlaySe(SoundId::Clear);
        break;

    case State::GameOver:
        sounds.StopBgm();
        sounds.PlaySe(SoundId::GameOver);
        break;
    }
}

クリアやゲームオーバーへ移るときは、sounds.StopBgm()でプレイ中のBGMを止めます。その後、結果画面用のファンファーレや効果音を1回再生します。

画面遷移とBGMの制御を連動させるため、リトライしてもタイトルBGMが鳴り続けるような切り替え漏れは起きません。

チェックリスト
  • SoundManager::PlayBgm()が既存の曲を停止してから新しい曲を再生している
  • BGMの切り替え処理がGame::ChangeState()に集約されている
  • クリア画面およびゲームオーバー画面でプレイ中BGMが停止することを確認できる
  • タイトルへ戻った際、タイトルBGMが最初から正しく再生されることを確認できる