ビヘイビア ツリーまたは有限ステート マシンを使用して、コードを 1 行も使用せずに、真に複雑な AI を作成します。AI システムはユニバーサルなので、ゲームのあらゆる側面に動作を適用できます。敵 AI の作成以外にも、ドアや移動するプラットフォームをプログラムしたり、保存システムを設計したり、複雑なロジックを必要とするユーティリティを作成したりできます。
AI を実装する 2 つのクラスは、AITree と AIFSM です。AI を作成する前に、動作の複雑さについて考えておく必要があります。通常、単純な AI には FSM を使用します。これは、一般的に作成が高速になるためです。ビヘイビア ツリーは、FSM で処理するには状態が多すぎる AI に使用してください。
どちらの AI システムも、動作を作成するためにノードを使用します。システム自体には 40 を超えるノードが付属しており、すぐに実用的な AI を作成するための多くの機能を備えています。ただし、システム内のどのノードも必要な動作を提供しない場合があります。その場合は、いつでもこのニーズを満たすノードを作成できます。以下は、インスペクターでこれらのクラスがどのように表示されるかを示した例です。


Behavior Tree
ビヘイビア ツリーは、有限ステート マシンの代替手段を提供します。ビヘイビア ツリーは、状態の概念から離れ、代わりに階層ノードを使用してアクションを実行します。これにより、開発者はツリーにビヘイビアを柔軟に追加でき、状態ジャンプ ロジックを気にすることなく、非常に複雑な設計を作成できます。
仕組み:
ツリーは常に左から右、上から下の順に実行されます。
つまり、ツリーの最も左で最も高いノードが、より低いノードよりも優先されます。
優先度の高いノードがアクティブでなくなると、ツリーは次の最も高いノードを評価します。
システムがフレームごとにツリー全体を再評価しないことに注意してください。
これは、ツリーを効率的にし、現在アクティブなノードのみを実行する必要があるため、良いことです。
ツリーが非アクティブな優先度のノードをチェックできるように、システムは割り込みチェックを実装します。割り込みチェックを有効にする必要があり、各複合ノードにあります。
Nodes
213 / 5,000
各ノードには、次の 3 つの状態のうち 1 つ以上があります。
- Success: ノードは実行を終了し、成功しました。
- Failure: ノードは実行を終了し、失敗しました。
- Running: ノードはまだ実行中です。
ノードには次の 4 つのタイプがあります:
Conditional Node
成功または失敗を返します。
その主な目的は、プレイヤーが近くにいるかどうかを確認するなど、ゲーム ワールド内の条件をテストし、それに応じてツリーがアクション ノードを実行できるようにすることです。
Action Node
ゲーム ワールドでの状態を変更して AI を変更します。
たとえば、AI に速度を適用して、プレイヤーに向かって移動するようにします。
これらのノードは通常、Running を返します。
Composite Node
このノードは、子ノードのリストを実行します。
複合ノードにはさまざまなタイプがあり、タイプによってこれらの子ノードの実行方法が決まります。
たとえば、シーケンスは、Failure を返すノードが見つかるまで、子ノードを順番に実行します。並列は、すべての子ノードを同時に実行します。
各複合ノードには、デフォルトのアニメーション信号を有効にするオプションもあります。
Decorator Node
このノードは子ノードを 1 つだけ持つことができ、子ノードの出力または動作を変更します。たとえば、子ノードを時間遅延後に実行したり、子ノードの出力を反転したりする必要がある場合があります。
パトロール AI の非常に基本的な例を見てみましょう。
シーケンスには 2 つの子ノードがあります。
最初のノードである条件は、プレイヤーが範囲内にいるかどうかを確認します。
2 番目のノードであるアクションは、AI をプレイヤーの方向に移動させます。
条件が成功を返した場合にのみ、シーケンスは 2 番目のノードを実行します。条件が失敗を返した場合、AI はプレイヤーを追跡しません。
Blackboard data
ビヘイビアツリーは、ノード間で共有できるデータであるブラックボードデータも実装します。
ブラックボードデータは 3 つのカテゴリに分かれており、各カテゴリは独自のタブ内に存在します。
Targetは、AI が検出や追跡の目的で使用するオブジェクトまたはポイントです。ターゲット プレーヤーが最も一般的ですが、もちろんターゲットは変換やベクター ポイント、さらにはマウスにすることもできます。
Territoryは、検出に使用されるゲーム ワールド内の長方形の領域です。
たとえば、Find Target ノードは、プレーヤーが指定された領域に入った場合に AI に警告します。領域はシーン内でドラッグしてサイズを変更できます。他の 2 つの領域はパス検索用です。
Variableは、ノードによって共有および変更される必要があるデータです。
2 つのノードが同じリストを変更する必要がある場合があり、その場合は TransformListVariable を作成することがあります。もちろん、システムは変数の一般的なデータ タイプをすべて実装します。
2 つの特別な変数を強調することが重要です。
Behavior Tree を使用する場合、各 AI には Reset と呼ばれるブール変数が自動的に含まれます。これは削除できません。このブール値は、WorldManager がゲームのリセットをトリガーすると true に設定されます。
ツリー内のどこかで、通常は最高の優先度で、Variable Logic ノードがリセット ブール値を読み取り、ブール値が true になると AI がリセットされます (位置またはヘルスがリセットされる可能性があります)。次に、Set Value ノードを使用してこのブール値を false に設定する必要があります。
もちろん、これはオプションです。AI をリセットする必要がない場合は、リセット ブール値を完全に無視できます。
AI クラスの ResetAI メソッドを呼び出して、このイベントを手動でトリガーすることもできます。
Tree 変数は通信にとって非常に重要です。
2 つの異なる AI システムが相互に通信する必要がある場合は、AI クラスの参照をこの変数にドロップするだけです。AI のすべての黒板データは、Tree 変数を実装する AI で使用できるようになります。つまり、2 つの AI システムは同じ変数を読み取り、変更できます。
作成する各ブラックボードデータには、一意の名前を付ける必要があります。このデータは、作成されると、それを必要とするすべてのノードですぐに使用できるようになります。
たとえば、Follow Target ノードには、Blackboard タイプの target というパブリック メンバーがあります。フィールドがこのタイプである場合は、インスペクターでそれをクリックし、使用可能なドロップダウン メニューからオプションを選択するだけです。これで完了です。
ノードを最初から作成していて、ブラックボードデータが必要な場合は、Blackboard タイプをパブリック メンバーとして追加し、名前を付けるだけです。
Tips
黒板データの名前が変更された場合は、それを使用しているノードをクリックして参照を更新してください。
Node Editor Window

