
ビデオゲーム業界では、人工知能(AI)は一般にノンプレイヤーキャラクターによる意思決定と呼ばれます。 単純な場合もあります。敵はプレイヤーを見て攻撃します。 または、より複雑な、たとえば、リアルタイム戦略におけるAI制御の敵。
アンリアルエンジンでは、 ビヘイビアツリーを使用してAIを作成できます。 動作ツリーは、AIが使用する動作を決定するためのシステムです。 たとえば、彼は戦うか走る行動をするかもしれません。 体力が高い場合、AIがプレイヤーと戦うビヘイビアツリーを作成できます。 50%未満の場合は、逃げます。
このチュートリアルでは、次のことを学びます。
- Pawn要素を制御できるAIエンティティを作成します
- ビヘイビアツリーと黒板を作成して使用する
- AI Perceptionを使用してPawn Sightを提供する
- Pawnが敵を歩いて攻撃できるようにビヘイビアを構築する
注:この記事は、Unreal Engineチュートリアルシリーズの9つのパートの1つです。
- パート1:エンジンの紹介
- パート2:ブループリント
- パート3:材料
- パート4:UI
- パート5:簡単なゲームを作成する方法
- パート6:アニメーション
- パート7:サウンド
- パート8:パーティクルシステム
- パート9:人工知能
- パート10:シンプルなFPSを作成する方法
仕事を始める
空白のプロジェクトをダウンロードして解凍します。 プロジェクトフォルダーに移動し、 MuffinWar.uprojectを開きます 。
[ プレイ]をクリックしてゲームを開始します。 囲まれた領域内を左クリックして、マフィンを作成します。
GIF

チュートリアルのこの部分では、画面をローミングするAIを作成します。 敵のマフィンがAIの視野に入ると、敵に近づいて攻撃します。
AIキャラクターを作成するには、3つのものが必要です。
- 体:キャラクターの物理的形態。 私たちの場合、体はマフィンです。
- 魂:キャラクターを制御するエンティティ。 プレーヤーまたはAIにすることができます。
- 脳: AIが決定を下す方法。 脳はさまざまな方法で作成できます。たとえば、C ++コード、ブループリント、ビヘイビアツリーを使用できます。
私たちはすでに身体を持っているので、魂と脳が必要です。 まず、「魂」となるコントローラーを作成します。
コントローラーとは?
コントローラーは、Pawnに生息できる非物理的なアクターです。 紹介することで、コントローラーが(ご想像のとおり)Pawn を制御できるようになります。 しかし、この文脈で「統治」とはどういう意味ですか?
プレーヤーにとって、これはPawnキーを押すと何かが行われることを意味します。 コントローラーはプレイヤーの入力を受け取り、入力をPawnに送信します。 また、コントローラーは入力自体を処理し、Pawnにアクションを実行するように命令できます。

AIの場合、Pawnはコントローラーまたは脳から情報を受け取ることができます(実装方法によって異なります)。
AIを使用してマフィンを制御するには、AIコントローラーと呼ばれる特別なタイプのコントローラーを作成する必要があります。
AIコントローラーの作成
Characters \ Muffin \ AIに移動し、新しいブループリントクラスを作成します。 AIControllerを親クラスとして選択し、 AIC_Muffinという名前を付けます。

次に、マフィンに新しいAIコントローラーを使用するように指示する必要があります。 Characters \ Muffin \ Blueprintsに移動し、 BP_Muffinを開きます 。
デフォルトでは、詳細パネルにデフォルトのブループリント設定が表示されます。 そうでない場合は、ツールバーの「 クラスのデフォルト」をクリックします。

[詳細]パネルに移動し、[ ポーン]セクションを見つけます。 AI Controller ClassをAIC_Muffinに設定します 。 これにより、マフィンを作成するときにコントローラーのインスタンスが作成されます。

マフィンを動的に作成するため、 Auto Possess AIの値をSpawnedに設定する必要もあります。 したがって、 AIC_Muffinは作成時にBP_Muffinを自動的に設定します。

