Studio X Labsは『逆コーラップス:パン屋作戦』の総合サウンドデザイン、オーディオプログラミング、ゲーム中のミキシング、プレイバックシステムなどを提供する機会に恵まれました。私たちにとって中国デベロッパとの初コラボレーションプロジェクトとなりました。Wwiseをオーディオエンジンとして活用したからこそ、最適なオーディオソリューションを提供することができました。
ゲームオーディオの制作において最も苦しく楽しいのが問題解決の過程であり、すべてのオーディオ要素から最大限のミックスを引き出すことのできるパイプライン、システム、そして構造を見つけることだと思います。私たちにとって『逆コーラップス』の旅は4年にわたりましたが、途中でストーリーやミッションの大幅な拡張に対応するため、2022年に8か月の中断期間がありました。
このプロジェクトには時差や言葉の違いなど難しい点もありましたが、『ドールズフロントライン』シリーズのファンに確実に受け入れてもらえるゲームにするためのプロセスを確立させました。
レビュー:
“『逆コーラップス:パン屋作戦』はプレイしていて楽しく、ビジュアル的にも魅力的。ところがゲームのビジュアルだけでなく、そのサウンドデザインもすごい。ゲームの雰囲気は音楽で決まり、必要なところでサウンドデザインがパンチを効かせている。英語の吹き替えがなくても声優の演技がしっかりとしていて、銃声音は期待通りのインパクトがあり、爆発は本当にパンチが効いていて、このゲームの設定とジャンルにぴったりの没入感を体験できる。" 5点中4点 Hardcore Gamer
“適切なオーディオ機器さえあれば卓越した音響効果を存分に楽しめるゲームだ。パンチの効いた銃撃と爆発は信じられないほど神々しい没入感がある。さらに敵の兵士たちが重くリズミカルで威嚇的な足音で戦場を移動する様子は、ミッションごとにふさわしい緊迫感を与える。” 100点中92点 Game8
コンテンツ実装のためのパイプライン策定:
プロジェクトを開始するにあたり、核心となる以下の領域のオーディオを効果的に配信するため、堅牢なコンテンツパイプラインを開発する必要がありました:
- サウンドデザイン:数千個にもおよぶカスタムアニメーションを支えるためのキャラクター、武器、環境のオーディオ制作。
- ローカリゼーション:本ゲームの日本語版の確実なシームレス再生。
- インタラクティブミュージックシステム:分刻みに変化するゲームプレイにリアルタイムで対応する、ダイナミックミュージックシステムの実装。
キャラクターアニメーション:
『逆コーラップス』はキャラクターやカスタムアニメーションが大量にあるゲームです。サウンドデザインを必要とする膨大な数のアニメーションを効率的に管理するため、スイッチコンテナをネスト化させたフォルダシステムを構築しました。このアプローチでUnityから呼び出すAKEventの数を最小限に抑えて処理を大幅に軽減させることができ、キャラクター別の柔軟なサウンドデザインが可能となりました。ネスト化されたスイッチコンテナを使い、各種キャラクターイベントをそれぞれのフォルダに効率的に繋げました。取り扱うアニメーションの数を考えると、このシステムが不可欠でした。プレイアブルキャラクターが27人、敵キャラクターが72人もいましたが、いずれもネスト化されたスイッチフォルダ構造となっています。例えば、以下が主役モンドのスイッチフォルダです:
モンド(Mendo)のフォルダの各スイッチコンテナには「走る」、「つかむ」、「元に戻す」などの具体的なEventタイプに関係するスイッチコンテナが入っています。 「走る」アクションには、環境サーフェス全種を取り込みました。「死亡」アニメーションはキャラクターのカスタムアニメーションに合わせたバリエーションとタイミングのために、ランダムフォルダに整理されたSFXアセットが各ブレンドコンテナに格納されています。「つかむ」アクションはプレイヤーが使うことのできる全52のアイテムのアニメーションが入っています。
この構造はスケーラビリティが高く、例えばキャラクター27人がそれぞれ52個のアイテムを扱うことで、全部のプレイアブルキャラクターで合わせて1,404の「つかむ」アニメーションと、追加で1,404の物を「元に戻す」アニメーションが生じます。 ネスト化されたスイッチコンテナを使用することで、これらのイベントコールを管理しやすくなりました。
多くのキャラクターが似たようなアニメーションタイプ(走る、落ちる、死ぬ、アイテムをつかむ、など)を共有するため、全キャラクタータイプを対象に、かなりの数のSFXアセットを再利用してメモリ使用量を最適化しました。足音、布のフォーリー音、アイテムの使用音などは、基礎となるアセットを作成した後にキャラクターごとに効率的に再利用しました。
時間をかけたのはキャラクターを検討する空間における各キャラクターや敵のアニメーションのテストと調整であり、カスタムアニメーションに必要なSFXの正確なタイミングを調整しました。文字通り何千ものキャラクターアニメーションがあるため、キャラクターや敵のイベントをスイッチコンテナで管理し配布するというアプローチが、最も効果的な方法であることが判明しました。
武器:
武器にスイッチコンテナを使いましたが、プレイヤーキャラクターは52あるアイテムのどれを使ってもよいため、ネスト化されたフォルダを逆さまに利用し、キャラクターをベースにしました。つまり各アイテムのスイッチコンテナにキャラクターのブレンドコンテナを設け、アイテムを使うたびにそのキャラクター独特となるような柔軟性を確保しました。本ゲームはカスタムアニメーションがあまりにも多く、こうして呼び出されるスキルイベントの数を削減することができ、Wwiseは参照するワールドのオブジェクトを通してイベントの宛先を判断します。
インタラクティブミュージックシステム
『逆コーラップス』は激しくも綿密なバックグランドのミュージックトラックが有名なゲームであり、音楽がゲームプレイの没入感と芸術的な全体ビジョンを高めています。本プロジェクトでは『ドールズフロントライン』や『Project Boundary』などで知られる、才能豊かな中国人コンポーザーのG.K.と緊密に連携しました。
インタラクティブでスケーラブルなミュージックシステムとしており、ゲーム内の膨大なレベル数に対応しています。各レベルに最大3ステージあり、敵ターンへと変わった時はそれを反映してミュージックミックスに特別な修正を加え、敵ユニットのターンが終わるまで待つ間のゲームプレイエクスペリエンスを強化させています。またボス対戦の音楽や、リメイクの2013年オリジナルゲームのレベルを忠実に復元した音楽など、特殊なケースでは特に慎重に取り組む必要がありました。
この野心的な目標を達成するため、私たちはWwiseのさまざまなツールを最大限に活用しました。例えば、柔軟性のあるInteractive Music Hierarchyのネスト化されたミュージックスイッチコンテナやステートなどのツールを使い、どの音楽を再生するのかを制御しています。ほかにもミュージックステートに重ねてボスミュージックをサポートするためのカスタムミュージックキューや、ミュージックトラックとシームレスに繋がるRTPCなどを実装し、ゲームのコードに統合しました。
ミュージックスイッチコンテナと、ステート
『逆コーラップス』が提供するコンテンツは60時間以上にもおよび、60以上のレベルがあります。これほど大量のデータを管理するため、下図に示すように各レベルで使用している名前に音楽データの名前を一致させ、リンクさせることにしました。
上図はゲームの第1章のインタラクティブミュージックの設定例です。後続するフォルダにおいても同様の設定となっています。最初は個別トラックを特定し、ミュージックプレイリストコンテナの数を少なくしようと考えました。しかしそのメリット・デメリットを比較した結果、各レベルに3つのミュージックプレイリストコンテナを設けることに決めました。以下がその理由の一部です:
メリット:
- 汎用的なソリューションになります。各レベルに最大3ステージありますが、1~2ステージしかないレベルもあります。その場合は必要のないステージで同じミュージックセグメントを再利用すればよいのです。これは効率的で応用の利くアプローチです。
- ゲームのデータテーブルと一致するアプローチであるため、すでにゲーム全体で使用されているlevelId変数をミュージックシステムにおいても活用できます。一貫性のある統合を確保することができます。
- 各レベルに音楽やシネマティック関連のファイルのための専用SoundBankがあるため、使用しているSoundBank管理ソリューションと容易に統合できます。処理が合理化され、効率的な編成を確立できます。
- 1つのレベルを特別扱いの対象にした場合でも、ほかのレベルへの影響や潜在的な連鎖反応などを回避できる柔軟な設定です。
- 上海チームとリモートで協力する関係上、時差があるため効率的なコミュニケーションと迅速なイテレーションが不可欠でした。オフィスでの対面型の典型的な仕事と比較して、コミュニケーションに時間がかかるかもしれません。私たちはコミュニケーションを円滑にするためにゲームのレベルをすべてリスト化し、Interactive Music Hierarchyの仕事に携わる人が誰でもすぐに把握できるようにしました。このアプローチにより、コンポーザーやサウンドデザイナーがファイルを管理・編集しやすくなりました。
- ミュージックトラックをインタラクティブに選択する必要がないため、かなり少ないコードで済みます。この設定では、レベルをロードした時にレベルに該当する音楽が自動的に再生されます。これにより開発プロセスが簡素化され、管理すべきコードの量も削減できます。
デメリット:
- 最初はWwise側の設定に非常に手間取るかもしれませんが、一度設定してしまえば使い方が明快で分かりやすいシステムです。
- 命名や構造が似ているため間違えが起きやすく、それに気づくことが難しく、すばやくテストすることも難しいです。
- ミュージックシステム構造をWwiseで編集する際、同じミュージックトラックを異なるコンテナ内で追跡する必要があるため、時間がかかります。
敵のターンを切り替えるRTPC
このゲームの後半レベルで特に敵のターンが頻発し、プレイヤーがマップ上で敵の交戦を観察しているうちに、かなり時間が経ってしまうことがあります。この一連の流れをボタン1つで加速させることもできますが、音楽を改変させてエクスペリエンスを強化し、敵の動きを確認するために時間を割くことを選択したプレイヤーのための代替ミックスを提供しました。
この処理はオリジナルのミュージックトラックの交代からはじまります。コンポーザーのG.K.が見事に対応してくれ変更をすばやく適応してくれ、通常のコンバットターンの該当箇所と比べて長さが同じである、リミックスされた敵ターンのミュージックトラックを提供してくれました。
私たちの方では特別な処理を適用し、構造をミラーリングしてプレイヤーまたは味方のターン音楽と敵のターン音楽の間のクロスフェードのための補完時間のRTPCを実装しました。敵のターンがはじまった時にこのRTPCが0から1へと徐々にトランジションし、またその逆もあり、代替ミックスが開始されます。
上図スクリーンショットがRTPCの調整される方法を示しています。敵のターンが起きた時にコード側でこのRTPCコールが起きるようにリンクさせ、プレイヤーや味方のターンがはじまった時に元に戻るようにしました。
Eventsタブにおいてメインのミュージックイベントが2つのスイッチコンテナを同時にトリガーさせますが、それぞれのミュージックミックスのプロパティが異なります。前述のRTPCを使い、どちらを再生するのかを決めます。ミュージックミックスのどちらのバージョンも長さが同じであるため、2つを同時にトリガーしてからRTPCで両者の間を切り替えることにより、いつでも敵ターンミックスとプレイヤーまたは味方のターンミックスの間をシームレスにトランジションすることができます。
「ボスミュージック」セグメントのトランジション
ボスターンという特殊なケースに対応するために3つのステージから成る既存のインタラクティブミュージックシステムの上に、RTPCを取り入れました。この設定によりゲームプレイ中のどの時点においても、通常の「コンバットミュージック」セグメントと「ボスミュージック」セグメントの間をシームレスにトランジションすることができます。
この設定で発生した問題の1つが「ボスミュージック」セグメントと通常の「コンバットミュージック」セグメントの長さの違いでした。ターゲットセグメントの長さが現在のセグメントよりも短い場合、音楽のない無音状態が発生する可能性があります。
上図では2つのミュージックセグメントの間をトランジションする際の問題点が浮き彫りになっています。トランジション中は2つのセグメントが同時に再生されるため、RC_RW_B10_pre_Upverに遷移するタイミングをRC_Boss3_preV2の終わりとした場合、一瞬の沈黙が生じますが、これは今回のケースでは望ましくありません。
この問題を解決するためにSeek() (Seek (audiokinetic.com)) 関数を実装してWwiseが提供する次の2つのカスタムミュージックキューをミュージックコールバック関数に利用しました。NormalExitCueは2つのトラックのうち「ノーマル」トラックの方が短いことを示し、BossExitCueは「ボス」トラックの方が短いことを示します。コードセグメントを追加して「ノーマル」エグジットキューから切り替えているのか、「ボス」エグジットキューから切り替えているのかを検出できるようにしました。次に短いクロスフェードを伴いターゲットトラックの頭をシークし、それを再生します。
以下の例ではパラメータモディファイアの出力値を抽出する小さなラッパー関数を作成し、この機能を使用する領域にオンデマンドで適用します。
public float GetGlobalRTPC(string rtpcName)
{
int rtpcType = 1;
float acquiredRtpcValue = float.MaxValue;
AkSoundEngine.GetRTPCValue(rtpcName, null, 0, out acquiredRtpcValue, ref rtpcType);
if(acquiredRtpcValue >= 0.25 && acquiredRtpcValue <= 16).
{
return acquiredRtpcValue;
}
else
{
return 1.0f;
}
}
上記の関数はRTPCをグローバルに設定するだけでなく、不正な値が検出された場合に設定予定のRTPCを無視してデフォルト値の1.0fにリセットします。
public void MusicSegmentSwitch(object in_cookie, AkCallbackType in_type, object in_info)
{
if (in_type == AkCallbackType.AK_MusicSyncUserCue)
{
var musicInfo = in_info as AkMusicSyncCallbackInfo;
if(musicInfo != null)
{
if (musicInfo.userCueName == “BossExitCue”)
{
if (GetGlobalRTPC(“BossBattleMusic”) > 0.5f)
{
AkSoundEngine.Seek(musicPlayingID, 0, false);
}
}
if (musicInfo.userCueName == “NormalExitCue”)
{
if (GetGlobalRTPC(“BossBattleMusic”) <= 0.5f)
{
AkSoundEngine.Seek(musicPlayingID, 0, false);
}
}
}
}
}
上記コードセグメントは0から1の範囲でクランプされたBossBattleMusicRTPCを利用し、ミュージックセグメントをインタラクティブに切り替える例です。切り替え時にミュージックセグメントを最初までロールバックし、クロスフェードエフェクトを適用して再生を再開します。
注:今回引用したコードスニペットはこの記事で紹介するために改めて再構築した汎用バージョンです。基礎にあるロジックが正しく機能することを確認済みです。プロジェクト固有のAPIコールや関数は、著作権に抵触する可能性があるため省略しました。
コメント