TNP資料室 @ ウィキ

sound.cppについて

最終更新:

Bot(ページ名リンク)

- view
だれでも歓迎! 編集

sound.hについて

 BGM制御構造体の定義と効果音の制御構造体の定義、それぞれの配列の添え字用の列挙型が用意されています。長いのでBGMと効果音に分けて説明します。


enum eBGM_INDEX{
	BGM_TITLE,BGM_GAMEMAIN,BGM_GAMECLEAR,BGM_GAMEOVER
};

// BGMコントロール
const int BGM_NUM = 16;		// BGMの数
struct SBgmControl{
	bool PlayFlag;			// 再生中かどうか
	int NowPlayIndex;		// 再生中の添え字
	struct{
		int Handle;			// ハンドル
		int Count;			// 再生時間(フレーム)
	}Bgm[BGM_NUM];			// BGMの数だけ用意する

	void Process();			// 全体処理
	void FirstInit();		// 最初の初期化
	void ChangePlay(int HandleIndex = -1 );	// 引数のBGMを再生する。
	void Load();			// ファイルロード
};
 まず列挙型の定義で配列の添え字を定義しています。追加するときは分かりやすい名前をつけましょう。次にconst指定でBGMの最大数を指定しています。必要なら増やして、いらないなら減らしてください。
 構造体の中身、主に変数の役割を見ていきます。
PlayFlagは、どの曲にせよ再生しているかどうかを記憶する変数です。何かを再生している場合を真(true)、再生していない場合を偽(false)としています。
NowPlayIndexは、現在再生中の音声ハンドルが格納されている配列の添え字です。もしタイトルのBGMが再生されている場合、この変数の値はBGM_TITLEとなるわけです。曲を停止したい場合、この添え字の番号を用いてDXライブラリの関数を用いて停止します。
 さて、次の構造体はBGM構造体です。型の定義と宣言を同時に行っています。文法的な説明は省きます。とにかく、型の定義と宣言を同時に行っているのです。また、BGM構造体はBGMの数だけ用意します。
BGM構造体のHandleは、音声ファイルのハンドルを格納する変数です。
Countは曲が再生されてからの経過時間を記憶する変数です。
 さて、ChangePlay関数の引数を見てください。引数に-1を代入するような記述をしていますね。これは引数を省略して関数を呼び出した場合、この-1の値を引数として呼び出したものとして扱うという意味を持ちます。これをデフォルト引数といいます。この=-1という記述は関数のプロトタイプ宣言にのみ書き、関数の定義には書きません。関数の動作の説明は下で。

次は効果音の部分を見ていきます。
enum eSE_INDEX{
	SE_PIPIPI , SE_BELL , SE_BOM_LONG , SE_BOM_SHORT
};

// SEコントロール
const int SE_NUM = 16;		// SEの数
struct SSeControl{
	struct {
		int Handle;
		int Interval;
		int Count;
	}Se[SE_NUM];
	void Process();			// 全体処理
	void FirstInit();		// 最初の初期化
	void Play(int HandleIndex);
	void Load();			// ファイルロード
};
 BGM同様、添え字を列挙型で定義しています。列挙型なしで0,1,2とかで管理すると時間を置いて見直したとき非常に戸惑います。経験談です。そのあと、効果音の数を定義しています。
 Se構造体のメンバ変数についてみていきます。
Handleは音声ファイルのハンドルを格納する変数です。
Intervalは、1度再生されたら次に再生するまでの最低待ち時間です。もしこれを設定しないと、ゲームによっては1フレームごとに効果音がなってしまい、うまく機能しない場合があります。たとえば弾幕シューティングゲームです。純粋に弾の発射ごとに効果音を再生してしまうと音が重なりすぎて聞き取ることが出来なくなるのです。Intervalが5なら1度鳴らされたら5フレーム間は鳴らさないという処理を実現しています。
Countは次に再生可能状態になるまでのカウントダウンをするための変数です。上のIntervalと組み合わせて使用します。2変数の詳しい動作は関数の説明のときにします。

BGM制御構造体について

Process関数について

// 全体処理
void SBgmControl::Process(){
	if( PlayFlag == true ){					// 再生中なら
		Bgm[NowPlayIndex].Count++;			// 再生時間を更新
	}
}
 この関数はMainLoop関数からループごとに呼び出されます。もしBGMを再生しているのであれば、その再生時間を記憶するというものです。

ChangePlay関数について

// 再生BGMを変える、とめる
void SBgmControl::ChangePlay(int HandleIndex){
	if( HandleIndex == -1 ){						// 引数の指定が無ければ
		PlayFlag = false;							// 再生停止
		StopSoundMem(Bgm[NowPlayIndex].Handle);		// 音声を止める
		return;
	}
	else{
		if( PlayFlag == true )						// 今まで何か再生していたか
			StopSoundMem( Bgm[NowPlayIndex].Handle ) ;	// 再生していたのなら停止する
		PlayFlag = true;								// 再生中
		NowPlayIndex = HandleIndex;						// 新しいハンドルを格納
		PlaySoundMem(Bgm[NowPlayIndex].Handle,DX_PLAYTYPE_BACK);	// 再生
		Bgm[NowPlayIndex].Count = 0;					// 再生時間を初期化
	}
}
 さて、上で説明があったように、引数を省略してこの関数を呼び出したとき、-1を引数として呼び出したものとして扱われます。もし引数を省略して呼び出した場合、最初のif文の条件式を満たし、処理を行います
