続いて効果音(SE)について説明します。
効果音はゲームにとって重要な音の1つです。
広い意味での「手ごたえ」も効果音で表現する事が出来ます。
※敵に弾が当たったとかボタンを押したとか色々ですね・・・
効果音も音源データのファイルを用意する必要があります。
※このシステムで使用可能な効果音データは「wav」形式のみです。
今回も「魔王魂」様に頼ります。
「魔王魂」様の効果音素材、システム音にある「システム12」をwav形式でダウンロードしました。
ダウンロードしたファイルは、プロジェクトフォルダの「Resource\\SEフォルダ」に入れておきます。
私が選んだ曲のファイル名は「se_maoudamashii_system12.wav」でした。
効果音もリソース(資源)の1つですから、テクスチャ(画像)と同じように扱います。
「GameBase.h」を開き、パス付ファイル名を定数化しましょう。
//----------------------------------------------------------------------------- //ゲーム中で使用するテクスチャ、BGM、SE、フォントのパス付ファイル名を書きます。 //----------------------------------------------------------------------------- namespace KeyString { const std::string TEXTURE_SAMEGAME = "Resource\\Texture\\Samegame.png"; const std::string BGM_GAME = "Resource\\BGM\\game_maoudamashii_7_event45.mp3"; const std::string SE_CLICK = "Resource\\SE\\se_maoudamashii_system12.wav"; } |
マウスのクリック音として使いたいので「SE_CLICK」と言う名前にしました。
「SceneGame.cpp」の「Start関数」で効果音を追加します。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { m_pEngine->AddTexture(TEXTURE_SAMEGAME); m_pEngine->AddSE(SE_CLICK); m_pEngine->LoadBGM(BGM_GAME); m_pEngine->PlayBGM(); m_samegame.Initialize(4); m_bStalemate = false; } |
効果音は一度に複数の音を再生する事がありますので、Add(追加)出来るように作っています。
効果音の再生には「PlaySE関数」を使います。
BGMと違い、何かのアクションに合わせて再生させますので、再生する場所が大事です。
今回はクリック音として使おうと思っていますが、ブロックを消した時に鳴るようにしたいと思います。
ブロックが消えるのは、Samegaraクラスの「DeleteBlock関数」です。
すでにシステムには効果音を追加していますので、エンジンさえあれば効果音を再生出来ます。
そこで、「DeleteBlock関数」に引数を追加します。
「Samegame.h」を開き、「DeleteBlock関数」に引数を追加します。
//ブロックの選択 void SelectBlock(POINT &refPoint); //ブロックを消す void DeleteBlock(Engine *pEngine); //手詰まりチェック bool IsStalemate(); |
「Samegame.cpp」にある本体にも追加しましょう。
//ブロックを消す void Samegame::DeleteBlock(Engine *pEngine) { if (m_selectBlockNum <= 1) { return; } DeleteSelectBlock(); FallBlock(); SlideLine(); m_score += (m_selectBlockNum - 2) * (m_selectBlockNum - 2); } |
「SceneGame.cpp」の「Update関数」の関数呼び出しに引数を追加します。
if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) {
if (!m_bStalemate) {
m_samegame.DeleteBlock(m_pEngine);
}
else {
m_nowSceneData.Set(Common::SCENE_EXIT, false, NULL);
}
}
|
これで「DeleteBlock関数」にエンジンを渡す事が出来るようになりました。
「Samegame.cpp」の「DeleteBlock関数」を開き、効果音の再生を追加しましょう。
//ブロックを消す void Samegame::DeleteBlock(Engine *pEngine) { if (m_selectBlockNum <= 1) { return; } DeleteSelectBlock(); FallBlock(); SlideLine(); m_score += (m_selectBlockNum - 2) * (m_selectBlockNum - 2); pEngine->PlaySE(SE_CLICK); } |
BGMと違い複数の効果音が追加出来るので、どの効果音を再生するか引数で渡す必要があります。
それでは、実行して試してください。
マウスをクリックする度に音が鳴るようになればOKです。
上に書いたようにブロックを消す時に効果音を出したいのですが、ブロックの無い部分でクリックしてもたまに音が鳴ります。
このバグの原因を考え対処していきます。
文字で伝えるのは難しいですが、状況を書きます。
「DeleteBlock関数」を再度表示します。
//ブロックを消す
void Samegame::DeleteBlock(Engine *pEngine)
{
if (m_selectBlockNum <= 1) {
return;
}
DeleteSelectBlock();
FallBlock();
SlideLine();
m_score += (m_selectBlockNum - 2) * (m_selectBlockNum - 2);
pEngine->PlaySE(SE_CLICK);
}
|
この関数はマウスの左ボタンを押した時に呼び出されます。
場所のチェックはしていませんので、どこでボタンを押しても呼び出されるのです。
ここでやっているのは、現在2個以上のブロックが選択されていた場合、そのブロックを消すと言う事です。
2個以上選択されているかどうかは「m_selectBlockNum」を調べて判定しています。
この変数は「SelectBlock関数」で毎回更新されていますが、空いているブロックの上では更新されません。
例えば、3個つながっているブロックの上にマウスカーソルを合わせると「m_selectBlockNum」は3になります。
その後、空いているブロックの上にカーソルを移動させても「m_selectBlockNum」は更新されないので3のままです。
そのまま左ボタンを押すと、(実際にブロックが消される事はありませんが)「DeleteBlock関数」が呼び出され、効果音が再生されます。
結局「m_selectBlockNum」が更新されていない事が原因で発生しているバグです。
ちゃんと「DeleteBlock関数」でも座標を取得し、隣接したブロックの数を更新出来るようにする必要があります。
「Samegame.h」を開き、「DeleteBlock関数」の引数を追加します。
//ブロックの選択 void SelectBlock(POINT &refPoint); //ブロックを消す void DeleteBlock(Engine *pEngine, POINT &refPoint); //手詰まりチェック bool IsStalemate(); |
「Samegame.cpp」を開き、「DeleteBlock関数」に次のコードを追加しましょう。
//ブロックを消す void Samegame::DeleteBlock(Engine *pEngine, POINT &refPoint) { if (IsOutsideField(refPoint)) { return; } int x = (refPoint.x - BLOCK_DEST_X) / BLOCK_WIDTH; int y = (refPoint.y - BLOCK_DEST_Y) / BLOCK_HEIGHT; if (m_field[y][x].m_color == NO_BLOCK) { return; } ClearSelectFlag(); CheckAround(x, y, m_field[y][x].m_color); m_selectBlockNum = GetSelectBlockNum(); if (m_selectBlockNum <= 1) { return; } DeleteSelectBlock(); FallBlock(); SlideLine(); m_score += (m_selectBlockNum - 2) * (m_selectBlockNum - 2); pEngine->PlaySE(SE_CLICK); |
「SelectBlock関数」と同じように、現在のカーソル位置を元に処理出来るように変更しました。
「SceneGame.cpp」を開き、「Update関数」の「DeleteBlock関数」に引数を追加します。
if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) {
if (!m_bStalemate) {
m_samegame.DeleteBlock(m_pEngine, point);
}
else {
m_nowSceneData.Set(Common::SCENE_EXIT, false, NULL);
}
}
|
これで実行して確認してください。
効果音の停止は「StopSE関数」で行います。
「PlaySE関数」同様、どの効果音を停止するか、引数で渡す必要があります。
「SceneGame.cpp」の「Exit関数」で呼び出してみましょう。
//============================================================================= // シーンの終了時に呼び出される終了処理関数 //============================================================================= void SceneGame::Exit() { m_pEngine->StopSE(SE_CLICK); m_pEngine->StopBGM(); m_pEngine->ReleaseBGM(); } |
もう1つ、全ての効果音を停止させる「StopAllSE関数」も用意しています。
こちらは引数は不要です。
シーンの切り替え時に効果音を全て停止する際は、この関数の方が向いています。
「Exit関数」を書き換えてみます。
//============================================================================= // シーンの終了時に呼び出される終了処理関数 //============================================================================= void SceneGame::Exit() { m_pEngine->StopAllSE(); m_pEngine->StopBGM(); m_pEngine->ReleaseBGM(); } |
効果音の解放は「ReleaseSE関数」を使います。
システムには複数の効果音が追加出来ますが、不要な効果音はメモリから削除した方が良いと思います。
「Exit関数」にコードを追加してみます。
//============================================================================= // シーンの終了時に呼び出される終了処理関数 //============================================================================= void SceneGame::Exit() { m_pEngine->StopAllSE(); m_pEngine->ReleaseSE(SE_CLICK); m_pEngine->StopBGM(); m_pEngine->ReleaseBGM(); } |
これで「さめがめ」も終了です。
今回は「音」についても触れましたので、タイトルやエンディングなどもBGMを追加したり出来そうです。
いつも通り、シーンの追加は皆さんでチャレンジしてください。