Sumo Digital が明かす『Spyder』の高度なアニメーション システムの構築方法

Sumo Digital Senior Programmer Nick Edwards and Sumo Digital Senior Programmer Andy Chapman

2003年に設立され、数々の賞を受賞した Sumo Digital は、イギリスのシェフィールド、ノッティンガム、ニューカッスル、ブライトン (The Chinese Room)、リーズ (Red Kite Games)、リーミントンスパー (Sumo Leamington と Lab42)、ウォリントン、およびインドのプネにある 9 つのスタジオで、700 人以上のスタッフを擁しています。Sumo は、あらゆるプラットフォームとジャンルにわたって成功したゲームを開発しています。多様性、独自のテクノロジー、創造性で知られており、Microsoft、Sony、SEGA、2Kなどの大手パブリッシャーのためのタイトルをフィーチャーしたゲームのフォートリオを築いてきました。

Sumo Digital は、Sumo Group plc の一員です。

詳細な情報を得るには、sumo-digital.com を訪れてください。
こんにちは、Sumo Digital のシニアプログラマー Nick Edwards と同じく Sumo Digital のシニアプログラマー Andy Chapman です。 Sumo Digital では、定期的に社内ゲームジャムが実施されます。受賞した作品には、開発時間をもっと投入することによって、そのコンセプトをさらに発展させることができるようにしています。これまでのゲームジャムの優勝作品には、Unreal Engine で制作された『Snake Pass』があります。これは、実際に製品化され、マルチプラットフォームでのローンチに成功しました

『Spyder』は、このようなプロセスから生まれた最新の作品です。ゲームジャムでの優勝を得たのち、元々 3 人のデザイナーから構成されていたチームが増員されて、魅力的なピッチデモを制作することになりました。その結果、Apple Arcade での場所を確保することができました。これはすなわち、このゲームが iPhone 6 などそこそこのモバイル デバイスで実行できることを保証するものでなければならない、ということを意味します。タイトルが生産段階に入ると、チームはさらに拡張されました。私たちも参加して、すでに出来ていた Blueprint ベースの Agent 8 のプロトタイプを C++ で書き直しました。より特徴をもたせ、保守がしやすく、パフォーマンスの高いものにするという狙いがありました。 

この記事では、そのような狙いを達成するために必要だったことについて解説しています。
 

アニメーション

第一段階
主人公の Agent 8 の最終バージョンを開発する前に、ゲームジャム用に作成されたキャラクターの初期のイテレーションと『Spyder』のプロトタイプを検討してみました。アーティストとアニメーターたちは、スパイダーのキャラクタライズを推し進めたかったのですが、初期バージョンで採用されていたプロシージャルなアニメーションではそれは難しいと思われました。
 

プロシージャルにアニメートするというアプローチを取らなくなると、課題が限りなく噴出しました。X 脚のキャラクターには十分なボーンが入ったスケルトンが必要でしたが、モバイルのターゲット プラットフォームで GPU スキニングを使用できるほど少ないボーンにする必要もありました。移動のためのアニメーション セットを膨大に作成しないようにすることによって、開発/ディスク/メモリを予算内に収めるようにする必要もありました。したがって、限られたセットのアニメーションを適応させることによって、ユーザーが完全に制御できる状態でさまざまな環境をナビゲートできるようにする必要があったのです。
 
Agent 8 にスケルトンを設定する
キャラクターのためにアート主導のアプローチを追求するには、重要な条件が 1つありました。それは、スパイダー (蜘蛛) のスケルトンを作成して、アニメータが Agent 8 に生命を吹き込むことができるようにするということでした。このようなスケルトンを作成するためには、問題がありました。脚の数が多いため、ボーン数も増えます。それにより、最大 75 のボーン数という制限を超えてしまい、ターゲットのモバイル プラットフォームで GPU スキニングが使用できなくなるのでした。この制限を超えたとき、Unreal Engine は CPU スキニングにフォールバックするため、パフォーマンスは大幅に低下します。

幸い、この問題は、エンジン コードを研究して、コードを改変することによって解決できました。Metal API を使って ES3.1 のプラットフォームで最大 256 個のボーンをサポートできるようにすることができたのです。私たちが行ったこの変更は、GitHub のプルリクエスト (ログインが必要です) で確認できます。『Spyder』は Apple Arcade のタイトルなので、Metal API を使用するすべてのターゲット プラットフォームに依拠できるため、この問題を解決することができました。
 
