DXライブラリとC言語で3Dゲーム制作。今回はBGMや効果音を鳴らす方法について。BGMのループ再生にも対応。
BGMや効果音を鳴らしたい
3Dモデルや画像の表示も大事だがBGMや効果音を鳴らすこともゲームを支える大事な要素。雰囲気づくりのためには欠かせない。アセットフリップを乱用した粗悪なゲームにはないことも多いが
BGMや効果音などの音声ファイルを読み込みには LoadSoundMem() を使用する。読み込める音声ファイルの形式はwav, mp3, ogg, opusの4つ。
宣言:int LoadSoundMem(char *FileName);
引数:FileName 読み込みたい音声ファイルのパス
戻り値:-1 エラー
-1以外 成功(サウンドハンドルの識別番号)
読み込んだ音声ファイルを再生するには PlaySoundMem() を使用する。
宣言:int PlaySoundMem(int SoundHandle, int PlayType, int TopPositionFlag);
引数:SoundHandle 再生するサウンドハンドル
PlayType 再生形式
DX_PLAYTYPE_NORMAL ノーマル再生
DX_PLAYTYPE_BACK バックグラウンド再生
DX_PLATTYPR_LOOP ループ+バックグラウンド再生
TopPositionFlag 再生位置を音声ファイルの先頭に移動するかどうか
TRUE:移動する FALSE:移動しない
戻り値:0 成功
:-1 エラー発生
読み込んだ音声ファイルを削除したい場合は DeleteSoundMem() を使用する。
宣言:int DeleteSoundMem(int SoundHandle);
引数:SoundHandle 削除するサウンドハンドル
戻り値:0 成功
-1 エラー発生
実装
それでは実装。とりあえず1つの効果音を鳴らすコード。まず音声ファイルを扱う専用のSound.cpp/hを作成して以下のようにする。
Sound.h
#ifndef DEF_SOUND_H #define DEF_SOUND_H void Sound_Initialize(); void Sound_Update(); void Sound_Play(); void Sound_Finalize(); #endif
Sound.cpp
#include "DxLib.h" #include "Sound.h" #include "Define.h" const static int SOUND_NUM = 4; //音声ハンドルの最大数 static int SrcSoundHandle; //音声ファイルハンドル static int SoundHandle[SOUND_NUM]; //実際に鳴らす音声ハンドル //初期化 void Sound_Initialize() { //音声ファイルの読み込み SrcSoundHandle = LoadSoundMem("読み込みたい音声ファイルのパス"); for (int i = 0; i < SOUND_NUM; i++) { SoundHandle[i] = DuplicateSoundMem(SrcSoundHandle); } } //更新 void Sound_Update() { } //再生 void Sound_Play() { //音声を再生する。すでに再生中だった場合はしない for (int i = 0; i < SOUND_NUM; i++) { if (CheckSoundMem(SoundHandle[i]) == 0) { PlaySoundMem(SoundHandle[i], DX_PLAYTYPE_BACK); break; } } } //終了処理 void Sound_Finalize() { //音声ハンドルの削除 for (int i = 0; i < SOUND_NUM; i++) { DeleteSoundMem(SoundHandle[i]); } DeleteSoundMem(SrcSoundHandle); }
音を鳴らすとき1つのサウンドハンドルを連続で鳴らすと音の鳴り方が変になるのでサウンドハンドルは複数用意しておく。サウンドハンドルを複製するときは DuplicateSoundMem() を使って複製する。
宣言:int DuplicateSoundMem(int SrcSoundHandle)
引数:SrcSoundHandle 複製したいサウンドハンドル
戻り値:-1以外 サウンドハンドル
-1 エラー発生
次に CheckSoundMem() で再生中かどうかを確認し、再生中であれば次のサウンドハンドルを鳴らすようにしている。音を鳴らすときは再生形式にDX_PLAYTYPE_BACKと指定すること(NORMALだと他の処理が行われない)。
宣言:int CheckSoundMem(int SoundHandle);
引数:SoundHandle 再生中か調べたいサウンドハンドル
戻り値:1 再生中
0 再生されていない
-1 エラー発生
最後に DeleteSoundMem() でサウンドハンドルを削除する。
次にGame.cppに以下のコードを追加する。
Game.cpp
//以下をインクルードに追加 #include "Sound.h" //初期化 void Game_Initialize() { //中略 //音声の情報初期化 SoundMng_Initialize(); } //終了処理 void Game_Finalize() { //中略 SoundMng_Finalize(); }
あとは音を鳴らしたいタイミングのところに Sound_Play() を書く。
BGMをループ再生したい場合
BGMをループ再生したい場合は読み込みたいBGMの音声ファイルと同じ場所に「(音声ファイルの名前)_loop.txt」を作成し、そのtxtファイル内にループ開始位置となるLOOPSTARTとループ範囲の長さとなるLOOPLENGTHを半角文字で書きこむ。あとは音声ファイルを読み込むときに勝手にtxtファイルが読み込まれる。
開始位置とループ範囲で指定する値は秒数*サンプル数(44.1kHzなら44100)となっている。
例:44.1kHzのBGMのループ開始位置を10秒後、ループ範囲を60秒にしたい場合は以下のようにする。
LOOPSTART=441000
LOOPLENGTH=2646000
あとはループ再生したいサウンドハンドルをPlaySoundMem()で再生する際に再生形式をDX_PLAYTYPE_LOOPと指定する。
BGMのサンプル数わからん!という人は無料の音声編集ソフト(SoundEngineなど)を使って確認。