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

1 / 4 SoundManagerで音声を所有する

このステップの目的

音声ハンドルを画像と同じようにManagerへ集約し、ゲーム中のクラスから直接扱わない

音声IDを定義する

ゲーム内では、音声ファイル名ではなくSoundManager::Idを使います。 タイトルBGM、プレイ中BGM、射撃や命中のSEを意味で区別します。

SoundManager.hcpp
enum class Id
{
    TitleBgm,
    PlayingBgm,
    Shot,
    Hit,
    Damage,
    Clear,
    GameOver,
    Count
};

画像と同じように、IDとファイルパスの対応表を用意します。

SoundManager.cppcpp
using SoundId = SoundManager::Id;

struct SoundEntry
{
    SoundId id;
    const wchar_t* path;
};

constexpr std::array<SoundEntry, static_cast<std::size_t>(SoundId::Count)> SoundTable =
{
    SoundEntry { SoundId::TitleBgm, L"Assets/Sounds/TitleBgm.wav" },
    SoundEntry { SoundId::PlayingBgm, L"Assets/Sounds/PlayingBgm.wav" },
    SoundEntry { SoundId::Shot, L"Assets/Sounds/Shot.wav" },
    SoundEntry { SoundId::Hit, L"Assets/Sounds/Hit.wav" },
    SoundEntry { SoundId::Damage, L"Assets/Sounds/Damage.wav" },
    SoundEntry { SoundId::Clear, L"Assets/Sounds/Clear.wav" },
    SoundEntry { SoundId::GameOver, L"Assets/Sounds/GameOver.wav" }
};

ImageManagerとの対応

音声Managerも、対応表を走査して読み込み、デストラクタまたは解放関数でハンドルを解放します。 LoadSoundMem()DeleteSoundMem()GameやEntityから直接呼びません。

読み込み処理は対応表を順に走査し、失敗した時点で対象パスを返します。

SoundManager.cppcpp
std::size_t ToIndex(SoundId id)
{
    return static_cast<std::size_t>(id);
}

for (const SoundEntry& entry : SoundTable)
{
    const std::size_t index = ToIndex(entry.id);
    handles[index] = LoadSoundMem(entry.path);
    if (handles[index] == -1)
    {
        Release();
        return { false, entry.path };
    }
}

音声が必須素材であることも画像と同じです。 読み込みに失敗したらゲームを開始せず、対象パスを確認できるようにします。

チェックリスト
  • 音声の種類をIdで表している
  • 音声ハンドルをSoundManagerが所有している
  • 音声の直接読み込みをGameやEntityへ置いていない