本領発揮
Agent 8 をアニメートさせるために、最も難しかった部分は、脚の数をうまく扱うことと、脚と環境をどのように相互作用させなければいけないのかという問題を処理することでした。たいていのゲームでは、キャラクターが 1 つの平面上を移動します。坂や階段を登り降りするとき、カプセルは直立したままであり、デベロッパーはインバース キネマティクス (IK) を使用して、足が地面を突き抜けてアニメートするのを防ぎます。足が現在あるところからいくらか上方の位置から、いくらか下方の位置まで物理トレースすると、足をコンストレインするサーフェスを見つけることができるかもしれません。

しかし、Agent 8 では別のソリューションが必要でした。キャラクターが環境内のさまざまな平面をただちに移動できるようにする必要があったからです。「反応性の高い」IK を実行するだけでは十分ではありません。サーフェスに沿って足を引きずってしまうことになるからです。そのようなサーフェスの場合は、さまざまなサーフェス上に移動する (たとえば、垂直な壁に接触しながら歩く場合) と予測して、脚の動きの弧を変化させる必要があります。しかし、ジオメトリは、多数の組み合わせが可能であるため、アニメーション セットは、単一の XY 平面のためにしか作ることができないということになります。そのため、「予測的な」IK を開発することによって、上記のような壁での移動のようなケースを解決する必要がありました。異なるサーフェスへの移動を予期して、それに従ってアニメーションをワープさせる必要があるのです。
イラストは、私たちが達成しようとしていた基本的な結果図を表しています。
外側のコーナーにじっと立っている場合ならば、Agent 8 の足の正しい IK 位置を見つけることは比較的簡単です。しかし、移動となると、問題は大きくなります。それぞれの足を置く位置を推定することによって、歩行サイクルの動きをワープさせて、カーブを描きながら壁を登ったり、エッジをまたいだりする必要があるのです。そうしなければ、キャラクターは、その上を歩く壁やまたがるコーナーの中に足をめり込ませながら引きずってしまいます。
Agent 8 の予測的 IK によって、足が接地する位置が予測されています。
Animation Modifier を移動のアニメーションで使って、コンポーネント空間で足がどこから離れてどこに接地するかを計算して保存しました。まず、アニメーターがルートモーションを使ってすべてのアニメーションを作成することによって、アニメーションのすべてのフレームについてモーションを決定できるようにしました。次に、Animation Modifier によって、足が置かれる (足のボーンが XY 平面で Z=0 の地点またはその近くにある) アニメーションの期間をマークします。すると、各フレームについて、現在のルートのトランスフォームと、足がフロアにあるときに記録されたルートのトランスフォームとの間の相対的なトランスフォームを計算できるようになります。次に、この相対的なトランスフォームに対して、接地したとき、または持ち上げようとしているときの足のコンポーネント空間における位置を掛け合わせることによって、最終的な値を出します。これらの位置ベクタを X、Y、Z 成分に分解し、アニメーション内の別個の Float Curve に格納します。到着位置ごとに 3 つの Float Curve と、出発位置ごとに 3 つの Float Curve をそれぞれの足について作成すると、合計で 36 の Float Curve になります。
ターゲットの足の位置が、各脚とベクトルの成分のための Float カーブとしてエンコードされます。
到達/出発する足の位置は、Animation Modifier によって生成されます。
くまなくトレース
足がどこから持ち上げられ、どこに接地するかがわかるデータがいつでも使えるようになると、予測的な IK が可能になります。IK ターゲットの位置を見つけるためのロジックはすべて、カスタムの AnimGraph ノード内に含まれています。当初は、AnimInstance の中で行いましたが、レイテンシが発生して、不正確な結果が出てしまいました。関係するアニメーションをティックさせることによって、最新のカーブデータがサンプリングに利用できるようにするとともに、さらに、Virtual Bone (LegIK ノードがデータを引っ張ってくることができるものです) を更新する前にトレースと計算を実行できるようにする必要がありました。Virtual Bone は、異なる AnimGraph ノード間で共有されるトランスフォームのためのスクラッチ領域として機能します。できれば、AnimGraph ノードをより再利用可能なセクションとして括りだしたいと考えています。将来的には、ControlRig が生産対応できるようになると、そのためのソリューションとなると見ています。