[ コンパイル]をクリックし、 BP_Muffinを閉じます 。
次に、マフィンの動作を制御するロジックを作成します。 これにはビヘイビアツリーを使用できます。
ビヘイビアツリーの作成
Characters \ Muffin \ AIに移動して、 Add New \ Artificial Intelligence \ Behavior Treeを選択します。 BT_Muffinと名前を付けて開きます。
ビヘイビアツリーエディタ
ビヘイビアツリーエディタには2つの新しいパネルがあります。

- 動作ツリー:これは、動作ツリーのノードを作成するグラフです
- 詳細:選択したノードのプロパティがここに表示されます。
- 黒板:このパネルには、黒板キー(後で詳しく説明します)とその意味が表示されます。 ゲームの実行中にのみ表示されます。
ブループリントと同様に、動作ツリーはノードで構成されます。 動作ツリーには4つのタイプのノードがあります。 最初の2つはtaskとcompositeです。
タスクとコンポジットとは何ですか?
名前が示すように、タスクは何かを「行う」ノードです。 コンボチェーンなどの複雑なものでも、待機などの単純なものでもかまいません。

タスクを実行するには、コンポジット(コンポジット)を使用する必要があります。 ビヘイビアツリーは、多くのブランチ(動作)で構成されています。 各ブランチのルートにはコンポジットがあります。 異なるタイプのコンポジットには、子ノードを実行する異なる方法があります。
次の一連のアクションがあるとします。

Sequenceは子ノードを左から右に実行するため、各アクションを順次実行するには、 Sequenceコンポジットを使用する必要があります。 これは次のようになります。

注:コンポジットで始まるものはすべてサブツリーと呼ぶことができます。 通常、これらは動作です。 この例では、「 シーケンス」 、 「敵に移動」 、 「敵に向かって回転」、および「攻撃」は「敵を攻撃する」と考えることができます。
Sequence子ノードのいずれかが実行に失敗すると、Sequenceは実行を停止します。
たとえば、Pawnが敵に向かって移動できない場合、 Move To Enemyは失敗します。 これは、 敵への回転と攻撃が完了しないことを意味します。 ただし、ポーンがなんとか敵に向かって移動できれば、それらは満たされます。
後で、 セレクターコンポジットについても学習します。 ここでは、Pawnがランダムなポイントに移動して待機するようにSequenceを使用します。
ランダムポイント移動
シーケンスを作成し、それをRootに接続します。
GIF

次に、Pawnを移動する必要があります。 MoveToを作成し、それをSequenceに接続します。 このノードは、Pawnを指定されたポイントまたはアクターに移動します。

次に、 待機を作成し、それをSequenceに接続します。 このノードはMoveToの右側に配置する必要があります。 子ノードは左から右に実行されるため、ここでの順序は重要です。

注:各ノードの右上隅にある数字を見て、実行順序を確認できます。 値が低いほど、ノードの優先度が高くなります。
おめでとうございます、あなたはあなたの最初の振る舞いを作成しました! Pawnを選択したポイントに移動し、5秒間待機します。
Pawnを移動するには、ポイントを指定する必要があります。 ただし、 MoveToはblackboardからのみ値を受け取ることができるため、作成してみましょう。
黒板作成
Blackboardは、変数( キーと呼ばれる)を保存することを唯一の目的とするリソースです。 AIの記憶と考えることができます。
必須ではありませんが、黒板はデータを読み取り、保存する便利な方法を提供します。 ビヘイビアツリーの多くのノードは黒板キーしか受信できないため、便利です。
黒板を作成するには、コンテンツブラウザに戻り、[ 新規追加] \ [ 人工知能] \ [黒板]を選択します。 BB_Muffinと名前を付けて開きます。
黒板エディター
黒板エディターは2つのパネルで構成されています。

- 黒板:このパネルにはキーのリストが表示されます
- 黒板の詳細:このパネルには、選択したキーのプロパティが表示されます
次に、ターゲットポイントを含むキーを作成する必要があります。
ターゲットポイントキーを作成する
ポイントを3D空間に保存するため、ベクトルとして保存する必要があります。 [ 新しいキー]をクリックし、[ ベクター]を選択します。 TargetLocationという名前を付けます。

