Unreal Engine 5 (Unreal Engine) では、さまざまな方法でキャラクターの AI を作成することができます。Blueprint Visual Scripting を使用すると、キャラクターに対して、アニメーションの再生、特定の位置への移動、何かにヒットしたときの反応などの「アクション」をするように指示することができます。AI キャラクターに独自の思考と意思決定をさせたいときに Behavior Tree が役立ちます。以下に、AI キャラクターがプレーヤーを巡回するか追跡するかを切り替えるビヘイビアツリーの例を示します。
ビヘイビアツリーの基本
ビヘイビアツリーは、一部の機能がアタッチされた一連のノードを Behavior Tree グラフに追加および接続することによって、ブループリントと同様の視覚的な方法で作成されます。Behavior Tree がロジックを実行している間、ブラックボード という別のアセットが情報 (ブラックボード キー という) を格納するために使用されます。一般的なワークフローとしては、ブラックボードを作成し、ブラックボード キーをいくつか追加してから、Blackboard アセットを使用する Behavior Tree を作成します (以下の図では、Behavior Tree にブラックボードが割り当てられています)。
Unreal Engine のビヘイビアツリーは、ロジックを左から右、そして上から下に実行します。操作の数値順は、グラフに配置されたノードの右上に表示されます。以下の画像では、Behavior Tree グラフの左端に配置されたブランチのサンプルにいくつかのノードがあり、ブラックボード キーである HasLineOfSight が設定されていれば、プレイヤーを追跡するよう AI に指示しています。
上の画像では青いノードが デコレーター (または他の Behavior Tree システムでは「条件式」という) です。これは、 Composite ノードにアタッチされ、ブラックボード キーが true か false かの検証に使用されます。これにより、残りのブランチを実行できるかどうかが決まります。紫色のノードは Task ノードで、AI が実行できるアクションです。
Behavior Tree の作成と編集の詳細については、「ビヘイビアツリー ユーザー ガイド」を参照してください。
ビヘイビアツリーとロジックを作成したら、ゲームプレイ中にビヘイビアツリーを実行する必要があります。通常は ポーン (すなわち、キャラクターなどのエンティティである AI の「ボディ」) があり、ポーンには関連付けられた AI コントローラー があり、アクション (その 1 つは、Behavior Tree を実行すること) を実行する際にポーンの制御や指示に使用されます。以下では、ポーンにカスタム AI Controller クラスを割り当てます。
AI コントローラーは、コントローラーがポーンの「占有」を取得すると、Behavior Tree が実行されます。
ポーンで環境内を移動するには、レベルに ナビメッシュ バウンズ ボリューム を追加する必要があります。
Behavior Tree を使用した AI の設定については、「Behavior Tree のクイックスタートガイド」を参照してください。
Unreal Engine のビヘイビアツリーの違い
このセクションでは、従来のビヘイビアツリー システムと比較して、Unreal Engine のビヘイビアツリーの相違点について説明します。
ビヘイビアツリーがイベント駆動型である
Unreal Engine には のビヘイビアツリーが他のビヘイビアツリー システムと異なる点の 1 つは、Unreal Engine のビヘイビアツリーは、フレームごとに不要な作業を行わないようにイベント駆動型であることです。ビヘイビアツリーは、関連付けられた変更が発生したかどうかを常にチェックする代わりに、ツリー内の変更をトリガーするために使用できる「イベント」を受動的にリッスンします。下の画像では、イベントを使用して Blackboard Key の HasLineOfSight? を更新しています。これにより、優先度の高い左端のブランチを実行するために、優先度の低いタスクが中止されます。
イベント駆動のアーキテクチャーを持つことで、パフォーマンスとデバッグの両方が改善されます。ただし、これらの改善を最大限に活用するには、Unreal Engine のビヘイビアツリーとのその他の違いを理解し、ビヘイビアツリーを適切に構成する必要があります。コードはツリー全体を 1 ティックごとに繰り返す必要がないため、パフォーマンスは大幅に向上します。概念上は、常に「もういますか?」と尋ねるのではなく、「もういます!」と言われるまでただ休んでいるようなものです。
動作を視覚的にデバッグするためにビヘイビアツリーの実行履歴を前後に移動する場合は、履歴に関連する変更を表示して無関係な変更は表示しないようにすることをお勧めします。Unreal Engine のイベント駆動の実装では、最初から追加のイテレーションの必要がないため、ツリーに対してイテレーションをして以前と同じ動作を選択した無関係なステップを除外する必要はありません。代わりに、ツリー内の実行位置またはブラックボード値への変更のみが重要であり、表示されるのはそれらの違いです。
条件式がリーフ ノードではない
ビヘイビアツリーの標準モデルでは、条件式は Task リーフ ノードであり、成功または失敗を返す以外の処理は行いません。従来の条件式のタスクは正常に実行できますが、条件式用には デコレーター を使用することを強くお勧めします。
条件式をタスクではなくデコレーターで作成すると、かなり有利な点がいくつかあります。
-
条件式をデコレーターにすると、ビヘイビアツリーの UI がより直感的で見やすくなります。
-
すべてのリーフはアクション タスクであるため、ツリーによって実際のアクションがどのような順序付けられているかを簡単に確認できます。
条件は、制御しているサブツリーのルートにあるため、条件が一致しない場合は、ツリーのどの部分が「遮断されている」のかすぐに確認できます。また、すべてのリーフはアクション タスクであるため、アクションの内容を簡単に確認できます。従来のモデルの場合、条件式がリーフの中にあるので、条件式のリーフとアクションのリーフを見分けるための時間が長くかかってしまいます。
上のビヘイビアツリーのセクションでは、デコレーターの Close Enough と ブラックボード により、Sequence ノードの子ノードの実行を妨げることができます。条件式をデコレーターにするもう 1 つの利点は、これらのデコレーターをツリー内の重要なノードで (イベントを待機する) オブザーバーとして機能させることが簡単な点です。この機能は、ツリーのイベント駆動型の特性を最大限に活用するために重要です。
同時動作
標準的なビヘイビアツリーは、Parallel Composite ノードを使用して同時にビヘイビアを処理することが多く、Parallel ノードはそのすべての子に対して同時に実行を開始します。これらの子ツリーのいずれかが終了した場合の動作については、特別なルールで定義されています (必要な動作に応じて)。
Parallel ノードは必ずしもマルチスレッド (タスクの同時実行) である必要はありません。概念的には、これらは複数のタスクを一度に実行するための手段にすぎません。多くの場合、それらは同じスレッド上で実行され、あるシーケンスで開始する場合も多いです。このシーケンスはすべて同じフレーム内で発生するため無関係であるはずですが、重要な場合もあります。
複雑な Parallel ノードの代わりに、Unreal Engine のビヘイビアツリーでは、Simple Parallel ノードと特殊なノード タイプである サービス 、そして デコレーター の Observer Aborts プロパティを使用することで、同様の動作を実現しています。
Simple Parallel ノード
Simple Parallel ノードは、2 つの子ノードのみを持つことができます。1 つはシングル Task ノード (オプションのデコレーター) でなければならず、もう 1 つは完全なサブツリーです。Simple Parallel ノードは、「A をしている間に B もするノード」と考えてみてください。例えば、「敵を攻撃しながら、敵に向かって前進する」という状況です。A がプライマリ タスクになり、B は A の完了を待機している間のセカンダリ、あるいはフィラー タスクです。
セカンダリタスク (タスク B) の処理方法についてはいくつかのオプションがありますが、このノードは従来の Parallel ノードに比べて概念的には、比較的単純です。単純ではありますが、Parallel ノードが提供する一般的な使用法のほとんどをサポートしています。Simple Parallel ノードでは、イベント駆動の最適化を簡単に使用できますが、Full Parallel ノードでは、最適化がはるかに複雑になります。
Services
サービス は、任意の Composite ノード (Selector、Sequence、または Simple Parallel) に関連付けられた特別なノードであり、指定した秒数ごとにコールバックを登録し、定期的に発生する必要のあるさまざまな種類の更新を実行することができます。
たとえば、あるサービスを使用すると、Pawn はその Behavior Tree で現在の敵に向かって正常に動作し続けながら、AI Pawn が追跡するのに最適な敵を判断できます。
そのサービスが追加された Composite ノードのサブツリーに実行中のツリーが残っている限り、サービスはアクティブのままです。
Observer Aborts
標準的な Parallel ノードの一般的な使用例の 1 つは、常に条件をチェックし、タスクが必要とする条件が偽になった場合にタスクを中断できるようにすることです。
たとえば、「Hiss」や「Pounce」などのシーケンスを実行する猫がいる場合、マウスが穴の中に逃げ込んだらすぐに諦めるという処理を実行できます。Parallel ノードを使うと、マウスに飛びかかることができるかどうかを子ノードが確認し、別の子ノードがシーケンスを実行します。Unreal Engine のビヘイビアツリーは、イベント駆動型であるため、条件式デコレーターに値を監視させて、必要に応じて中断します。この例では、シーケンス上に「Observer Aborts」設定が「Self」に設定されている「Mouse Can Be Pounced On?」デコレーターがあるだけです。
同時動作での Unreal Engine のアプローチのメリット
Unreal Engine が同時動作を処理する方法には、主に 次の 3 つのメリットがあります。
-
明確さ- サービスと Simple Parallel ノードを使用すると、わかりやすくシンプルなツリーが作成されます。
-
デバックのしやすさ- グラフが明確になると、デバッグが簡単になります。また、同時実行パスが少ないほど、何が実行されているかがわかりやすくなります。
-
最適化のしやすさ - イベント駆動型のグラフは、同時に多数のサブツリーが実行されていなければ、最適化が簡単です。