私たちのカスタムの AnimGraph ノードがデータをどのように使用するのか、その実装について研究しながら、まず、Agent 8 のスケルトンの各脚について静的参照ソケットを定義しました。その参照ソケットから出発点および到達点まで Swept Sphere Trace が行われることになります。これらの参照ソケットは、各股関節の大まかな場所に置かれていました。スパイダーが単一の平らなサーフェス上にある場合は、これらのトレースの結果はそのエンドポイントとなるはずです。垂直なサーフェスに隣接しているサーフェス上では、脚によっては、トレース結果がそのサーフェスにヒットするでしょう。エッジに隣接しているサーフェス上では、何にもヒットしない脚もあるはずです。 
サーフェスを発見するために私たちが使用している多数のトレースのうち 3 つを示しています。
最初のトレースでヒットしなかった場合は、追加のトレースを実行してサーフェスを見つけます。私たちは、事前に定義された一連の手法を使用しました。その順番は、成功する可能性が高い順にソートされていました。最初の追加のトレースは、到着点/出発点から真下に向かって実行されて、大きな球のような、わずかに湾曲したジオメトリでサーフェスを見つけます。このトレースが失敗すると、別のトレースを実行します。前回のトレースのエンドポイントから、スパイダーに向かって内側にトレースを実行します。これにより、多くの単純な外部コーナーを処理できます。ヒットするまで、さらにトレースを行います。サーフェスが何も見つからなかった場合は、早々に戻り、何も行いません。

サーフェスが見つかったら、平面に沿って足の位置を計算します。計算は、変数に照らし合わせて行われます。そのような変数には、どのくらい足を離すと適切に配置できるか目安となる距離があります。股関節と足の到達位置との現在の距離を使って、脚が過度に伸びることなく置ける範囲を推定することができます。 
過度の伸展は、脚のストレッチとしては望ましくないです。
衝突するサーフェスに沿ってターゲットの足の位置を「投影」した後は、追加の物理トレースを実行することによって、足がまだサーフェスに接しているかどうかを判断します。接していない場合は、上からプロセスを繰り返すことで、他のサーフェスを見つけ、今度はそのサーフェスに沿って投影を試みます。私たちの投影のロジックは、法線ベクトルが完全に向こう側に向いているサーフェスを扱うことができるくらい堅牢であるため、Agent 8 が完全に視界にないサーフェス上にどれかの足が回り込んで到達した場合でも、足の位置をうまく決定することができます。

一つ留意していただきたいのですが、私たちは、大抵の場合トレースを二重に行っていました。『Spyder』では、ほとんどの環境とオブジェクトに 2 つの別個の複雑なコリジョン メッシュを利用しています。1 つは、レンダー メッシュを「単純化した」近似的なものです (それでもトライアングル メッシュなのですが、詳細度が下がります)。もう1つは、完全なレンダー メッシュ コリジョンそのものです。単純化されたコリジョンは、キャラクターの動きのシステムやカメラ システムで主に使われます。レンダー メッシュ コリジョンは、アニメーション システムによってのみ積極的に使われます。単純化されたコリジョンは、主に「歩行可能な」コリジョン チャンネルと関連付けられ、レンダー メッシュは、ビジビリティ チャンネルと関連付けられたままです。IK のトレースでは、両方が使われます。単純化されたコリジョンは、足を配置すべき場所を大まかに把握するのに役立ちます。鋲やその他の環境要素などはこのコリジョンで表現されないためです。レンダー メッシュ コリジョンは、足が可視的なジオメトリに接するようにするために使われます。

パフォーマンスに関する覚え書き。当初私たちは、多くのトレースを行なうことには慎重でした。一部のターゲット プラットフォームのスペックと、私たちがクエリするコリジョンの複雑さを思ってのことです。実際、非常に注意深ったため、初期の IK の多くでは、各フレーム各脚について 1 回だけのトレースを行い、AnimNotify を使用してトレース ターゲットを切り替えていました。ターゲットの足の位置が変更するときは、一度だけトレースし、わざわざ各フレームでトレースしない、というやり方さえ検討していました。しかし結局のところ、トレースのコストは思っていたほど大きくないことがわかりました。シッピングの実装では、各足が離れる位置と到達する位置に対して毎フレーム トレースしています。これには、両方のタイプのコリジョンが使われ、トレースのストラテジーが成功するまで行われます。その結果、アニメーション システムは、Agent 8 が複雑なジオメトリを横断しているときに、 1 フレームにつき最大 200 回の物理クエリを実行できるようになりました。必要があれば、これを最適化したのでしょうが、このロジックを実行するのがたった 1個のキャラクターだけなので、全体のフレーム時間にはあまり貢献しませんでした。
 