ここで、ランダムポイントを生成して黒板に保存する方法が必要です。 これを行うには、ビヘイビアツリーの3番目のタイプのノードであるserviceを使用します。
サービスとは?
サービスは、私たちが何かをするタスクに似ています。 ただし、Pawnに強制的にアクションを実行させる代わりに、サービスを使用してチェックを実行したり、黒板を更新したりします。
サービスは個別のノードではなく、タスクまたは複合を結合します。 これにより、より少ないノードで作業する必要があるため、より順序付けられたツリーが作成されます。 タスクの使用方法は次のとおりです。

そして、サービスの使用方法は次のとおりです。

これで、ランダムポイントを生成するサービスを作成できます。
サービス作成
BT_Muffinに戻り、[ 新しいサービス ]をクリックします 。

新しいサービスが作成され、自動的に開かれます。 BTService_SetRandomLocationという名前を付けます。 名前を変更するには、コンテンツブラウザに戻る必要があります。
Pawnを移動する必要がある場合にのみ、サービスを実行する必要があります。 これを行うには、 MoveToに添付します 。
BT_Muffinを開き、 MoveToを右クリックします 。 [ サービスの追加] \ BTService [ ランダムな場所の設定]を選択します。

MoveToがアクティブになると、 BTService_SetRandomLocationがアクティブになります。
次に、ランダムなターゲットポイントを生成する必要があります。
ランダムポイント生成
BTService_SetRandomLocationを開きます 。
サービスがいつアクティブ化されるかを調べるには、 イベント受信アクティブ化AIノードを作成します。 親がアクティブ化されたときに実行されます(親が接続されているノード)。

注:同じことを行うイベント受信アクティベーションイベントもあります。 2つのイベントの違いは、 イベント受信アクティベーションAIがControlled Pawnも提供することです。
ランダムポイントを生成するには、選択したノードを追加します。 Radiusを500に設定します。

これにより、到達可能なPawnの500単位内でランダムなポイントが得られます。
注: GetRandomPointInNavigableRadiusは、ナビゲーションデータ( NavMeshと呼ばれる)を使用して、ポイントに到達できるかどうかを判断します。 このチュートリアルでは、事前にNavMeshを作成しました。 ビューポートに移動し、 表示\ナビゲーションを選択することで視覚化できます。

独自のNavMeshを作成する場合は、 Nav Mesh Bounds Volumeを作成します。 スケールを変更して、移動可能な領域を制限します。
ここで、ポイントを黒板に保存する必要があります。 使用するキーを選択するには、2つの方法があります。
- 「リテラル名の作成」ノードでキーの名前を使用して、キーを指定できます。
- 変数をビヘイビアツリーから見えるようにすることができます。 これにより、ドロップダウンリストからキーを選択できます。
2番目の方法を使用します。 Blackboard Key Selectorタイプの変数を作成します。 BlackboardKeyという名前を付けて、 Instance Editableをオンにします。 これにより、動作ツリーでサービスを選択するときに変数が表示されます。

次に、次の選択されたノードを作成します。

要約すると:
- Event Receive Activation AIは、その親がアクティブ化されると実行されます(この場合はMoveToです )
- GetRandomPointInNavigableRadiusは、マネージドマフィンから半径500単位内のランダムなナビゲーション可能ポイントを返します
- 黒板の値をベクトルとして設定は、黒板のキー( BlackboardKeyを介して送信される)をランダムなポイント値に設定します
[ コンパイル]をクリックし、 BTService_SetRandomLocationを閉じます 。
次に、黒板を使用する必要があることをビヘイビアツリーに伝えます。
黒板の選択
BT_Muffinを開き、何も選択されていないことを確認します。 [詳細]パネルに移動します。 動作ツリーで 、 Blackboard AssetをBB_Muffinに設定します 。

その後、 MoveToとBTService_SetRandomLocationは最初の黒板キーを自動的に使用します。 この例では、これはTargetLocationです。

最後に、ビヘイビアツリーを開始するようAIコントローラーに指示する必要があります。
実行ツリーの動作
AIC_Muffinを開き、 Run Behavior TreeをイベントBeginPlayに接続します 。 BTAssetにBT_Muffinを選択します 。

