6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unreal Engine (UE)Advent Calendar 2021

Day 22

ADX2 + UE4でオープンワールド系ゲームを想定したBGMの実装

Last updated at Posted at 2021-12-21

はじめに

アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を使って、オープンワールド系のゲームを想定したBGMの実装をしてみます。

起伏に富んだ広大なフィールドを用意すれば、それだけプレイヤーがロケーションに滞在する時間も長くなります。
ずっと同じ曲調のBGMを流すだけでは、飽きを与えてしまうでしょう。

そこで、プレイヤーの行動やシチュエーションの変化に応じてBGMが変化する、「インタラクティブミュージック」を実装してみましょう。
「システムがプレイヤーの遊び方を監視し、うまく雰囲気を作ってあげる」イメージで、ゲームとBGMの雰囲気をあわせて上げる感じです。

次の画像はゲーム内での街から街への移動の雰囲気を想定したものです。
A00.png
色が変わっていく横線のように、各シチュエーションをブレンドしてBGMが移り変わるようにします。
街から出たばかりは冒険の始まりを予感させるように静かな雰囲気で、街を離れるにつれて本来のフィールド曲に遷移していきます。
途中で雨が降ってくれば静かで物悲しいフレーズをブレンドしていき、馬に乗ればパーカッションを追加し躍動感のあるBGMへと変化させていきます。
ダンジョンとの距離が近くなるごとに神秘的なBGMを混ぜ、空気の変化を表現します。
また別の街が近くなればBGMは徐々に静かになっていき、旅の終わりの安息を演出します。

当記事ではUE4.26.1を使用します。基本的にブループリントのみでの実装を想定しています。
ADX2はインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx2-le/

記事執筆時点のADX2 for UE4のSDKバージョンはv1_29です。

前提

ADX2 for UE4の導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
ADX2 for UE4の導入で、一歩上のサウンド表現を(導入編)
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX2 for UE4の導入で、一歩上のサウンド表現を(実践編)
https://qiita.com/SigRem/items/c089b71c42e898980a46

実装

AtomCraftでBGMを構成する

マテリアルの用意

設定したシチュエーションのとおり、ベーシックフレーズ+5フレーズを用意しました。数秒程度の簡単なBGMです。
A01.png

マテリアルツリーにインポートした後、それぞれ選択してインスペクターにて「ループ情報の上書き」を「True」にしておきます。これでフレーズがループ再生されるようになります。
A04.png

キューの作成

新規にキューを作成します。
ワークユニットツリーのキューシートを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」です。
A02.png

作成したキューに、トラックごとにマテリアルをドラッグアンドドロップで突っ込んでいきます。
A03.png
試しに再生して、ループが有効か試してみるといいかもしれません。

AISACコントロール

5つのシチュエーションを想定して、このキュー(楽曲)が6つのパラメータを持つものとして実装してみます。
今回設定するのは

  • ニュートラル状態を示す**「通常度」**
  • 天候変化時にBGMを変化させる**「悪天候度」**
  • 速く移動している間躍動感を追加する**「移動速度」**
  • 遺跡などのダンジョンやランドマークの近くに行くと高まる**「ダンジョンの近さ度」**
  • 敵との戦闘状態で使われる**「緊迫度」**
  • 視界の狭まりとともにBGMにエフェクトをかける**「霧の深さ」**
    です。
    このうち「霧の深さ」だけはハイパスフィルターのかかり具合に影響し、他のパラメータはトラックの音量変化に使用されます。

これらは**「AISACコントロール」**機能によりグラフ化され、UE4ではブループリントやC++、またはシーケンサーなどから操作することが可能です。

AISACコントロールについて基礎的な知識は次の記事にあります(当記事でも使い方を解説します)。

ADX2 for UE4でインタラクティブミュージック(AtomCraft編)
https://qiita.com/SigRem/items/8af9b7d8445477906741

AISACコントロールを設定する

「通常度」のAISAC

「通常状態」のトラックを右クリックし、「新規オブジェクト」→「AISACの作成」を選択します。
A05.png
名前を「Aisac_Neutral」として追加します。グラフタイプは「ボリューム」のままで大丈夫です。
A06.png
AISACタブに切り替わるので、トラックの「ボリューム」を選択してからグラフを編集します。
右肩上がりのシンプルなグラフでOKです。
A07.png
グラフができたら下部からタブを切り替えてタイムラインに戻ります。
A08.png
Aisacコントロールの動作チェックのため、トラックをベース部分と通常状態以外0にしておきます。
A09.png
AISACタブでテスト再生し、上部のスライダーを動かすと通常状態のトラックの音量が変化するはずです。
A10.png
テストが終わったら、各トラックのボリュームを戻しておきましょう。

「悪天候度」「移動速度」「ダンジョンの近さ度」「緊迫度」のAISAC

同じように、各トラックにAISACを追加していきます。
コントロールのIDを被らせないように注意してください。同じIDが存在すると、ひとつのパラメータを変動させた際に連動して音量が変わってしまいます。
A11.png
A12.png
A13.png
A14.png
A15.png

各AISACの「ボリューム」を選択し、右肩上がりのグラフを作ります。グラフの一番右を最大まで上げてしまうと音量が大きすぎることがあるので、最大でも「1.0」にとどめておくのがいいでしょう。
A16.png

「霧の深さ」のAISAC