モーションのワープ
出発と到着の足のトランスフォームを見つけるためのロジックが準備できたので、これらを使用してアニメーションに何らかの影響を与えます。そのためには、生のアニメーションの平面を、トランスフォームを利用して生成したスプラインの上にワープさせるという考え方を取りました。コンポーネント空間における出発/到達位置の参照ポイントがまだあるため、これらを使用して、足の現在の位置がこれら2つの位置の間のどこにあるのかを表すアルファ値を計算できます。このアルファ値を利用すると、スプライン上で使うべき点が決定できます。これが新しい「地面」の位置になります。次に、参照とする地面の位置と足の現在位置から相対的なトランスフォームを算出してから、この相対的なトランスフォームを新しいスプラインの地面の位置に適用します。その結果、スプラインを、ワープした新しいグラウンドの「平面」として使うことによって、足があるべき場所が得られます。
移動が行われるジオメトリに関わりなく、同じ移動アニメーション セットが使用されています。
すべてのスパイダーの足に対してこのプロセスを実行した後に、それらの計算結果を一連の Virtual Bone に入れると、Virtual Bone がそれらを LegIK ノードに渡します。FABRIK IK ソルバーはこれにより実装されています。LegIK ノードは、すぐにスパイダーと私たちの役に立ち、脚 1本につき 4 本のボーン チェーンが備わりました。
サーフェスを発見することは、足をどこに置くか知るために欠かせません。
ダイナミックス
脚の作業と並行して、キャラクター アニメーションの他の問題も解決するために時間を投入しました。これは主に、環境内を動き回るときに Agent 8 の体の他の部分がどのような反応をするかという問題でした。

アンテナ
そのようなものの 1 つに、Agent 8 のリアハッチに取り付けられた無線アンテナがあります。これらのアンテナは、主人公に無線通信を受信する手段をもたらすだけではなく、キャラクターがどの方向に向いているのか分かりやすくしてくれます。ですから、重力による向きに応じて、アンテナにダイナミズムを導入できることが重要でした。そのために、私たちは、AnimDynamics ノードを利用して、各アンテナに属するボーンのチェーンにモーションを与えました。アニメーターは、カスタムのコードを書かなくても、このノードに備わっている多くの設定を使って、望みの結果を得ることができました。また、重力に応じてアンテナが傾くだけでなく、Agent 8 が動き回ったり、待機状態を再生したりするときに、素敵なセカンダリ アニメーションを簡単に得られました。これにより、キャラクターに素晴らしい弾みと面白みが加わりました。開発が進むにつれて、私たちはこのアンテナのことを親しみを込めてディーリー ボッパーと呼ぶようになりました。
 
Agent 8 の向きが変わるとアンテナも反応します。

本体

アンテナに動きがつき、脚の IK が十分に改善されたので、Agent 8 の本体に物理的な反応をもたらす方法について検討してみました。まず、スパイダー本体への重力の影響を再現してみようということになりました。逆さまにすると、地面から離れたところにぶら下がっているようにしてみるのです。そのためには、本体のボーンのトランスフォームを変更することによって、トランスレーションとローテーションのオフセットを供給しなければなりません。他にシステムがない場合は、脚を含めてメッシュ全体がオフセットされることになります。しかし、コンポーネント スペース IK があれば、これは問題になりません。ボディの移動先に合わせて脚の向きが変わるからです。

重力でスパイダーの体に影響を与える処理がうまくいったので、更なるエフェクトの実装について検討しました。本プロジェクト開始時から、キャラクター チーム内で頻繁に議論されていたアイデアがありました。それは、Agent 8 で重量感を出すというアイデアでした。動き出すときや止まるときに、あるいは、動いているオブジェクトの上にじっとしているときにも、それに反応して体が動くようにします。そのために私たちは、Vector Spring を使用しました。スパイダーの現実の位置をターゲットとして、前のボディ スプリングの位置から現実の位置までを補間するのです。特定の状況 (停止時など) 下では、ボディ スプリングの位置に力を加えることによって、ボディが受け取る揺れの量を増やします。また、現在のボディ スプリング オフセットを使って、ピッチとロールのローテーションを算出します。これらは (トランスレーションのオフセットも)、重力の影響とともに蓄積されてから、ボディのボーンに適用されることになります。
 