そのため、 AIC_Controllerの作成時にBT_Muffinが起動されます。
[ コンパイル]をクリックして、メインエディターに戻ります。 [ 再生]をクリックして、マフィンを作成し、画面内をさまよう様子を観察します。
GIF

私たちは一生懸命働かなければなりませんでしたが、やりました! 次に、視野内の敵を認識するようにAIコントローラーを構成する必要があります。 これにはAI Perceptionを使用できます。
AI知覚を構成する
AI知覚は、アクターに追加できるコンポーネントです。 これを使用して、AIの感情 (視覚や聴覚など)を与えることができます。
AIC_Muffinを開き、 AIPerceptionコンポーネントを追加します。

次に、感情を追加する必要があります。 マフィンに視界に入る別のマフィンを認識させるため、 ビジョンを追加する必要があります。
AIPerceptionを選択して、詳細パネルに移動します。 AI Perceptionセクションで、新しい要素をSenses Configに追加します。

AI Sight構成の要素0を設定し 、展開します。

ビジョンには3つの主要なパラメーターがあります。
- 視力半径:マフィンが見える最大距離。 値3000をここに残しましょう。
- 視力半径の喪失:マフィンが敵を見た場合、これは、マフィンが彼の視界を失うために敵が離れなければならない値です。 ここに値3500を残しましょう。
- 周辺視野の半分の角度:マフィンの視野角。 値を45に設定します。 これにより、マフィンに90度の視野角が与えられます。

デフォルトでは、AI Perceptionは敵(別のコマンドに割り当てられた俳優)のみを認識します。 ただし、デフォルトでは、アクターにはコマンドがありません。 アクターにコマンドがない場合、AI Perceptionはそれをニュートラルと見なします。
執筆時点では、ブループリントを使用してコマンドを割り当てる方法はありませんでした。 代わりに、AI Perpcetionに中立のアクターを認識するように指示するだけです。 これを行うには、[ 所属による検出]を展開し、[ 中性の検出]をオンにします。

[ コンパイル]をクリックして、メインエディターに戻ります。 [ 再生]をクリックして、マフィンを作成します。 'キーを押してAIデバッグ画面を表示します。 AI知覚を視覚化するには、 テンキーの 4を押します 。 マフィンが表示されると、緑色の球体が表示されます。
GIF

次に、マフィンを敵に向かって移動する必要があります。 これを行うには、行動ツリーが敵について知っている必要があります。 これは、黒板に敵へのリンクを保持することで実行できます。
敵の鍵を作成する
BB_Muffinを開き、 Object型のキーを追加します。 名前をEnemyに変更します。

キーがObject型であるため、これまでのところ、 MoveToでEnemyを使用することはできませんが、 MoveToはVectorまたはActor型のキーのみを受け取ることができます。
これを修正するには、[ 敵]を選択し、[ キータイプ]を展開します。 Base ClassをActorに設定します。 これにより、ビヘイビアツリーがEnemyをアクターとして認識することができます。

BB_Muffinを閉じます 。 次に、敵に向かって移動するための動作を作成する必要があります。
敵に向かう動き
BT_Muffinを開き、 SequenceをRootから分離します。 これを行うには、 Altキーを押しながら、それらを接続しているワイヤを左クリックします。 とりあえず、ランダム移動のサブツリーはそのままにしておきましょう。
選択したノードを作成し、 Blackboard KeyをEnemyに設定します:

同時に、PawnはEnemyに移動します。 場合によっては、ポーンが完全にターゲットに向かないため、 BBエントリに直面するために回転を使用する必要があります 。
ここで、AI Perceptionが別のマフィンを認識したときにEnemyを設定する必要があります。
敵のキー設定
AIC_Muffinを開き、 AIPerceptionコンポーネントを選択します。 On Perception Updatedイベントを追加します。

このイベントは、感情が更新されたときに実行されます。 私たちの場合、AIが誰かに気づいたとき、またはそれを見失ったときに実行されます。 このイベントは、感覚によって現在検出されている俳優のリストも伝えます。
選択したノードを追加します。 Make Literal NameがEnemyに設定されていることを確認してください 。

これにより、AIに既に敵がいるかどうかを確認できます。 そうでなければ、彼に敵を与えなければなりません。 これを行うには、選択したノードを追加します。

