第09回 音声の管理と再生
3 / 4 戦闘イベントと効果音の連動
このステップの目的
射撃、命中、被弾などのゲーム内イベントが「成立した瞬間」を検知し、効果音(SE)を鳴らす処理を接続します。
キー入力ではなく「イベントの成立」で効果音を鳴らす
効果音は、操作を受け付けたことや、ゲーム内で出来事が起きたことをプレイヤーへ伝えます。結果を知らせるための重要な手段です。
効果音を鳴らすタイミングには注意が必要です。
射撃キーを押したときに音を鳴らすと、クールダウン中や弾数の上限に達したときも音だけが出ます。弾が出たと誤解させ、操作を信頼できなくなります。
効果音は、処理が実際に成立したときだけ再生します。
射撃SEの再生
Player::TryShoot()は、発射間隔のタイマーを満たし、プールの空きスロットに弾が実際に生成できた場合のみtrueを返します。
この戻り値を調べて、trueのときだけ射撃効果音を鳴らします。
Game.cppcpp
// 弾の生成に成功した場合のみ、射撃音を再生する
if (player.TryShoot(input, playerShots))
{
sounds.PlaySe(SoundId::Shot);
}効果音には、非同期のバックグラウンド再生(DX_PLAYTYPE_BACK)を使います。再生中も、ゲームの進行や次の射撃を止めずに済みます。
命中・被弾SEの接続
同様に、敵への命中やプレイヤーの被弾も、Game::ResolveCollisions()内で出来事が確定した瞬間に効果音を再生します。
Game.cppcpp
void Game::ResolveCollisions()
{
// プレイヤーの弾は最初に重なった敵だけに命中させる
for (PlayerShot& playerShot : playerShots.GetAll())
{
if (!playerShot.IsActive())
continue;
for (Enemy& enemy : enemies.GetAll())
{
if (!enemy.IsActive())
continue;
if (!playerShot.GetHitbox().Overlaps(enemy.GetHitbox()))
continue;
enemy.TakeDamage(tuning::playerShot::Damage);
playerShot.Deactivate();
if (!enemy.IsActive())
++score;
sounds.PlaySe(SoundId::Hit);
break;
}
}
for (EnemyShot& enemyShot : enemyShots.GetAll())
{
if (!enemyShot.IsActive())
continue;
if (!enemyShot.GetHitbox().Overlaps(player.GetHitbox()))
continue;
enemyShot.Deactivate();
if (player.TryTakeDamage())
sounds.PlaySe(SoundId::Damage);
}
for (Enemy& enemy : enemies.GetAll())
{
if (!enemy.IsActive())
continue;
if (!enemy.GetHitbox().Overlaps(player.GetHitbox()))
continue;
enemy.Deactivate();
if (player.TryTakeDamage())
sounds.PlaySe(SoundId::Damage);
}
}被弾SEは、player.TryTakeDamage()がtrueを返したときだけ鳴らします。無敵時間中に敵弾が当たると、弾は消えますが被弾SEは鳴りません。ダメージを受けていないことが、音からも分かります。
チェックリスト
- キー入力の瞬間ではなく、弾が生成されたときのみ射撃音が鳴ることを確認できる
- 敵に弾が当たった瞬間に命中音が鳴ることを確認できる
- 無敵時間中に接触しても被弾音が鳴らず、成立時のみ鳴ることを確認できる
- 効果音が非同期(
DX_PLAYTYPE_BACK)で再生され、ゲームのテンポを阻害しないことを理解している