このチュートリアルでは、Unityでオーディオファイルを再生する方法、そして特に、Audio Sourceから音声が重複して再生されてしまう問題をどのように解決したかをご紹介します。


このチュートリアルの動画版は、現在この言語では利用できません。


動画の書き起こし

みなさん、こんにちは。このチュートリアルでは、Unityでオーディオファイルを再生する方法、そして特に、Audio Sourceから音声が重複して再生されてしまう問題をどのように解決したかをご紹介します。なお、この動画で紹介している解決方法は、私がこの問題に対して採用した一例にすぎません。他にも別の、あるいはより良い方法がある可能性がありますので、ここでの内容を唯一の正解として受け取らないでください。

このチュートリアルはUnity 2022を使用して作成しました。具体的には、シーン内でキャラクターが移動したときに足音のオーディオファイルを再生したいと考えています。使用する音声は、Jordan Mechnerによる最初のPrince of Persiaからのもので、これは私にとって初めてのPCゲーム体験でした。一見すると簡単そうな処理ですが、実際には小さな課題が隠れています。

足音を再生するための最初のステップは、キャラクターにAudio Sourceオブジェクトをアタッチすることです。このオブジェクト内で、再生するオーディオファイルを指定し、その他の再生プロパティを設定します。

Audio Sourceは、シーン内のオブジェクトに追加する必要があるコンポーネントです。キャラクター、ドア、ボール、あるいは不可視オブジェクトなど、どのオブジェクトにも追加できます。たとえば、キャラクターが特定の部屋に入ったときや、特定のアイテムに近づいたときに音を再生する場合にも利用できます。

音声をMain Cameraで聞くためには、Cameraに有効なAudio Listenerコンポーネントが必要です。新規のUnityプロジェクトでは、通常Main CameraにAudio Listenerが最初から有効な状態で追加されています。これは、ユーザーが音声を再生したいと想定されているためです。もしAudio Listenerが存在しない場合は、Main CameraオブジェクトのInspectorから追加できます。

今回のケースでは、オーディオファイルはキャラクターに関連付ける必要があります。

私のプロジェクトでは、PlayerオブジェクトがMain Cameraの親オブジェクトになっています。移動スクリプトはPlayerに関連付けられており、カメラには視点操作用のスクリプトが追加されています。そのため、AudioSourceコンポーネントはPlayerオブジェクトに追加します。

新しく追加したコンポーネントのタブを開くと、最初にAudioClipフィールドが表示されます。このフィールドは初期状態ではNoneになっています。

また、Play on Awakeというチェックボックスがあり、これはデフォルトで有効になっています。このオプションは、ゲーム開始時に音声を再生するためのものです。場合によっては便利ですが、今回の用途では不要なのでチェックを外します。

オーディオクリップをプロジェクトにインポートするのは簡単です。File BrowserウィンドウからオーディオファイルをProjectタブにドラッグするか、AssetsからImport New Assetを選択してディスクから読み込みます。

Unityはmp3などさまざまなオーディオ形式に対応しており、Project内では音符アイコンで表示されます。

ご覧のとおり、私のプロジェクトにはすでに複数のオーディオファイルがあります。その中で今回使用するのは「PoP---walk」です。

まずHierarchyでPlayerを選択します。

次に、Project内のPoP---walkアセットをクリックしてボタンを押したままにします。

そのまま、この要素をPlayerに関連付けられているAudioSourceコンポーネントのAudioClipボックスへドラッグします。

先ほど述べたように、音はキャラクターが移動したときに再生される必要があります。

そのため、キャラクターの移動を管理しているスクリプトを開き、必要なコードを追加します。

まず、AudioSource型の変数を作成し、Start関数内でPlayerのAudioSourceコンポーネントと関連付けて初期化します。

次のコードを書きます。

private AudioSource playerAudioSource;

そしてStart関数の中に次のように記述します。

playerAudioSource = GetComponent();

さらに、再生するオーディオファイルを関連付けるためのAudioClip変数も作成します。この変数をmyAudioClipと名付け、Inspectorで表示させたいのでSerializeField属性を使用します。

スクリプトを保存したら、Inspector内のスクリプトにあるmyAudioClipフィールドへ「PoP---Walk」アセットをドラッグします。

playerAudioSourceの定義の直後に、次のコードを書きます。

[SerializeField] private AudioClip myAudioClip;

スクリプトを保存したらUnity Editorに戻り、先ほど説明したとおり「PoP---Walk」アセットをmyAudioClipフィールドへドラッグします。

現時点では、音声はまだ再生されません。

スクリプトのUpdate関数には、ユーザーのキー入力を検出する処理がすでに書かれており、それによってキャラクターを移動させています。

具体的には、キャラクターが移動すると、Input.GetAxisのHorizontalとVerticalの値は、方向に応じて-1または1になります。ここでは便宜上、それらをxとyと呼びます。

この場合、次のように書くことができます。

if ((Mathf.Abs(x) == 1) || (Mathf.Abs(z) == 1))

playerAudioSource.PlayOneShot(myAudioClip);

そしてゲームを実行してみたくなるかもしれません。しかし、これは大きな間違いです。Unityはゲームの毎フレームごとにオーディオファイルを再生してしまいます。

PlayOneShotをCoroutineの中に移動し、yield return new WaitForSeconds(1)で1秒待機させたとしても結果は改善しません。Updateは毎フレームCoroutineを呼び出すため、同じ問題が発生します。

したがって、Coroutineは不要です。必要なのは、AudioSourceに対してシンプルなチェックを行うことです。AudioSourceがすでに再生中でない場合にのみ音声を再生します。

Update関数内のifブロックに、次のコードを追加します。

if (!(playerAudioSource.isPlaying))

playerAudioSource.PlayOneShot(myAudioClip);

これでスクリプトを保存し、ゲームを実行して結果を確認できます。ぜひ音を聞いてみてください。

最後に一つ補足です。AudioSourceコンポーネントのAudioClipフィールドは、スクリプトから変更することも可能です。

つまり、通常の足音を再生しつつ、キャラクターが砂利の上や海岸線など異なる地面を歩いている場合には、Colliderを使って判定し、再生するオーディオクリップを別のものに差し替えることができます。

さらに、キャラクターが飛行できる場合は、AudioSourceを無効にして音が再生されないようにすることも可能です。

以上でこのチュートリアルは終了です。お役に立てば幸いです。それでは、またお会いしましょう。

このサイトは、私の制作物の一部を紹介することのみを目的としており、宣伝目的ではありません。現在、カスタム制作、コンサルティング、その他いかなる業務上の協力に関するご依頼も受け付けておらず、対応いたしませんので、あらかじめご了承ください。


プライバシー及びクッキーの使用に関する拡張情報の通知