要約すると:
- IsValidは、 敵のキーが設定されているかどうかを確認します
- 設定されていない場合、その時点で発見されたすべてのアクターがループします
- Cast to BP_Muffinは、アクターがマフィンかどうかをチェックします
- 彼がマフィンである場合、彼が死んでいるかどうかを確認します
- IsDeadがfalseを返す場合、マフィンを新しい敵として設定し、ループを終了します
[ コンパイル]をクリックして、 AIC_Muffinを閉じます 。 [ 再生]をクリックし、2つのマフィンを作成して、一方が他方の前になるようにします。 奥にあるマフィンは、自動的に別のマフィンに移動し始めます。
GIF

ここで、マフィンが攻撃を実行するための独自のタスクを作成します。
攻撃タスクの作成
ビヘイビアツリーエディタの代わりに、コンテンツブラウザでタスクを作成できます。 新しいブループリントクラスを作成し、親クラスとしてBTTask_BlueprintBaseを選択します。

BTTask_Attackと名前を付けて開きます。 イベント受信実行AIノードを追加します。 このノードは、動作ツリーがBTTask_Attackを実行するときに実行されます 。

まず、マフィンを攻撃させる必要があります。 BP_Muffinには変数IsAttackingが含まれています。 設定されている場合、マフィンは攻撃を実行します。 これを行うには、選択したノードを追加します。

現在の状態でタスクを使用すると、ビヘイビアツリーはタスクが完了したかどうかを認識しないため、タスクの実行は停止します。 これを修正するには、チェーンの最後に「 実行を終了 」を追加します。

次にSuccessを有効にします。 Sequenceを使用しているため、 BTTask_Attackの後にノードを実行できます。

グラフは次のようになります。

要約すると:
- ビヘイビアツリーがBTTask_Attackを起動すると、 イベント受信実行AIが実行されます
- Cast to BP_Muffinは、 Controlled Pawnのタイプが BP_Muffinかどうかをチェックします
- はいの場合、そのIsAttacking変数が設定されます。
- Finish Executeは、タスクが正常に完了したことをビヘイビアツリーに認識させます
[ コンパイル]をクリックし、 BTTask_Attackを閉じます 。
ここで、 BTTask_Attackをビヘイビアツリーに追加する必要があります 。
ビヘイビアツリーへの攻撃の追加
BT_Muffinを開きます 。 次に、 BTTask_AttackノードをSequenceの最後に追加します。

次に、 シーケンスの最後に待機ノードを追加します。 Wait Time変数の値を2に変更します。 これにより、マフィンは常に攻撃しなくなります。

メインエディターに戻り、[ 再生 ]をクリックします。 前回と同様に、2つのマフィンを作成します。 マフィンは動き始め、敵の方に向きを変えます。 それから彼は攻撃し、2秒間待ちます。 彼が別の敵を見た場合、彼は同じシーケンスを再度繰り返します。

最後の部分では、攻撃のサブツリーとランダムな動きを組み合わせます。
サブツリーの連合
サブツリーを結合するには、 Selectorコンポジットを使用できます。 シーケンスと同様に、左から右にも実行されます。 ただし、子ノードが成功した場合、セレクターは停止し、失敗しません。 この動作を使用して、動作ツリーに1つのサブツリーのみを実行させることができます。
BT_Muffinを開き、 ルートノードの後にセレクターを作成します。 次に、次のようにサブツリーを接続します。

このようなスキームでは、一度に1つのサブツリーのみが実行されます。 各サブツリーの開始方法は次のとおりです。
- 攻撃: セレクターは、攻撃の最初のサブツリーを起動します。 すべてのタスクが正常に完了すると、 シーケンスも成功します。 セレクタはこれを検出し、実行を停止します。 これにより、ランダム移動のサブツリーは実行されません。
- ローミング:セレクターは最初に攻撃のサブツリーを実行しようとします。 Enemyが設定されていない場合、 MoveToは失敗します。 したがって、 シーケンスも失敗します。 攻撃サブツリーが失敗したため、 セレクターは次の子、つまりランダムな動きのサブツリーを実行します。
メインエディターに戻り、[ 再生 ]をクリックします。 いくつかのマフィンを作成して、作業をテストします。