Agent 8 のボディのスプリングによって、動きに面白味が出て、ダイナミックになりました。
ガジェット
Agent 8 がワールドとインタラクトする場合、主に、ガジェットを使用します。ゲームにはガジェットがいくつか用意されています。それぞれのガジェットは、プレイヤーがレベルを上げていくときに、触覚体験をもたらすのに役立ちます。各ガジェットはユニークな経験を提供するため、さまざまに制御およびアニメートされます。私たちは、ゲームプレイの動作がアニメーション自体から切り離されるようにガジェットを書きました。つまり、ガジェットが使用されるときの外観は、完全に制御できるということになります。
どうしたらそこにフィットするのか? 蜘蛛学。
各ガジェットは、それに関連付けられた Actor クラスをもち、そこにはそのガジェットの物理的表現が含まれています。各ガジェットは少なくとも 2 つのスケルタル メッシュ コンポーネント (1 つは腕用、もう 1 つはガジェット ヘッド用) で構成されています。腕のスケルトンはすべてのガジェットで共有されていますが、各ヘッドは固有のスケルトンをもちます。私たちは、Copy Pose From Mesh AnimGraph ノードを活用して、共有されているボーンのトランスフォームを Agent 8 から腕に、そして腕からヘッドへと伝えます。ほとんどのガジェットでは、アニメーション ブループリントを使って、手動計算されたさまざまなタイプの IK を実装し、目指している効果を作り出します。
 
感情的な応答
Agent 8 のアニメーションを完全に制御できるようになったので、感情的反応のためのシステムを開発することによって、キャラクタライズをさらに推し進めようと考えました。特定の動作をとったり、ゲームの特定の場所にいると、感情を呼び起こし、それによって、歩き回っているときのさまざまな表情や、じっとしているときの待機/そわそわのアニメーションがトリガーされるようにすることが可能です。ゲームには、12 個の感情それぞれについて、少なくとも 1 つの待機/そわそわのアニメーションが用意されています。これらのアニメーションは、AnimGraph のカスタム ノードのインスタンスを介して再生されます。このカスタム ノードは Random Sequence Player ノードに似ていますが、偶然に基づいてリストから 1 個のアニメーションを選択し、ランダムな再生速度でランダムな回数ループしてから、再生を停止します。これにより、ノードの 2 つのインスタンス間を遷移できるようになります。それぞれのインスタンスには、アニメーション、確率、ループ時間、再生速度が入っている異なるバケットがあります。

待機状態の各アニメーションで IK を十分に機能させることが鍵となりました。これらは、IK システムを開発した時にテストした移動のアニメーションとは大きく異なります。幸いにも、私たちが作成したソリューションは、いくつかの調整と修正を行うだけで、これらの新しいアニメーションをうまく動かすことができました。
Agent 8 の 12 の感情をすべてご覧になれます。

移動

360 度のナビゲーションと移動の自由をもたせる、ということは、素晴らしいことであるとともに、忌むべきことでもあります。これによって、従来の 3D ゲームでは必ずしもプレイヤーに提供されていなかった多くの自由がプレイヤーにもたらされますが、デベロッパーには、頭痛の種となるかもしれません。プレーヤーが壁や天井の上を歩き始めると、コントロールやカメラといった、オーソドックスなファーストパーソンやサードパーソンのゲームで使用されている一般的なシステムが破綻してしまうのです。
 
問題
私たちは、プロジェクトの早い段階で制限リストを考案しました。これは、設計要件と工数の制限を組み合わせたものでした (私たちは、守るべき締め切りと生成すべき多数のレベル コンテンツを抱えていました)。
 
  • レベルの目印やヒントはつけない。(つまり、「これは壁です」とか、「これは端です」とか、「これはコーナーです」などのことです)。工数制限によるものでした。進化するレベルのレイアウトについていく手段は私たちにはありませんでした。
  • 比較的自由な形状のジオメトリにする: 現実の世界はグリッド ベースではないので。
  • 動くサーフェスにする: 静止しているものに面白味はあるでしょうか?

こうすることによって、はっきりしたことがありました。それは、計画していたレベルのジオメトリの潜在的な複雑さと、時として動的となる性質が原因となって、スパイダーの周りの局所的な環境を何とかしてリアルタイムで把握する必要があるということです。
 
出だしは簡単に
私たちは、何らかのトレースを実行することによって、スパイダーが歩くことができる周囲のサーフェスの状態を判定する必要があるとわかっていたので、Floating Pawn Movement コンポーネントをベースにして、それに重力を加え、Multi Sphere Trace を 1 回呼び出すようにしました。