AITree を使用する場合、ノードを作成してノード階層を構成するには、ノード エディターが必要です。Unity で、[Window/BehaviorTreeEditor] に移動して、ノード エディター ウィンドウを開きます。ウィンドウはズームしたりドラッグしたりできます。
次に、ゲーム オブジェクトを選択し、AITree コンポーネントを追加します。すると、エディターに 1 つのノードが表示されます。これはルートです。ルートは、ビヘイビア ツリーへのエントリ ポイントであり、すべてのノードとブランチはルートに属します。
ノード エディターの任意の場所を右クリックすると、ノードのコンテキスト メニューが表示されます。作成するノードを選択すると、そのノードもノード エディターに表示されます。AITree のインスペクターに移動します。新しく作成されたノードを選択すると、[インスペクト] タブにこのノードが表示されます。ここで、ノードのパブリック フィールドを変更します。したがって、ノード エディター ウィンドウとインスペクターの両方を使用して、ビヘイビア ツリーを作成します。

必要なノードを作成したら、それらを接続します。接続を確立できる各ノード (Root, Composites, Decorators) の左側には円が表示されます。この円をクリックしてから、接続するノードに移動し、ノードの上部 (黒いマークがある場所) をクリックします。接続が機能すると、2 つのノードを接続する青い線が表示されます。
念のため、ビヘイビア ツリーは左から右、上から下に実行されます。ノードに 2 つの子がある場合、左側にある子ノードが優先されます。もう 1 つの子ノードをクリックしてドラッグし、最初のノードの左側に移動すると、システムは自動的にこのノードをより高い優先順位に設定します。
任意のノードを右クリックすると、別のコンテキスト メニューが表示されます。ノード自体またはノードに属するブランチ全体を削除できます。ノードを複製できます。ノードに必要な数のメモを追加することもできます。メモをクリックすると、インスペクタに表示され、必要な情報を入力できます。これらのメモは、利便性のために移動したりサイズを変更したりできます。
ブランチ テンプレートを作成することもできます。
たとえば、他のビヘイビア ツリーで再作成したい単純なパトロール ブランチがある場合、これをテンプレートとして保存して、後でいつでも再作成できます。これらのテンプレートは、ノードのコンテキスト メニューで使用できます。現時点では、これらのテンプレートに名前を付ける唯一の方法は、メモを作成することです。そのメモに入力したものがテンプレートの名前になります。不要になった場合は、メモを削除するだけです。
ゲームがプレイ モードになると、アクティブなノードと接続がデバッグ用に緑色に変わります。
Tips
In the upper left corner, change the color of editor background.
Interrupts
ビヘイビア ツリーには通常、優先度の低いブランチと高いブランチがあります。優先度の低いブランチが実行されると、デフォルトでは、システムは優先度の高いブランチを実行する必要があるかどうかをチェックしなくなります。これは、システムが各フレームでツリーを最初から実行しないようにするためです。この問題を回避するために、優先度の高いブランチが優先度の低いブランチを中断できるように割り込みが実装されています。
たとえば、AI がプレイヤーを追跡しているが、その過程でプレイヤーが AI を殺し、AI のヘルス チェックを担当するノードがチェックされなくなった場合、AI は自分が死んだことを認識しません。このシナリオを回避するには、優先度の高いブランチで割り込みを有効にして、システムが常に AI のヘルス チェックを行うようにする必要があります。
また、どのブランチも自分自身を中断できることにも注意してください。たとえば、次のシナリオでは、AI はプレイヤーを追跡するタスクを負っていますが、プレイヤーが AI の領域内にいる場合のみです。プレイヤーが領域内にいる場合、AI は盲目的にプレイヤーを追跡し始めます。ブランチは初期条件がTrueであるかどうかをチェックしなくなるため、プレイヤーがテリトリーの外に出ても AI はそれを認識できず、追跡を続けます。このシナリオを回避するには、ブランチで自己割り込みを有効にして、プレイヤーがテリトリー内にいるかどうかを常にチェックする必要があります。
割り込みは、コンポジットの最初の子ノードのみをチェックします。子ノードが条件付きの場合、システムは成功をチェックします。子ノードがコンポジットの場合、コンポジットに入り、その最初の子が条件付きであるかどうかなどをチェックします。他のタイプのノードはすべて無視されます。
Interrupts | |
---|---|
None | ノードは割り込みをチェックしません。 |
This Node | ノードは自身のブランチを中断できるようになります。ノードの上に下向き矢印が表示されます。 |
Lower Priority Nodes | ノードは優先度の低いノードに割り込みます。ノードの上に上向きの矢印が表示されます。 |
This And Lower Priority Nodes | ノードは自身を中断し、優先順位の低いノードを中断します。 |
Terminate Immediately | 有効にすると、優先度の低いノードが中断された場合、ノードはジョブを終了し、中断を続行できるようになります。 |
Cancel Interrupt And Complete | 有効にすると、優先度の低いノードが中断された場合、中断をキャンセルして実行を続行します。ノードの上に黒いブロックが表示されます。 |
以下は、架空の例です。ノードは実際には何もしませんが、割り込みが理論的にどのように機能するかを示しています。