待って、でもなぜマフィンはすぐに別のマフィンを攻撃しないのですか?
従来の動作ツリーでは、ルートからの更新ごとに実行が開始されます。 つまり、更新のたびに、ツリーは最初に攻撃のサブツリーを実行し、次にランダムな動きのサブツリーを実行しようとします。 これは、 敵の値が変更されると、動作ツリーが即座にサブツリーを変更できることを意味します。
ただし、アンリアルのビヘイビアツリーの動作は異なります。 Unrealでは、最後に実行されたノードから実行が継続されます。 AI知覚は他のアクターをすぐには感知しないため、ランダムな動きのサブツリーが実行を開始します。 これで、ビヘイビアツリーはランダム移動ツリーの完了を待機し、攻撃のサブツリーを実行する可能性を確認するだけです。
これを修正するために、ノードの最後のタイプであるdecoratorsを使用できます。
デコレータを作成する
サービスと同様に、デコレータはタスクまたはコンポジットに参加します。 通常、デコレータはチェックを実行するために使用されます。 結果がtrueの場合、デコレータもtrueを返し、その逆も同様です。 デコレータのおかげで、親要素の実行を制御できます。
さらに、デコレータにはサブツリーを終了する機能があります 。 これは、 敵が指定されている場合、ランダム移動サブツリーの実行を完了することができることを意味します。 したがって、マフィンは発見後すぐに敵を攻撃することができます。
終端を使用するには、 Blackboardデコレータを使用できます。 黒板キーが設定されているかどうかを確認するだけです。 BT_Muffinを開き、攻撃のシーケンスサブツリーを右クリックします 。 [ デコレータの追加] \ [ 黒板]を選択します。 同時に、Blackboardデコレータがシーケンスに追加されます。

次に、 Blackboardデコレータを選択して、詳細パネルに移動します。 Blackboard KeyをEnemyに設定します。

これにより、 敵が設定されているかどうかが確認されます。 設定されていない場合、デコレータは失敗し、 シーケンスは失敗します。 これにより、ランダム移動のサブツリーが開始されます。
ランダム移動サブツリーの実行を停止するには、 Observer Abortsパラメーターを使用する必要があります。
オブザーバーアボートの使用
オブザーバーを中止すると、選択した黒板キーが変更されたときにサブツリーが停止します。 終了には2つのタイプがあります。
- Self:このオプションにより、 敵が無効になったときに攻撃サブツリーの実行を停止できます。 これは、攻撃のサブツリーを完了する前に敵が死亡したときに発生する可能性があります。
- 低優先度:このオプションを使用すると、 Enemyを設定するときに低優先度でツリーの実行を停止できます。 ランダム移動サブツリーは攻撃後に配置されるため、優先順位は低くなります。
Observer AbortsをBothに設定して、両方のタイプの終了を有効にします。

これで、敵がいない場合、攻撃サブツリーは即座にランダムな動きに移行します。そして、ランダムな動きのサブツリーは、敵が検出されるとすぐに攻撃モードに切り替わります。
完成したビヘイビアツリーは次のようになります。

攻撃のサブツリーを要約するには:
- 敵が指定されている場合、セレクターは攻撃サブツリーを起動します
- 設定されている場合、ポーンは移動して敵の方に向きます
- その後、彼は攻撃を実行します
- 最後に、Pawnは2秒待機します。
ランダム移動のサブツリーを要約するには:
- セレクターは、攻撃サブツリーが失敗すると、ランダムサブツリーを開始します。私たちの場合、Enemyが指定されていないと失敗します。
- BTService_SetRandomLocationはランダムポイントを生成します
- ポーンは生成されたポイントに移動します
- それから彼は5秒待ちます
BT_Muffinを閉じて、[ 再生 ]をクリックします。マフィンをいくつか作って、最高のバトルロワイヤルの準備をしましょう!
GIF

次はどこに行きますか?
完成したプロジェクトはここからダウンロードできます 。
ご覧のとおり、単純なAIキャラクターの作成は非常に簡単です。より複雑なAIを作成する場合は、Environment Query Systemをご覧ください。このシステムにより、AIは環境に関するデータを収集し、それに応答できます。