霧の深さによってBGM全体にエフェクトをかけたいので、ハイパスフィルターのAISACはトラックに対してかけることになります。
トラックの一番上、キュー自体を選択して、トラックリストの空欄で右クリックし「新規オブジェクト」→「AISACの作成」をします。
A17.png
IDを被らないものに変更し、グラフタイプを「バンドパス - Cof高域」にします。
高域の音をカットしてくぐもった音に変化させます。
A18.png
紫色のグラフが現れます。これだけは数値が大きくなるにつれて下がっていくように設定します。
A19.png

キューシートのビルド

ここまでできたら、スライダーをいろいろ動かして遊びながら動作確認してみましょう。
A20.png

動作が大丈夫そうならキューシートをビルドします。
A21.png
A22.png

UE4での実装

セットアップ

ビルドしたキューシートをUE4にインポートします。
B01.png

プロジェクト設定を開き、CriWareタブ→「Atom Config」にacfファイルを設定しておきます。
B02.png
B03.png

コンテンツブラウザからキューをドラッグアンドドロップしてレベル上に配置します。
B04.png
ゲームを再生すると、自動でBGMが再生されます。AISACコントロールのパラメータを設定していないため、全部入りのBGMが聞こえてくることがあります。
B05.png

AISACコントロールの初期値を設定することもできます。レベルに配置したキューを選択し、Detailsパネルの「AISAC Control」の項目にある「+」ボタンを押してAisacコントロールを追加します。
B06.png
必要なぶんだけ項目を追加したら、「AisacControl_00」などの番号を振って初期値を設定します(『Name』はAtomCraftでつけた名前とは関係ないようです)。
B07.png
画像のように設定した場合、ベースのフレーズ+通常状態のフレーズだけが流れるようになります。

では、ここから各シチュエーションに応じたBGM変化を実装していきます。

街が近い状態のBGM

街が近い状態では、距離に応じて通常状態のフレーズの音量を上げていく設計とします。

まずはトリガーボリュームなどを使い、プレイヤーが街へ近づいたことを検知して処理を有効にします。
B08.png

街との距離を計測するために、基準となるアクターを置いてしまうのがいいでしょう。
次の画像では「TargetPoint」アクターを使用しています。
B09.png
Get Vertical Distance Toノードで2アクター間の距離を出すことができます。試しにPrint Stringで画面に表示してみましょう。
B10.png
B11.png

通常の場合この数値はcm単位として扱われるので、50000(500メートル)離れたら街から離れ、通常のフレーズに移行するようにしてみます。

Get Vertical Distance Toノードで取得した距離を50000で割り、数値を0~1の間になるようClampノードで丸めます。これが「街から離れた度」と言っても良さそうです。Lerpノードを使い、街からの距離に応じてSet Aisac by Nameで通常状態のフレーズの音量を上げていきます。
B12.png

雨天時のBGM

天候が崩れた場合の変化を起こすには、レベルブループリントや環境マネージャを担当するアクターに「雨の強さ」になる変数を持っておき、キューに数値を渡してBGMを変化させます。
B15.png

B16.png
画像ではTickイベントで処理を行っていますが、雨の強度を変化させるイベントがあればその際に一括で処理してしまったほうが負荷に優しいです。

ストーリー進行による悲しい場面は天候に関わらずAisacコントロールをしたり、嵐の場合はBGM自体をオフにするなどの演出をしても面白いかもしれません。

移動速度が速い場合のBGM

平原で馬に乗った状態や、キャラクターが全力でダッシュしている間BGMを躍動感のあるミックスに変化させます。

プレイヤーのアクターには予めキャストして変数化しておきます。
B19.png

Get Velocityで移動速度を取得できます。これだけだとジャンプした際に縦方向の速度も加わってしまいますので、VectorLengthXYを噛ませることでXY軸の移動速度だけを参照するようにします。
B21.png

処理の全体図は次のようになります。
移動速度を2000で割れば、速度が2000以上のときに完全にフレーズが置き換わることになります。
B20.png
立ち止まると通常状態のフレーズに戻るので、走っている間だけ専用のフレーズが聞こえるようになります。

立ち止まったり走った際に急激にフレーズが変わってしまうので、FInterpToノードを噛ませることで滑らかな変化になるかと思います。
FInterpToノードを使った際の処理の全体図は次のような感じです。
B22.png

ダンジョンが近い状態のBGM

ダンジョンが近い場合の実装は街が近い場合とほぼ同じです。
B13.png
Lerpノードの数値を逆にして、近づくほど専用のフレーズの音量が高まるようにしましょう。
逆に通常状態のフレーズは入れ替わるように小さくなっていきます。

B17.png
B18.png

戦闘時のBGM

戦闘などの場合は決まったテンポでBGMを切り替えたいので、タイムラインノードを使います。
タイムラインノードが吐き出したFloat変数をAisacコントロールに渡してあげればOKです。
B23.png
タイムラインノードの中身は次のようになります。
B24.png

霧が深い状態のBGM

雨の場合と同じです。

霧の強さの変数を持っておき、
B17.png
Aisacコントロールに渡します。
B18.png

最大まで霧が深まるとフィルターが大きくかかり、BGMがほぼ聞こえなくなります。
これもシチュエーションに合っていて良さげですが、少しだけBGMが聞こえる状態にしたい場合はAtomCraftでグラフを少しいじってみると解決します。
B14.png

補足

今回はAisacコントロールを細かく分けたので、シチュエーション別に実装していけば同時に処理を走らせることも可能なため「ダンジョンの近く+緊迫状態+霧が深い」状態といった場合にミックスされたBGMを作り上げることもできます。

戦闘状態はゲームの華なので、さらに細かく凝ったBGM変化についてもそのうちまとめてみたいと思います。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?