ゲームプレイ アビリティ システム は、アクタが保有し、トリガーできるアビリティとインタラクションを構築するためのフレームワークです。このシステムは主に、キャラクターがメカニクス、視覚効果、アニメーション、サウンド、データドリブン要素を調整するために必要な能力 (アビリティ) を持つ RPG、アクションアドベンチャー ゲーム、MOBA など向けに設計されていますが、その他多様なプロジェクトに適合できます。ゲームプレイ アビリティ システムはマルチプレイヤー ゲームのレプリケーションもサポートします。デベロッパーは、マルチプレイヤーをサポートするように設計を拡張する場合に多くの時間を節約できます。
このシステムを使うと、シンプルな単一攻撃から、ユーザーやターゲットのデータに応じて多くのステータス エフェクトをトリガーする複雑な魔法まで、対応するアビリティを作成できます。このページでは、アビリティ システムとそのコンポーネントが連携するしくみの概要について説明します。
ゲームプレイ アビリティとは?
ゲームプレイ アビリティ は、アクタが保有し、繰り返しトリガーできるゲーム内アクションです。代表的な例としては、アイテムでトリガーされるエフェクト、魔法、特殊攻撃があります。この考え方はビデオ ゲームでよくあるもので、そのため当たり前のものと考えられていますが、多くの場合、アビリティの実行に関わるプロセスは複雑で、特別なタイミングを考慮することが必要になります。たとえば、攻撃のアクティベーションをコーディングすること自体はかなりシンプルですが、長期にわたるプロジェクトの中で、プレイヤーやコンボ システムなどの細部に対して追加/削除するためにリソース コストやバフ/デバフ エフェクトを追加するに伴って、アビリティを構築する複雑さは爆発的に増大します。そのため、Unreal Engine のゲームプレイ アビリティ システムを設計する方法に関して、3 種類の重要な考慮事項があります。
アビリティのオーナーをトラックする
アビリティとそのエフェクトではオーナーシップについて留意する必要があります。エフェクトで計算を実行するとき、誰がオーナーであるのかを知る必要があります。その結果、オーナーの属性 (アトリビュート) を使用できます。さらにプレイヤーのスコアを増やすようなことをアビリティが実行するとき、正しい評価を与えられるようプレイヤーが保有しているものを知る必要があります。
ゲームプレイ アビリティの「オーナー」はネットワーク レプリケーションにおけるオーナーシップと同じ意味ではありません。
アビリティのステートをトラックする
アビリティは次ステートのサイクルをトラックする必要があります。
- アビリティをアクティブ化するとき
- アビリティの実行が進行中であるとき
- アビリティが完全に完了し、アクティブではなくなったとき
Lyra サンプル プロジェクト ではアビリティが許可されたときもトラックします。
例として、アビリティを使用する途中のアクタは、一般に完了するまで、同じアビリティを再びアクティブ化できません。ただし、アビリティを キャンセル できる特別ルールをアビリティに設定でき、このとき実行を早めに終わらせて、別のアビリティを開始できます。
アビリティの実行を調整する
アビリティは、その実行中に、特別のタイミングで複数の異なるシステムとやり取りすることが必要です。これらのインタラクションを次に示します。
-
アニメーション モンタージュを有効化する。
-
キャラクターの移動を一時的にコントロールする。
-
視覚効果をトリガーする。
-
オーバーラップ イベントまたはコリジョン イベントを実行する。
-
キャラクターの統計情報を一時または永続的に変更する。
-
ゲーム内リソースを増加または削減する。
-
他のアビリティのアクティベーションを許可またはブロックする。
-
アビリティの使用を制限するためにクールダウンを処理する。
-
ゲーム内イベントにより中断される。
-
進行中の他のアビリティをキャンセルする。
-
キャラクターに対して大きなステートの変更 (新しい移動モードのアクティブ化など) を行う。
-
他のインタラクションの途中で入力に応答する。
-
アビリティに対するゲーム内ステータスを表示するため、UI 要素を更新する。
アビリティがどのように働くのかに応じて、アクティブである間 (アニメーションの途中など)、多くの異なる時点でこれらのインタラクションのいずれかを実行できます。一部のエフェクトは、アビリティ自体が完了した後でも維持する必要があります。
ゲームプレイ アビリティ システムのコンポーネント
ゲームプレイ アビリティ システムは、それ自体の実行に責任がある独立したエンティティとしてアビリティをモデリングすることにより、これらのユースケースすべてに対応するように設計されています。このシステムは次の複数コンポーネントで構成されます。
-
アビリティ システム コンポーネント がある所有アクタ。これはアクタが所有するすべてのアビリティのリストを維持し、アクティベーションを処理します。
- ゲームプレイ アビリティ ブループリント。個別のアビリティを表し、そのゲーム内実行を調整します。
- ゲームプレイ アビリティ タスク は他の関数とともに構成されます。
- アビリティ システム コンポーネントにアタッチされた 属性セット。
- 計算を進め、リソースを表現する ゲームプレイ属性 を含みます。
- ゲームプレイ エフェクト。アビリティを使用した結果としてのアクタへの変更を処理します。
- ゲームプレイ エフェクト計算。エフェクトの計算にモジュラーで、再利用可能なメソッドが用意されています。
- ゲームプレイ キュー。ゲームプレイ エフェクトに関連付けられ、視覚効果を扱うデータドリブン メソッドが用意されています。
次のセクションではこれらのクラスの詳細についてまとめます。
オーナーシップをトラックする
ゲームプレイ アビリティを使用するために、アビリティ システム コンポーネントをアクタにアタッチする必要があります。このコンポーネントで対応するのは、アビリティのアクタへの追加/削除、アクタが保有しているアビリティの種類の追跡、さらにそれらのアクティブ化です。アビリティ システムのコンテキストで、所有アクタの主な表現でもあり、属性、継続中のエフェクト、ゲームプレイ タグ、ゲームプレイ イベント を追跡するシステム、所有アクタに直接アクセスするインターフェースがあります。
マルチプレイヤー ゲームでは、アビリティ システム コンポーネントで対応するのは、クライアントへの情報のレプリケーション、プレイヤー アクションとサーバーとの通信、アビリティ システム コンポーネントのステートの変更をクライアントが認可されているのかの検証もあります。アビリティ システム コンポーネントの親アクタは、リモート アクティベーションを実行するために、ローカルにコントロールするプレイヤーに所有される必要があります。
アビリティとその実行を処理する
ゲームプレイ アビリティはブループリント オブジェクトでアビリティ イベントのすべての実行を担当します。これにはアニメーションのプレイ、エフェクトのトリガー、オーナーからの属性のフェッチ、視覚効果の表示が含まれます。
アクティベーションを制御する
次の主なメソッドでゲームプレイ アビリティを アクティブ化 できます。
-
ゲームプレイ アビリティ ハンドル を使用して、ブループリントや C++ コードを通じて明示的にアビリティをアクティブ化できます。これがアビリティ システム コンポーネントより提供されるのは、アビリティが許可されたときです。
-
ゲームプレイ イベントを使用します。これは一致するアビリティ トリガーですべてのアビリティを発動します。入力や決定メカニズムを抽象化する必要がある場合、柔軟性が最も高いため、このメソッドをお勧めします。
-
一致するタグでゲームプレイ エフェクトを使用します。これは一致するアビリティ トリガーですべてのアビリティを発動します。ゲームプレイ エフェクトのアビリティのトリガーをオフにするときに推奨されるメソッドです。一般的なユースケースは、スリープ デバフで、無効化状態のアニメーションをプレイし、他のゲーム アクションを抑止するアビリティをトリガーします。
ゲームプレイ アビリティはゲーム内の幅広いアクションを表現することができ、プレイヤー自ら使用するパワーや魔法に限られません。ヒット リアクションや前に示したスリープ アニメーションもその例です。
- 入力コード を使用します。これらはアビリティ システム コンポーネントに追加され、呼び出されたとき、一致するすべてのアビリティをトリガーします。これは、ゲームプレイ イベントと同様に機能します。
ゲームプレイ アビリティを アクティブ化 するとき、システムはそのアビリティが進行中であると認識します。それから Activate イベントにアタッチされたコードが実行され、各関数とゲームプレイ タスクを通じて移動します。これはアビリティの実行が完了したことを示すシグナルを出すために Finish 関数を呼び出すまで続きます。追加のクリーンアップの実行が必要な場合、さらにコードを On Finished イベントにアタッチできます。実行途中で停止するために、アビリティを キャンセル することもできます。
ゲームプレイ アビリティではゲームプレイ タグを使用して、実行を制限します。すべてのアビリティには、アクティブ化されたときに、その所有アクタに追加されたすべてのタグのリストがあります。さらにアクティベーションをブロックする、またはそのアビリティを自動的にキャンセルするタグのリストもあります。自作のコードでアビリティの実行を手動でキャンセル、ブロック、または許可できますが、このタグによりシステムとして一貫したメソッドが提供されます。
実行を制御する
ゲームプレイ アビリティでは多様なよくあるユースケース (クールダウンやリソース コストの割り当てなど) をサポートします。さらにアニメーションや Unreal Engine の他の共通システムを処理する、ゲームプレイ アビリティ タスクの作成済みライブラリがあります。
標準のブループリント関数ノードはすぐに実行が終了しますが、ゲームプレイ アビリティ タスクでは、アクティブではない、進行中、完了したかどうかを追跡し、実行中に他のイベントを発生させるようにプログラムできます。親のゲームプレイ アビリティがキャンセルまたは対応してクリーンアップされたかどうかもトラックできます。ゲームでよくあるのは、ゲームプレイ アビリティ タスクを拡張することで、カスタム仕様のゲームプレイ ロジックを実装することです。
ゲームプレイ アビリティは、ゲームプレイ イベントにも対応し、所有するアクタからゲームプレイ タグと イベント データ 構造体を受け取るために待機する汎用イベント リスナーです。
属性 (アトリビュート) セットと属性
ゲームプレイ アビリティ システムは主に 属性セット を通じてアクタとやり取りし、これには ゲームプレイ属性 が含まれます。これらは計算で使用できる、ゲームプレイ アビリティで変更できる浮動小数点値です。これらは希望するどの目的にも使用できますが、一般的なユースケースは、キャラクターのヘルスまたはヒット ポイント、さらにキャラクターのコア統計値 (強さや知能など) のトラックです。これらの値を表現する基本変数を使用できる一方、ゲームプレイ属性では次のとおり複数のメリットがあります。
-
属性セットには、システムを構築するときにベースになる属性の一貫して再利用可能なグループがあります。
-
ゲームプレイ アビリティでは、リフレクションを通じてゲームプレイ属性にアクセスでき、ブループリント エディタで直接シンプルな計算とエフェクトを作成することが可能になっています。
-
ゲームプレイ属性はそのデフォルト値、現在の値、最大値を別々にトラックし、一時変更 (バフとデバフ) および永続的なエフェクトを作成することが簡単になります。ゲームプレイ属性はすべてのクライアントにもレプリケートされ、敵のヘルス値バーなどローカルの UI ビジュアライゼーションに対して安全に使用できます。
ゲームプレイ属性を使用するアクタにとって、属性セットをそのアビリティ システム コンポーネントに追加する必要があります。その後、アビリティ システム コンポーネントは属性セットに割り当てた属性に自動でアクセスできます。
ゲームプレイ エフェクトを処理する
ゲームプレイ アビリティ システムはゲームプレイ エフェクトを使用して、ゲームプレイ アビリティによりターゲットになったアクタに変更が適用されます。これらには 1 回限りのエフェクト (ダメージの適用など)、または永続的なエフェクト (継続的な毒のダメージ、バフ、デバフなど) があります。永続的なエフェクトの場合、ゲームプレイ エフェクトは、削除されるまでターゲット アクタにアタッチされます。期限が切れてクリーンアップされるまで限られたライフタイムを事前設定でき、ターゲット アクタのゲームプレイ属性への変更が取り消されます。
ゲームプレイ エフェクトはゲームプレイ エフェクト計算を使用して、ゲームプレイ属性に基づいて計算を処理します。ブループリント エディタで直接シンプルな計算を作成できる一方、複雑なロジックがあり一度に複数属性に影響を及ぼす、カスタムのエフェクト計算もプログラムできます。これらはゲームプレイ アビリティの所有アクタとターゲット アクタの両方からの情報を処理でき、再利用可能なコード ピースに共通の計算を集約できます。
コスメティック エフェクトを処理する
ゲームプレイ キューは、ビジュアルおよびサウンド エフェクトの実行に責任がある UObject とアクタであり、マルチプレイヤー ゲームにおいて、コスメティック フィードバックをレプリケートする推奨メソッドです。ゲームプレイ キューを作成するとき、イベント グラフ内部でプレイしたいエフェクトのロジックを実行します。ゲームプレイ キューは一連のゲームプレイ タグに関連付けられ、それらのタグに一致する、どのゲームプレイ エフェクトも自動的にそれらに適用されます。
たとえば、タグ Ability.Magic.Fire.Weak をゲームプレイ キューに追加する場合は、Ability.Magic.Fire.Weak を持つゲームプレイ エフェクトは自動的にそのゲームプレイ キューをスポーンして、実行します。これにより、コードから手動でトリガーすることなく、視覚効果の汎用ライブラリをすばやく簡単に作成できます。
代わりに、ゲームプレイ エフェクトに関連付けることなく、キューをトリガーできます。この実装サンプルについては、Lyra のサンプル ゲームで武器を発射したときのフィードバックを確認できます。
ゲームプレイ キューは信頼性のあるレプリケーションを使用しません。つまり一部のクライアントでキューを受信しない、またはフィードバックを表示しない可能性があります。ゲームプレイ コードをキューに結び付けている場合、これにより同期が失われることがあります。したがって、ゲームプレイ キューは、コスメティック フィードバックにのみ使用する必要があります。すべてのクライアントにレプリケートが必要な、ゲームプレイ関連フィードバックでは、代わりにレプリケーションを処理するために、アビリティ タスクを必ず使う必要があります。その良い例が、プレイ モンタージュ アビリティ タスクです。
ネットワーク マルチプレイヤーをサポートする
ゲームプレイ アビリティには、ネットワーク上のマルチプレイヤー ゲームをサポートするための組み込み機能が用意されていますが、注意すべき制限事項とガイドラインがあります。これらのガイドラインの多くは、一般的なネットワーク マルチプレイヤーでのベストプラクティスを反映しています。
アビリティ システム コンポーネントとレプリケーション
帯域幅を節約し、不正行為を防ぐには、アビリティ システム コンポーネントで完全なステートをすべてのクライアントにレプリケートしないようにします。具体的には、アビリティとゲームプレイ エフェクトをすべてのクライアントにレプリケートせず、影響を及ぼすゲームプレイ属性とタグのみをレプリケートします。
アビリティをレプリケートし、予測を使用する
ネットワーク ゲームの大半のアビリティは、サーバーで実行し、クライアントにレプリケートする必要があり、したがって一般にアビリティ アクティベーションに遅延があります。これは高速で展開する多くのマルチプレイヤー ゲームでは望ましくありません。この遅延をマスクするには、アビリティをローカルでアクティブ化し、遅延が生じないように、そのことをサーバーに通知します。
このとき、サーバーがアビリティのアクティベーションを拒否する可能性があります。この場合は、ローカルでアビリティが実行した変更を元に戻す必要があります。ローカルで予測された アビリティを使用してこれらのケースを処理できます。これをサポートするには、一部のゲームプレイ エフェクトで、それらを許可したアビリティがサーバーにより拒否された場合のロールバックをサポートします。これらには多くの即時ではない GE が含まれますが、特にダメージや他の即時の属性/タグの変更などが除外されます。
アビリティを使用して、サーバー所有オブジェクトとやり取りする
ゲームプレイ アビリティはボット、NPC、他のサーバー所有アクタやオブジェクトとのインタラクションを処理できます。これはローカルで所有したアクタ (一般にプレイヤーのポーン)、およびレプリケートするアビリティ、またはサーバー機能を呼び出す GAS ではない別のメカニズムを通じて実行する必要があります。これは NPC への変更を実行する権限を備えた、サーバーへのインタラクションをレプリケートします。
参考文献
ゲームプレイ アビリティ システムの実際の動作モデルについては、複数のアビリティと武器が実装された Lyra サンプル ゲーム プロジェクト を調べてください。これらの構成要素で作業を開始するには、ゲームプレイ アビリティ システムのクイックスタート ガイドに従ってください。