最初のif文の処理は再生中のBGMをとめるというものです。まず、再生中かどうかのフラグを最中でないとします。そして、DXライブラリの関数に再生中の音声のハンドルを渡して音声を停止します。NowPlayIndexはBgm構造体の添え字ですハンドルとは違うので勘違いしないようにしましょう
 さて、この関数に変更したいBGMの添え字が引数として呼び出された場合、elseの処理を行います
 まず今までなにかしらBGMを再生していたかどうかを調べますもし何かを再生していたのならそのBGMを停止します
次にPlayFlagを立て、再生中であることを示します
引数を構造体の変数に代入し、新しいBGMの添え字を記憶します
そのハンドルをDXライブラリの関数に渡し、BGMを再生します
再生時間を記憶する変数を初期化します。単位はフレームです。

FirstInit関数について

// 最初の初期化
void SBgmControl::FirstInit(){
	memset(this,0,sizeof(SBgmControl));
}
 全部0で埋めて終わりです。

Load関数について

// 音楽ファイルをロードする
void SBgmControl::Load(){
	Bgm[BGM_TITLE].Handle		= LoadSoundMem("music/title.mp3");
	SetLoopPosSoundMem(0,Bgm[BGM_TITLE].Handle);

	Bgm[BGM_GAMEMAIN].Handle	= LoadSoundMem("music/game_main.mp3");
	SetLoopPosSoundMem(0,Bgm[BGM_GAMEMAIN].Handle);

	Bgm[BGM_GAMECLEAR].Handle	= LoadSoundMem("music/game_clear.mp3");
	SetLoopPosSoundMem(0,Bgm[BGM_GAMECLEAR].Handle);

	Bgm[BGM_GAMEOVER].Handle	= LoadSoundMem("music/game_over.mp3");
	SetLoopPosSoundMem(0,Bgm[BGM_GAMEOVER].Handle);
} 
それぞれの構造体に音声データを読み込んでいます。また、読み込んだ後にループ位置を指定しています。ループ位置は全て曲の先頭にしています。この関数の詳しい使い方に関しては本家サイトを見てください。

効果音制御構造体について

Process関数について

// 全体処理
void SSeControl::Process(){
	for(int i=0 ; i<SE_NUM ; i++){		// 全ての効果音
		if( Se[i].Count != 0 ){			// 再生したのなら
			Se[i].Count--;				// インターバル更新
		}
	}

	DrawString(20,20,"1~4を押すことで効果音が鳴ります",Black);
	if( Key[KEY_INPUT_1] == 1 ){
		Play(SE_PIPIPI);
	}
	if( Key[KEY_INPUT_2] == 1 ){
		Play(SE_BELL);
	}
	if( Key[KEY_INPUT_3] == 1 ){
		Play(SE_BOM_LONG);
	}
	if( Key[KEY_INPUT_4] == 1 ){
		Play(SE_BOM_SHORT);
	}
}
 この関数はMainLoop関数からループごとに呼び出されます。for文で全ての効果音構造体を調べ、1度再生されてから次の再生までのカウントダウンが0でないなら(つまりまだ待ち時間なら)そのカウントを減らす処理をしています。このCountが0のときのみその効果音を鳴らすことが出来ます。
 それ以降の処理はサンプル処理です。どのようにして再生関数を呼び出せばいいのか参考にしてください。引数に鳴らしたい効果音の添え字を渡せば実現できます。

FirstInit関数について

// 最初の初期化
void SSeControl::FirstInit(){
	memset(this,0,sizeof(SSeControl));	// 全ての変数を0にする
}
 全ての変数を0で埋めてるだけです。

Play関数について

// 再生する
void SSeControl::Play(int HandleIndex){
	if( Se[HandleIndex].Count == 0 ){		// 再生可能時間なら
		PlaySoundMem(Se[HandleIndex].Handle,DX_PLAYTYPE_BACK);		// 再生
		Se[HandleIndex].Count = Se[HandleIndex].Interval;	// 最小待ち時間を指定
	}
}
 この関数の引数に再生したい効果音の添え字を渡すことで効果音を鳴らすことが出来ます。添え字は列挙定数を用いると分かりやすいでしょう。
 ただし、再生したい効果音の1度鳴らしてからある程度の時間がたっている場合にのみ再生できます
 また、再生した場合はその効果音のCount変数に今からの待ち時間を代入します。この待ち時間は1フレームごとに1づつ減り、0になったら再び再生することが出来ます。それまでは再生することが出来ません。過度な連続再生防止処置です。

Load関数について

// 音楽ファイルをロードする
void SSeControl::Load(){
	Se[SE_PIPIPI].Handle	= LoadSoundMem("music/pipipi.wav");	// ロード
	Se[SE_PIPIPI].Interval	= 5;									// 最低待ち時間

	Se[SE_BELL].Handle		= LoadSoundMem("music/bell.wav");
	Se[SE_BELL].Interval	= 5;

	Se[SE_BOM_LONG].Handle		= LoadSoundMem("music/bom_long.wav");
	Se[SE_BOM_LONG].Interval	= 5;

	Se[SE_BOM_SHORT].Handle		= LoadSoundMem("music/bom_short.wav");
	Se[SE_BOM_SHORT].Interval	= 5;
}
それぞれの構造体に音楽ファイルをロードし、最低待ち時間を代入しています。この場合、全ての効果音は1度再生したら5フレーム間は再生することが出来ないようになっています。ここの数字は適当にいじってもらってかまいません。
+ タグ編集
  • タグ:
  • 音楽
  • 音声
  • sound
  • bgm
  • se
  • 効果音
ウィキ募集バナー