補足すると、長さゼロの Sphere Trace を実行すると、問題が生じました。エンジンがそのことに気づいて、X 軸 の長さを強制的に 1 にしたのです (記憶が正しければ)。その部分のコードをコメントアウトして対処しましたが、それによって問題は発生しなかったようです。

この Floating Pawn のソリューションは、急遽作成したテストレベルで有望な結果を出しました。そのトレースの呼び出しからかなり多くの情報が得られていたのです。今にして思えば、これは、そのレベルが多数の個別のキューブから構築されていたために起こったことです。Multi Sphere Trace は、トレースに対して複数の Hit Result を返しますが、オブジェクト 1 個につき、1 つの Hit Result しか返しません。これは、最初のテスト レベルでは問題ありませんでした。

単一のスタティック メッシュでこのアプローチを試してみると、すぐに、トレースからの Hit Result が 1 つに下がってしまい、十分な情報が得られなくなりました。
 
交差させる
次のアプローチは、あからさまに Sphere Trace の数を増やすことでした。これは、スパイダーの垂直軸に沿った単一のトレースと、スパイダーを中心とする東西南北 4 つの方位トレースで構成されていました。

これにより大幅な改善が見られ、文字通り 5 倍の情報が得られました。今度は、この情報をどのように扱うか考えなければなりませんでした。
 
空飛ぶじゅうたん
今思うに、変数の命名技術を披露することに失敗したようです。というのも、私たちは、トレース時に見つかったサーフェスの配列から計算される仮想的な「movement surface」 (動きのサーフェス) を使っているのですが、これは「flying carpet」(空飛ぶじゅうたん) という名前にしたほうがずっとよかったと思うのです。
発見されたサーフェス ― 灰色の四角形がサーフェスです。赤い矢印は、そのサーフェスの影響度を表しています。
私たちは、新たに発見されたサーフェスのリストをイテレートしました。最初に、不適切な面を破棄します。そのような面は、スパイダーが歩くことができないものです (たとえば、スパイダーの上側や反対側などにある面)。破棄されなかった面には、重みを与えます。これは、スパイダーの向きにどの程度寄与すべきかを表す重みと、スパイダーの位置にどの程度影響を与えるべきかを表す重みです。この重みを計算するために、さまざまな式を試し、テストしました。最終的な式は、次の変数の加重和で作られています。
 
  1. サーフェスのヒット位置とスパイダーの原点との間の距離。サーフェスを見つけるためにスキャンする最大距離によって正規化されています。
  2. サーフェスのヒット法線と、スパイダーの上方ベクトルの内積。
  3. スパイダーの前方ベクトルと、検出されたサーフェスのヒット ポイントへの方向との内積。

上記の最初のものは、以下のような曲線になります:
スパイダーの向きに対するサーフェスの影響が距離とともに減少する様子を示しています。
そして、2 番目と 3 番目の値を組み込むことにより、スパイダーのローテーションをより重要と思われるサーフェスに偏らせることができる複雑な 3D サーフェスが得られました。
サーフェスの影響度の重み付けによる前方への偏りの例。
さらに、洗練されたリストのコンテンツを使って、仮想的な「movement surface」(動きのサーフェス) の位置と方向を計算しました。
仮想的な movement surface (黄色)。
この movement surface は、スパイダーの位置と向きのためのターゲットとしてではなく、スパイダーの現在の座標系を決定するためのガイドとして使用されます。この情報は、スパイダーに対して、「しがみつく」方向と、自分をどちらに向かせるかを伝えるために使用されます。

この時点では、かなり良いシステムができました。壁での移動は現在のサンドボックスのテスト レベルでうまく機能しました。しかし残念ながら、テストレベルにはエッジケースが文字通りありませんでした。

この移動システムは、初期のかなり狭いテスト レベルにあるミニチュアの丘や谷、崖、壁に対してうまく機能しました。問題が生じたのは、アート チームによって作成されたより表現性の高いレベルのジオメトリに取り組み始めたときでした。

その問題は、「ピンポン」と名付けられました。これは、スパイダーの方向システムにおけるフィードバック ループから生じるものでした。レベルを移動する際に、システムが素早く反応してスパイダーの向きを正しくできるようにする必要があったため、回転運動を過度に弱めることができなかったのです。
もう 1 つの大きな問題は、外側のコーナーがおよそ 270 度を超えると発生するものでした。スパイダーが全速力で移動しているときに、そこのジオメトリから飛び出して、まるでロードランナーに肩透かしをくらったコヨーテのように、空中に舞う場合があったのです。