Inspector
Property | |
---|---|
AI Type | Regular: AI は重力の影響を受け、レイキャストを介してゲームの世界と対話できます。BoxCollider2D が必要になります。 No Collision Checks: これは通常と完全に逆です。これは、世界との複雑な対話を必要としない AI 向けです。 Moving Platform: AI が移動プラットフォームである場合、移動プラットフォームはゲームの世界にある他のすべてのオブジェクトよりも先に実行されるため、適切に機能するにはこの設定になっていることを確認してください。移動プラットフォームは軸上で回転してはいけません。最新バージョンでは、重力を有効にすると通常の AI のように動作します。 |
Collision And Gravity | これらの設定についてはPlayerを参照してください。 |
Damage | 有効になっており、AI に Collider2D がある場合、指定されたレイヤー上に存在する Health コンポーネントを持つすべてのオブジェクトにダメージを与えます。 |
Create Units | AI が同じ AI ロジックで動作するユニットのグループの一部である場合、これを使用して必要な数のユニット (ゲームオブジェクト) を作成します。FSM または BehaviorTree に変更を加えるたびに、このボタンを押してユニットを再作成し、すべてのユニットが同じコードを持つようにします。システムは、表面的な変換設定を一意に保つために最善を尽くします。 |
Reset To First | FSM の場合、これが有効になっていると、システムはグローバル リセット時に最初の状態に移行します。これは、リセット状態が空の場合にのみ発生します。 それ以外の場合は、リセット状態が完了すると、システムは自動的に最初の状態に移行します。 |
Turn Off Signals | AI がアニメーション信号を必要としない場合は、これを有効にして基本的なアニメーション信号の設定を停止します。 |
FSM
Finite state machine(FSM)は、AI を作成するための直感的なアプローチを提供します。状態の数が少ない限り、状態によってロジックの推論が容易になります。したがって、最も基本的な AI を設計する場合は、FSM の使用が最初の選択肢になります。
ビヘイビア ツリーで使用できるすべてのノードは、FSM でも使用できます。ただし、複合ノードとデコレータ ノードは除きます。これらの概念はここでは無関係です。
ステート(States)には 3 つの種類があります。
まず、Normal States (青で表示) があります。
これらのステートの最初のものは、ステートマシンへのエントリ ポイントになります。ステートマシンの実行中は、これらのステートのうち 1 つだけが一度にアクティブになります。これらのステートを作成するには、インスペクターの下部にある青いボタンをクリックします。
次に、Always States (紫で表示) があります。
これらの状態は常に実行されます。これは、この種の機能が必要になる場合があるためです。これらの状態は技術的にはステートマシンの一部ではないため、Always Stateからステートをジャンプすることはできません。これらのステートには、各ステートに適用可能なコンテンツが含まれている必要があります。これらを作成するには、インスペクターの下部にある紫色のボタンをクリックします。
最後はReset State (赤で表示) です。
この状態は、WorldManager がゲーム リセットを実行するときに呼び出されます。リセット状態が使用される場合、1 フレームで発生し、衝突はチェックされません。この状態を使用して、AI の位置、health、およびその他の重要な変数をリセットします。
状態バーには重要なオプションがいくつかあります。最初のフィールドでは、ノードの実行方法を選択できます。
Parallel が有効になっている場合、すべてのノードが同時に実行されます。
Sequence が有効になっている場合、ノードは順番に実行されます。つまり、現在のノードが成功または失敗するまで、システムは次のノードに移動しません。このシーケンスは常に自動的にループします。
SequenceSucceed が有効になっている場合、現在のノードが成功した場合にのみシステムが次のノードに移動することを除いて、Sequence と同じように動作します。
2 番目のフィールドは折りたたみボタンです。これを開いて状態に名前を付け、デフォルトのアニメーションシグナルを設定します。このシグナルが有効になっている場合、システムはステートの実行中にこれを true に設定します。削除ボタンを押すとステートが削除されます。追加ボタンをクリックしてノードのコンテキスト メニューを開き、必要なノード (オレンジ色で表示) を作成します。
すべてのノードは 3 つの状態 (Success, Failure, Running) のいずれかになる可能性があるため、システムはこれを使用して次のステートにジャンプするタイミングを判断します。したがって、ほとんどのノードには、Success時とFailure時の 2 つのオプションが装備されています。白い矢印を切り替えると、これらのオプションが表示されます。どちらかが有効になっている場合、白い矢印は青に変わります。ノードに白い矢印がない場合は、このノードからステートをジャンプできないことを意味します。実行時に、Success時またはFailure時の条件が満たされると、システムは指定されたステートにジャンプします。
以下は単純な FSM です。
AI はプレイヤーを追跡するタスクを負っています。
プレイヤーが AI にダメージを与えると、AI は押し戻され、待機状態になります。そこで指定された時間待機します。クロック タイマーが完了すると、成功時のオプションによって、追跡状態への状態ジャンプがトリガーされます。

