GOAP(Goal Oriented Action Planning)
目次
1. はじめに
GOAPのQuantumコードとvisual editorはともにベータ版です。
1.1 GOAPとは
GOAP(Goal-oriented action planning)は、2つの部分からなるAIの手法です。
- S現在の状況に応じて、指定されたゴールのセットから最も適したゴールを選択。 ゴール(願望ともいう)には次のようなものがある。ターゲットを倒す、回復する、敵の旗を盗む、 敵から逃げる、など。
- 指定されたアクションプールから、このゴールを満たすアクションのセット(プラン)を見つける。 アクションには次のようなものがある。オブジェクトを見つける、ターゲットを見つける、オブジェクトを拾う (例:銃、敵の旗、ヘルスパック)、ポジションに行く、戦闘範囲に行く、撃つ
1.2 他のBotSDKのAIアプローチとの比較
FSM、HFSM、Behavior Treeなどの標準的なAIアプローチとは対照的に、
設計者が作成する正確なAI動作はありません。
AIエージェントは、どのような欲求を持ち、何ができるかを伝えられ、
正確なステップは、現在の状況(ワールドステート)に基づいて、ランタイムに組み立てられます(計画される)。
強み
* 複雑さをうまく処理する
新しいゴールやアクションを追加しても、
以前のAIの動作と自動的に連動するので 簡単
* 大規模プロジェクトの開発期間を短縮できる
十分な行動とゴールのセットを作成すると、異なる行動を持つ多くのAIエージェントに再利用できる
* 自然な(あいまいな)動作
AIの動作が自明でない場合、プレイヤーが求めない限りパターンを発見することはより困難になります。 効用/関連性/コストを計算するAIのように、多くの値が考慮されるので、同じような状況でもAIは少し異なる行動をとる可能性があります。
* 独自のソリューション
可能なアクションの数が多いと、AIが問題を解決する方法も増え、ユニークな解決策を見つけることができます。
これは良いことでもあり悪いことでもあります。
一方で、アクションの数が多すぎると、プランニングのパフォーマンスに影響を与えるため、慎重に対処する必要があります。
弱み
* プランニングの部分(適切なアクションのセットを見つけるプロセス)では、多くの可能性を評価する必要があるため、
GOAPは、より軽量なAIソリューション(FSMなど)よりも一般的に遅くなる可能性があります。
* 使いこなすのが難しい
GOAP AIを設計する際、ユーザーは複雑なワールドをいかにWorldStateの値に単純化するかを考え、
行動を直接指定するのではなく、GOAPアクションがこのWorldStateにどのような影響を与えるかを常に考える必要があります。
* AIが何をすべきか具体的に指示されないため、ボス戦などの「スクリプト」的なAIの動作を行うのは大変です。
GOAPの強みを最大限に活用するためには、アクションとゴールを慎重に設計する必要があります。
GOAPのアクションはアトミックであるべきです。つまり、より複雑なアクションは、
新たに作成されたアクションが異なる状況で異なるアクションを行うことができる場合に限り、複数のアクションに分割されるべきです。
例えば、複雑な_KillEnemyNest_アクションは、_FindNest_ , _GoToCombatRange_, _Attack_ アクションに分割することができます。このようなアプローチが不可能または望ましい場合は、より標準的なAIソリューションをすぐに使用する方が良いでしょう。
2. Quantum GOAP コーディング
2.1 実装
まず、GOAPをコードの観点から分析し、主に内部でどのように動作しているのかを、いくつかの画像例を使って理解してみましょう。
その後、Unity Editor上で直接分析することでフォローアップしていきます。
GOAPの核となる部分は、_GOAPManager_ にあります。マネージャー(GOAPの文脈では_planner_と呼ばれています)は、
最適なゴールを選択し、選択したゴールを満たすプラン(一連の行動)を構築し、可能であればプランからすべての行動を実行します。
可能な行動シーケンスの検索は、ワールドステートの差(ゴール状態と異なるワールドステートフラグの数)を
ヒューリスティックとするバックワードA*によって行われます。
BotSDK GOAPは、非常に高速で軽量ですが、特定のゲームのニーズに基づいてさらに拡張することもできます。
2.2 GOAPエージェントの作成と更新
ここでは、独自のエージェントを作成して更新するために必要な手順をご紹介します。
1. エンティティに `GOAPAgent` コンポーネントを追加します。これはUnity上のEntity Prototypesで
直接行うことができますが、フレームAPIを使ってQuantumコード内から直接行うこともできます。
2. 目的の `GOAPRoot` アセットを見つけて、それを初期化メソッドで使用します。
<pre><code class="language-csharp"> var goapRoot = frame.FindAsset<GOAPRoot>(playerData.GOAPRoot.Id);
GOAPManager.Initialize(frame, entity, goapRoot);</code></pre>
3. Updateメソッドを呼び出し、パラメータとしてエージェントエンティティを渡します。
<pre><code class="language-csharp"> GOAPManager.Update(frame, filter.Entity, frame.DeltaTime);</code></pre>
4. 必要に応じて、以下のようにエージェントの現在の状態を手動で設定します。
<pre><code class="language-csharp"> goapAgent->CurrentState.SetFlag();</code></pre>
2.3 GOAP 状態
<figure>
<img alt="World State" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-world-state.png">
</figure>
GOAPの状態は、**プランナーにとって関連性のある** ゲームの状態を表します。
各AIエージェント は自身のGOAP状態を持っています。我々の実装では、状態は_Positive_と_Negative_のビットマスクで表されます。
つまり、各ワールドステートフラグはtrue, false, not definedの3つの値を持つことができます。
フラグの正しいセットを選択することは、優れたGOAP AI設計にとって非常に重要です。普遍的なルールとして、
**フラグが計画中に変更できる場合にのみ、フラグはワールドステートに存在するできです**(つまり、GOAPアクションの_条件_または_効果_として使用される場合)
_例えば、以下のようなものがあります。他のゲームコードが `IsHungry` を使用していても、条件や効果として `IsHungry` を持つ GOAP アクションがなければ、
ワールドステートに `IsHungry` フラグを置く意味はありません。そのような場合には、カスタムエージェントのデータに `IsHungry` フラグを置くのが良いでしょう。_
ワールドステートにフラグを追加するには、`GOAPState.qtn`ファイルの`EWorldState enum`を編集する必要があります。
カスタムデータでワールドステートを拡張することも可能です。
### 2.4 GOAPのゴール
<figure>
<img alt="Goal Sample" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-goal-sample.png">
</figure>
**Target State**
プランニングの過程でプランナーがたどり着こうとする状態。
**Start State**
通常は空白にしておく。プランナーが計画プロセスを開始するとき、現在のエージェントの状態を取り、
それをゴールの_開始状態_にマージする。このマージされた状態は、FROM状態として機能し、_Target State_ はTO状態として機能する。
_注:通常、エージェントの状態から何らかのフラグをクリアして、特定のアクションが計画されるようにするために使用されます。_
**Validation**
ゴールが有効でない場合は、ゴール選択プロセスで考慮されません。
**Relevancy**
このゴールがどの程度関連しているかを示します。最も関連性の高いゴールがプランナーによって選択されます。
2つの有効なゴールが同じ関連性を持つ場合、ゴールのリストの上位のものが選択されます。
**Disable Time**
ゴールを再利用できるまでの時間。
_注: 無効化の時間は、それが状況の最良のゴールと考えられていても、AIエージェントに同じゴールを何度も連続して実行させたくない場合によく使われます
(例えば、敵に手榴弾を5発連続で投げさせたくない場合など)。
また、プランが見つからず(現在の状況では有効でない行動もある)、異なるゴールを選択する必要がある場合にも重要です。_
**IsFinished**
ゴールが達成されると、プランナーはこのゴールを非活性化し、新しいゴールの探索を開始します。
IsFinished がtrueであるか、エージェントのGOAP状態がゴールの Target State を含むとき、ゴールは満たされます。
**Interruption Behaviour**
有効なゴール(プラン)の実行を中断することができます。中断が有効な場合、プランナー は、より適切なゴールが存在するかどうかを定期的にチェックします。
存在する場合、現在のプランの実行が停止され、新たなゴールを計画します。
<pre><code class="language-"> ● Always - Always check whether more relevant goal exists
● Never - Plan is never interrupted
● Based On Actions - Active action controls if the plancan be interrupted</code></pre>
**OnInitPlanning**
プランが始まる前に実行されるアクション。
**OnActivate**
プランが正常に発見され、プランの実行が開始されたときに実行されるアクション。
**OnDeactivate**
ゴールが非アクティブになったときに実行されるアクション。
### 2.5 GOAP アクション
<figure>
<img alt="Action Sample" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-action-sample.png">
</figure>
**Conditions**
このアクションがプランで考慮されるために必要な状態。
**Effects**
このアクションがエージェントの状態に与える影響。
**Validation**
有効でないアクションは、プランニングの過程で考慮されません。
_注: こうすることで、実際に不要なフラグでワールドステートを複雑にすることなく、特定の状況下で特定のアクションを「無効」にすることができます。
ワールドステートのセクションで述べたように、ワールドステートは計画プロセス自体で変更可能なプロパティのみを含むべきです。_
**Cost**
アクションのコストを決定します。プランナーは総コストが最も低くなるアクションのシーケンスを見つけようとします。
アクションのコストはゼロより大きくなければなりません。通常、コストはアクションにかかる時間(秒)として考えるのがベストですが、
ある程度の妥当な範囲(例えば、0.5から5で、ほとんどのアクションは1前後)を保ちます。コストの差が大きすぎると、GOAPのパフォーマンスが低下することがあります。
詳しくは _最適化_ の項を参照してください。
**IsDone**
アクションが完了した場合、プランナーは計画の次のアクションを続行します。アクションは、_IsDone_ がtrueの場合、
またはエージェントの状態にすべての_Effects_が存在する場合に自動的に完了します。
**IsFailed**
アクションが失敗すると、プラン全体が失敗し、新しい最適なゴールの探索が再び始まる。
**Interruptible**
アクションを中断することができるかどうか。この設定を考慮するには、
現在のアクティブなゴールで _Interruption Behaviour_ が _Based On Actions_ に設定されている必要があります。
**OnActivate**
このGOAPアクションがアクティブになると、AIアクションが実行されます。
**OnUpdate**
このGOAPアクションが更新されると、AIアクションが実行されます。
**OnDeactivate**
このGOAPアクションが非活性化されたときに実行されるAIアクション。
**Plan State Validation**
プラン状態検証ノードは、高度なGOAP機能に使用されます。基本的には、
現在の計画状態に基づいて計画中のアクションを検証することを意味します。また、計画を分岐させる可能性もあります。
## 3. エディター
### 3.1 新しいGOAPをの作成
<figure>
<img alt="Create Document" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-create-document.png">
</figure>
エディタのトップバーで、(+)ボタンをクリックし、代替となるGOAPを選択します。
HFSMファイルを保存するよう促されます。お好きな場所に保存してください。
これで、**visual editorで行った** 作業を保持するために使用するデータアセットが作成されます。
<figure>
<img alt="GOAP Asset" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-ai-document.png">
</figure>
注:今選択した名前は、ビジュアルエディターで行った作業をコンパイルする際に、さらに生成される別のデータアセットの名前になります。
実際にボットを動かすために使用されるデータアセットとなりますので、示唆に富んだ名前を選択することができます。
ファイルを保存すると、Bot SDKのメインウィンドウにGOAPドキュメントの最も基本的なフォーマットが表示され、
その中に`GOAP Goals`と`GOAP Actions`という名前の2つのコンテナが表示されます。
<figure>
<img alt="GOAP Clean Document" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-clean-document.png">
</figure>
### 3.2 新しいGOAPゴールの作成
新しいゴールを作成するには、Bot SDKウィンドウの空いている場所を右クリックし、`GOAPDefaultGoal`を選択します。
より高度な設定では、独自のゴールを作成することができ、そのゴールも右クリックメニューに表示されます。
<figure>
<img alt="Create GOAL" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-create-goal.png">
</figure>
ルートレベルでは、修正されていないゴールノードは次のようになります。
<figure>
<img alt="GOAL Root Level" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-root-level-goal.png">
</figure>
また、ゴールノードをダブルクリックすることで、その詳細を見ることができます。
デフォルトのゴールには、あなたがAIに求めるものを表現するために記入するフィールドがたくさん用意されています。
<figure>
<img alt="GOAL Detailed" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goal-goal-detailed.png">
</figure>
ゴールの核となるのは、"Start State "と "Target State "の2つです。これらは `EWorldState` タイプのEnumで、
特定のGOAPエージェントの現在のワールドステートを表します(つまり、これは共有/グローバルステート **ではありません**)。
これらの状態は、エージェントの目的を達成する方法でゲームの状態を変更するゴールを選択する計画プロセスで使用されます。
世界状態フラグは、PositiveまたはNegativeで表現することができる。プランニングの過程で、プランナーは望ましい世界状態を適切に満たすゴールをフィルタリングします。これを少し例証してみましょう。
_注: ワール素材ステートの定義に関する詳細は、Quantum GOAPコーディングのセクションをご覧ください。_
### 3.2.1 Start/Target Stateの設定
1. `Start State` または `Target State` ボタンをクリックして、
計画中にワールドステートに含まれなければならないフラグを、ネガティブまたはポジティブのどちらかで定義します。
<figure>
<img alt="Add World Flag" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-add-world-flag.png">
</figure>
2. 希望する状態を選択すると、それらがゴールノードに含まれるようになります。
<figure>
<img alt="World States Added" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-goal-some-world-states.png">
</figure>
3. デフォルトでは、ワールドステートは小さな緑の円で表示されます。
これは、ワールドステートフラグにそのワールドステートフラグが含まれていること、
**そして** それがPositiveであるべきことを意味します。
この小さな緑色の円をクリックすると、Negativeに変更することができます。その場合、円の色は赤になります。
<figure>
<img alt="World State Negative" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-world-state-negative.png">
</figure>
4. 上の例では、このゴールが(他のゴールと一緒に)計画プロセスに含まれるためには、
ワールドステートのフラグが、エージェントが **射程内** にいるが **回復中ではない** ことを通知することが期待されます。
しかし、Target Stateの結果がエージェントの現在の目標に貢献する場合にのみ含まれます。上の例では、そのゴールを選択した結果、ターゲットが倒されることになります。
5. また、ルートレベルからワールドステートフラグを**見たり、変更**することも可能です。
ルートレベルに戻るには、「ESC」キーを押すか、トップバーのパンくずリストにある「Root」ボタンをクリックします。
Rootレベルのゴールは常に要約して表示されます。
<figure>
<img alt="Root Level World Flags" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goal-goal-root-with-flags.png">
</figure>
### 3.2.2 目標の組み込みと整理
ゴールノードをプランニングプロセスに含めるには、GOAP ゴールコンテナ (灰色の領域) に含める必要があります。
これを実現するには、コンテナ内にゴールノードをドラッグ&ドロップするだけです。
<figure>
<img alt="GOALS Container" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-goal-container.png">
</figure>
また、ゴールノードの名前を変更することもできます。これを行うには、ノードを選択してF2を押すか、ノードを右クリックして "Rename "を選択します。
<figure>
<img alt="Goal Renamed" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-goal-renamed.png">
</figure>
ここで一つ重要なことは、**ノードの順番が重要である** ということです。一番上のノードは他のノードより高い優先度を持ちます。
プランナーが、エージェントのゴールを達成するために、同じ関連性を持つ複数のゴールを同じ方法で使用できると判断した場合、
ノードの位置がタイブレーカーとなります。ゴールノードの名前を変更し、適切に並べ替えることをお勧めします。
<figure>
<img alt="Organised Goals" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-organised-goals.png">
</figure>
### 3.3 新しいGOAPアクションの作成
ノードの作成、編集、整理については、上記と同じコンセプトがGOAP アクションにも当てはまります。以下は、Actionsコンテナに含まれるいくつかのアクションの簡単な例です。
<figure>
<img alt="Actions Container" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-actions-container.png">
</figure>
### 3.4 ゴール/アクションの無視とミュート
ノードを削除せずにゴールやアクションを計画から取り除くことは可能です。
これは、デバッグや代替経路を試すときに便利です。ノードのデータを失わず、再びノードを追加することができます。
そのためには、主に2つの方法があります。
1. **ノードを無視するには**、コンテナからそれを削除し、それがもう無視されるべきでない場合は、それを追加して戻すだけです。
ignored anymore;
2. **ノードをミュートするには**、ノードを右クリックし、「Mute」を選択します。
ノードは半透明になり、ミュートされていることを表します。ノードをミュートすると、コンテナ上の位置や順序が失われないので便利です。
無視されたノードとミュートされたノードは、コンパイル時にスキップされますので、 **その際には再コンパイルを忘れないでください。**
### 3.5 スロット値の設定
GOAPゴールとGOAPアクションを編集するとき(ダブルクリック後)、多くのスロット値を編集することができます。
それらのいくつかは、ハードコードされた値であったり、他のノードからの値であったりします。
また、アクションスロットのような他のいくつかのスロットは、1つ以上のアクションノードにのみリンクさせることができます。
このセクションでは、このような値を定義する方法について、いくつかの選択肢を検討します。
### 3.5.1 プリミティブ型
例証を始めるために、GOAPゴールにはFPとBoolean型を持ついくつかのスロットがあります。
これらのスロットの値をクリックすることで、エディターで直接定義することができます。
<figure>
<img alt="Edit Slot" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-edit-slot.png">
</figure>
値をハードコーディングする以外に、あらかじめ定義された値や、そのスロット値をポーリングするときに実行されるあらかじめ定義されたロジックを
含むかもしれないノードとスロットをリンクすることが可能です。これには多くの方法があり、すべてこのトピックで説明されています。
[共有概念](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#defining_fields_values).
### 3.5.2 アクションスロット
GOAPゴールとGOAPアクションの両方は、その右側にいくつかのアクションスロットを備えています。
これらは、ユーザーによって実装されるマイクロアクションで、実際にゲーム状態を変更します。これらのアクションは、
ターゲットを追いかける、攻撃を行う、アイテムを収集する、などに使用することができます。
**重要:** 「GOAPアクション」を「アクション」と混同しないでください。これらは2つの異なる概念です。
<figure>
<img alt="Linked Action" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-linked-action.png">
</figure>
アクションは、Bot SDKのHFSMとUTでも再利用されるため、共通のトピックです。アクションの使用方法については、こちらのトピックを参照してください。
[アクションのコーディング](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#coding_actions)
### 3.5 GOAPのコンパイル
作成したGOAPを実際に使用するためには、作成したものをコンパイルし、Quantumシミュレーションで使用するQuantumアセットを取得する必要があります。
コンパイルするには、2つの方法があります。
<figure>
<img alt="Compile Buttons" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/compile-buttons.png">
</figure>
* 左側のボタンは、現在開いているドキュメントのみをコンパイルするために使用します。
* 右側のボタンは、プロジェクト内の現在開いているすべてのAIドキュメントをコンパイルするために使用します。
GOAPファイルは以次の場所に置かれます:`Assets/Resources/DB/CircuitExport/GOAP_Assets`.
### 3.6 Botsが使用するAIを設定
コンパイルされたアセットを使用するには、Quantumのコード内から参照する必要があります。
GUIDを元にアセットを読み込むか、`AssetRefGOAPRoot`を作成して、目的のAIアセットを指定することで実現できます。
これは、コンポーネント、データアセット、RuntimeConfig、RuntimePlayerなど、あなたのコードアーキテクチャに合ったものに含めることができます。
<figure>
<img alt="GOAP Root Reference" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-root-reference.png">
</figure>
_PS: 詳細については、Quantum GOAPコーディングのセクションを参照してください。_
## 4. 最適化とデバッグ
### 4.1 デバッグ
BotSDKには独自のデバッグツールが付属していますが、GOAPエディタでは現在それを利用していません。デバッガーを追加することは、GOAPエディタの次の機能の1つです。
当面は、GOAPロギング機能を使用してください。` GameManager.DebugEntity` にエンティティを割り当てるだけで、デバッグメッセージがコンソールに出力されます。
<figure>
<img alt="GOAP Debug 1" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-code-debug-1.png">
</figure>
### 4.2 最適化
GOAPの最適化は通常、Aが処理する必要のあるノード数を制限することになります。
処理にかかった数と時間を確認するには、エンティティデバッグを有効にして(上記参照)、ログメッセージを確認します。
<figure>
<img alt="GOAP Debug 2" class="no-border" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="/docs/img/quantum/v2/addons/bot-sdk/new-goap/goap-code-debug-2.png">
</figure>
_注:検索時間の値は、通常、実際のビルドよりもUnityエディタではかなり大きくなります。しかし、パフォーマンスを向上させたいときには、良い参考となります。_
一般的に、訪問ノード数は少なくしたいものですが、正確な数はAIの複雑さに依存します。
訪問ノード数が多すぎる場合(例えば、単純なAIで100以上)、アクションの設計が正しくない可能性が高いです。 よくある問題は、アクションの条件や効果が曖昧すぎるため、プランナーが多くの選択肢を検討し、そのほとんどが有効な結果にならないことです。 もう一つ気をつけなければならないのは、行動の「コスト」です。Aはプランニングの過程で、コストを使って最適なアクションの順序を決定します。 そのため、アクションのコストが正しく設定されていないと、プランナーは正しい分岐に戻る前に多くの行き止まりを経験することになります。 ベストなのは、コストをアクションにかかる時間を秒数で考えることですが、現実的にアクションにかかる時間が短くても長くても、 ある程度の範囲(例えば0.5〜5、ほとんどのアクションは1前後)にして、アクション間のコストに大きな差が出ないようにすることです。
## 5 詳細
### 5.1 AIParam
`AIParam` の使用に関する詳細はこちらをご覧ください。これは、さまざまな方法で定義できる、より柔軟なフィールドを持ちたい場合に便利です。
例えば手動やBlackboard/Constant/Configノードで設定する場合です:[AIParam](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#aiparam)
### 5.2 AIContext
エージェントコンテキストの情報をパラメータとして渡す方法については、[AIContext](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#aicontext)を参照してください。
### 5.3 BotSDKSystem
Blackboardのメモリ解放など、いくつかの処理を自動化するために使用するクラスがあります。
詳しくはこちらをご覧ください:[BotSDKSystem](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#bot-sdk-system).
### 5.4 Visual Editorのコメント
Visual Editorでのコメントの作成方法については、こちらをご覧ください: [Visual Editor Comments](/ja-jp/quantum/current/addons/bot-sdk/shared-concepts#visual_editor_comments).
### 5.5 コンパイルエクスポートフォルダーの変更
デフォルトでは、Bot SDKのコンパイルで生成されたアセットは、Assets/Resources/DB/CircuitExportフォルダに配置されます。エクスポートフォルダを変更する方法は、こちらを参照してください: [エクスポートフォルダの変更](./shared-concepts#changing_the_compilat