問題は明らかで、私たちの現状の Sphere Trace が発射されたときに、しがみつかなければならない崖の面が Trace には「見えて」いなかったことにあります。
これは、崖の端にヒットしてそれを回り込むようにするときに、スパイダーの向きが調整されることに依存しているために生じた問題です。スパイダーの垂直トレースなら崖に気がつくことができるでしょうが、スパイダーが移動していた速度では、そうもいきません。さらにトレースが必要となりました。
 
ヘッド マッサージャー
これらの追加のトレースを実行することによって、2 つの問題とも最終的に解決することができましたが、一足飛びに最終的なシステムに辿り着けたわけではありません。いつもの如く、段階的なアプローチが必要でした。

この時点で、システムはスパイダーを基準にした方向ベクトルのテーブルを使用していました。既存のシステムに追加のトレースを付け加えるためには、この配列の既存の各エントリに追加のベクトルを付け加える必要がありました。これにより、ピンポン問題の最初のテストケースが解決しましたが、QA がすぐに別の問題を見つけるのでした。
トレースが実行されている様子。赤いトレースは、ワールドのジオメトリとの交差を示しています。
スパイダーの下で出会うトレースを作成することにより、その問題は修正されたかのように見えました。しかし、これらの追加のトレースを追加すると、システムを更新するのがものすごく時間がかかるということが浮かび上がりました。トレースの形状に変更を加えることは、大変な手間がかかり、トレースする方向ごとに個別のベクトルを計算する必要がありました。本質的に、更新プロセス全体を格段に簡素化するための改善が必要となりました。

このコードを少しリファクタリングして、連結されたベクトルの配列を介して複数のトレースを実行できるようにすると、カーブを効果的にトレースできるようになりました。それにさらに少しコードを追加して、スパイダーを中心とした完全な 360 度のために、これらの個々のトレースの回転スイープを実行できるようになりました。
トレースの増加 (左から右へ) ― 1、4、8 回のトレースが実行されています。
キャッシュがあれば
あいにく、この世にあるトレースは、ピンポンの回転振動問題を完全に修正してくれることはありませんでした。大幅に緩和されましたが、それでもまだ問題は消えず、目につく状態にありました。

根本的な原因は、以下のようなフィードバック ループでした。
スパイダーの向きのためのロジックによるフィードバック ループ。
サーフェスのジオメトリの変化にスパイダーの向きを反応させる必要があるため、クモのローテーションの減衰レベルを上げることができなかったのです。

フィードバック ループの進行を遅らせることはできないため、私たちの解決策は、問題が最も目立つときにループを断ち切ることでした。それは、スパイダーが静止しているときに行われました。

下図の赤い矢印が、ループをどこで切るかを示しています。
スパイダーの向きのためのロジックによるフィードバック ループが現在中断されている。
それを行うために私たちは、検出されたサーフェスのキャッシュを保持しました。これらのキャッシュは、スパイダーが一定の距離を超えて移動するか、あるいは、指定されている量を超えて回転するか、あるいは、キャッシュされたサーフェスの1つが移動するまで有効にしました。これらの条件が成立した場合に、キャッシュはクリアされて最初の状態に戻るようにしました。

これにより、私たちが抱えていた問題はとうとう修正されました。修正を追加することによって、都合の良い副作用が得られました。一定期間に実行されるスキャンの量が大幅に削減されたのです。
 
運動はしないようにしよう
私たちは、スパイダーの動きのシステムを、Floating Pawn Movement のサンプル コードを基にして作成したように、キネマティックなキャラクターの制作にかなり注力しました。元々のゲームデザインでは、物理的なトリックは何も必要ありませんでした。重力は、私たちがその上を歩いているサーフェスに常に作用していたものです。

そのため、(ゲームプレイのために) 物理関連の追加をキャラクターの機能に追加しなければならなくなったとき、私たちは次のいずれかを選択しなければなりませんでした。
 
  • メイン キャラクターで物理を有効にし、すべての動きのコードを変えて物理的な力を使用するようにする

もしくは
 
  • ゲームプレイの都合を考えて、必要な物理的力をシミュレートする

私たちは後者を選択しました。

そのように決定した理由は、主に、プロジェクトを開始したときのクモの性格にあります。

そのスパイダーはブループリントで書かれていて、社内で開催された Sumo Digital ゲームジャムに出品されたブループリントのプロトタイプから進化したものです。スパイダーは物理オブジェクト上に構築されていて、すべての動き/回転/表面引力がキャラクターに物理的力を加えることによって実装されていました。そして当時それを使ったことがある誰もが、楽しくて魅力的なゲームプレイにするためには、物理的に正確なシミュレーションのバランスを取ることが相当難しいと言っていました。