AI Attacks, Damage
AI が他のキャラクターを攻撃する方法は 4 つあります。
まず、AI オプションで Damage を有効にします。
システムは AI の既存のコライダーを使用します。キャラクターが AI と接触すると、ダメージを受けます。
2 番目は、非常によく似た方法で、Damage クラスを使用します。
このコンポーネントを任意のゲーム オブジェクトに追加するだけです。Collider2D を追加し、isTrigger を有効にします。これは、スパイクなどの静的オブジェクトに特に便利です。
Property | |
---|---|
Layer | ダメージが与えられるレイヤー。通常はPlayerです。 |
Direction | ダメージの方向。AI_X_Direction は、AI の相対的な位置に応じて、負傷者を左または右に移動します。 |
Amount | 与えるダメージの量。 |
Force | ダメージの方向に加えられる力。 |
3 番目に、AI は Firearm を使用して発射物を発射できます。
ロジックのどこかで、OnEvent ノードを使用します。このイベントは、Firearm クラスに属する Shoot() メソッドをトリガーする必要があります。
4 番目に、MeleeAttack ノードを使用します。
このノードがアクティブになると、別のコライダーが有効になり、キャラクターにダメージを与えることができます。近接攻撃の攻撃アニメーションは、別の場所で設定および実行されます。MeleeAttack ノードは、ダメージを与え、コライダーを有効にし、アニメーション信号を設定することのみを担当します。SpriteEngine を使用してアニメーションを再生し、コライダーのサイズと位置を制御できます。アニメーションの再生が終了したら、MeleeAttack クラスの CompleteAttack() メソッドを呼び出す必要があります。そうしないと、Finite state machineが現在の状態で停止します。