このことは私たちにとって不都合でした。簡単に調整でき、バランスを取れるシステムを作らなければならなかったからです。そこで、2 番目の選択肢を目指すことにしたのです。
 

細部をつめる

先に述べたように、スパイダーにはいくつかの機能を追加する必要がありました。

設計面では、Unreal Engine で物理マテリアルを拡張する必要がありました。特に、摩擦のシミュレーションについて必要でした。

私たちはすでに、スパイダーで独自の物理シミュレーションを行っていたため、その内部で摩擦の計算を拡張することによって、必要となっていた粘着性のあるサーフェスに対応することはかなり容易でした。

2つ目のリクエストは、ゲーム内で使われるカスタムの風システムに対応することでした。

このカスタムの風システムは、レベル内でゲームプレイ オブジェクトに風を吹きつけるためにすでに開発されていたものです。スパイダーもその風に同じように反応させる必要があったのです。このシステムを使用してスパイダーを動かすには、コードに簡単な追加が必要となりました。すでに AddForce 関数と AddImpulse 関数の実装をスパイダーに追加していたので、これらに接続するだけで済みました。

この作業は、必ずしも順調に進んだわけではありません。一定の範囲にあるフレームレート全部でこのシステムの一貫性を保つことは、予想していたよりもかなり難しかったからです。

このシステムは、非常に高いフレームレートで動く開発用 PC では、十分に機能しました。しかし、サポートを予定しているローエンドのデバイスでは、そうはなりませんでした。

スパイダーに風を当てるだけだったら、それほど問題になることはなかったでしょうが、同じシステムを使って他のゲームプレイ オブジェクトも動かしていたため、これら 2 つの動作で齟齬が生じていたのです。

独自の物理シミュレーションのデバッグと改良にかなりの時間を費やして、ようやく、システム内に物理サブステップ機能を実装できました。この最後の追加により、同じ動作を得ることができるようになりました。
 

さらに働く

『Spyder』がショッピングされたため、コード チームは、開発の旅と獲得した知識について振り返り、未解決の問題について検討することができるようになりました。

今後必要となるかもしれない作業として、2 つの機能が思い浮かびます:
 
  • スパイダーを物理オブジェクトにする。
    • これは、Unreal Engine の枠組みにより近いものとなります。こうすることで、デザイナー (ブループリントだけを使っています) に力を与え、現在簡単に利用できる Unreal Engine の機能を使って、より自由にプロトタイプを作成できるようにしてあげられます。
  • 粘着性のある移動技術を転用する
    • 『ワイプアウト』的なホーバーレース
    • 『スーパーマリオギャラクシー』風プラットフォーマー
    • 『ワンダと巨像』のゲームプレイ

アニメーションは、Unreal Engine で活発に開発されている分野です。いくつかの新たな技術は、将来的な作業の一環として調査してみる価値がありそうです。私たちはこのブログですでに、実験的でスクリプト可能なリギング システムの Control Rig について触れました。これは、IK ロジックをよりモジュール化された強力な方式で再実装する際に役立ちそうなツールとして候補に上がっています。あるいは、慣性ブレンディングという機能は、パフォーマンスとブレンドのクオリティを向上させることができます。また、ゲームプレイの状態とアニメーションの動作をリアルタイムに調査できる新しいプロファイリングツールである Animation Insights も開発に役立ちそうです。このようにアニメーションという分野には、将来的な改善のために使える手段が多数そろっています。

私たちが予定しているアニメーション システムの改善ついて述べれば、生成されたスプラインの経時的な安定性を図ることによって、フレーム毎に大きく異なる結果をトレースが返すときに、脚/足がなるべくちらつかないようにしたいと考えています。アニメーションのブレンドの動作には調整する余地があり、停止したときなどにポーズ間のブレンドが速すぎないようにする必要があるのです。

『Spyder』の開発の旅についてお楽しみいただけたでしょうか。Agent8 といっしょに世界を救いたい人は、Apple Arcade における『Spyder』をぜひチェックしてみてください!
 

    Get Unreal Engine today!

    世界で最もオープンで先進的な制作ツールが入手可能です。 
    Unreal Engine では、あらゆる機能と完全なソースコードがアクセス可能です。満載の機能がすぐに使える状態で入手できます。