Hierarchical Finite State Machine
新しいHFSMの作成
エディターのトップバーで(+)ボタンをクリックし、オプションState Machineを選択します。

これを行うと、HFSMファイルを保存するように求められます。
好きな場所に保存してください。
これにより、ビジュアルエディター で行った作業を永続化するために使用されるデータアセットが作成されます。

注:ここで選択する名前は、ビジュアルエディターで行ったことをコンパイルするときにさらに生成される別のデータアセットの名前になります。
これが実際にボットを駆動するために使用されるデータアセットになるため、この時点で名前を選択できます。

ファイルを保存すると、Bot SDKのメインウィンドウに次のような単一のNewStateが表示されます。
それでは、この初期状態を詳しく見てみましょう。

- HFSMの初期状態を示します。
- 状態の名前。
- 状態の遷移リスト。
新しい状態の作成
新しい状態を作成するには、エディターウィンドウの空のスペースを右クリックし、Create New State を選択します。


状態の編集
状態を編集するには、対象の状態を右クリックし、[Edit This State]を選択します。

ここで、状態の名前を定義し、遷移を削除し、その位置を並べ替えることができます。
遷移の位置を並べ替えても優先順位は変わりません。
視覚的な調整にのみ使用されます。
状態の編集が完了したら、Enter を押して変更を適用する必要があります。Esc を押すと、変更を破棄できます。
状態ビューの最小化
時間内にHFSMに多くの遷移が行われることはよくあり、その構造を理解することは困難です。
状態のノードで、Minimize ボタンをクリックして、外観をより良く整理します。

before と after を分析しましょう。


2つの状態間の遷移の作成
2つの状態間の遷移を作成するには、任意の状態の左/右端にある小さな円をクリックします。
次に、別の状態をクリックすると、新しい遷移が作成されます。
ターゲット状態をすぐに作成する場合、別の状態をクリックする代わりに空の空白スペースをクリックすると、エディターは作成パネルを表示します。

新しい遷移を作成すると、その色は赤になります。これは、遷移がまだ定義されていないことを示しています。
遷移とインタラクトする方法は3つあります:
- マウスが遷移の上にあるとき、ハイライトされます。
- 遷移を左クリックすると、小さな円が遷移の方向を示します。
- 遷移をダブルクリックすると、そのサブグラフに入ります。
- これは、右クリックして[Edit Transition]を選択することでも実行できます。
ここで最初に分析するのは、すでにそこに作成されているノードです。

これは、実際に遷移を定義するために使用されるノードです。
ここには4つの重要な概念があります。
- このノードの名前は、起点状態とターゲット状態を示します。
- 最初のスロットは、遷移を行うイベントを定義するために使用されます。
- 2番目のスロットは、移行を行う決定を定義するために使用されます。
- 3番目のスロットは、同じノードから来る すべての遷移間の実行順序を定義するために使用されます。
この遷移の簡単な決定を定義することから始めましょう。
これを行う際、空白スペースを右クリックすると、作成可能な決定が表示されます。

簡単にするために、TrueDecision を選択しましょう。
もちろん、この決定の結果は常にTrueです。

この決定の結果がどこに送られるかを定義するアウトバウンドスロットがあります。
したがって、Result スロットの横にある円を左クリックして、Decisionスロットに接続します。

以上です。
単純な遷移を定義しました。
これにより、ボットがNewStateにあり、HFSMが更新されるたびに、ボットはNewState1に遷移します。
Decisionフィールドの値を編集する には、Decisionをクリックしてから、フィールド自体をクリックします:

状態の編集が完了したら、Enter を押して変更を適用する必要があります。Esc を押すと、変更を破棄できます。
非常に単純な遷移が定義されたので、トップビューに戻ってどのように見えるかを確認しましょう。
トップバーのパンくずリストにあるRootボタンをクリックすると、状態ビューに戻ることができます。

または、左側のパネルを使用して状態をナビゲートできます。

遷移が赤ではなくなっていることがわかります。
これは有効な遷移であることを示しています。

遷移の優先順位を定義する
ある状態から他の状態への遷移が複数ある場合、最初に評価される遷移を定義することができます。
この順序を定義するには、Priority スロットを使用します。

状態ノードで遷移の優先順位を確認できます。

遷移が評価される順序は次のとおりです:高い優先度から低い優先度。
これにより、最初に確認する必要がある遷移を定義できます。
注: 状態の遷移に定義された優先順位は、別の状態の遷移に影響を与えません。
新しい遷移の作成
現在、2つの状態間の遷移は1つのみです。
複数の遷移を持つ状態がないため、優先度フィールドは役に立ちません。
新しい遷移を作成するには、状態の下部にマウスを置いて**(+)** ボタンが表示されるようにする必要があります。

次に、最初の遷移と同じように、新しい遷移を定義できます。

特別な遷移タイプ
遷移セット
Transition Set は、多くの遷移をグループ化するために使用できます。
多くの状態が単一の遷移セットを指すことができるため、以前に定義された遷移セットを再利用することが役立ちます。
新しい遷移セットを作成するには、空のスペースで右クリックし、Create New Transition Set を選択します。
これにより、状態ノードに非常によく似たノードが作成されます。1つの未定義の遷移で始まり、その下部にマウスを移動させると複数の新しい遷移を作成することができます。

これで、この一連の遷移を再利用する多くの状態を持つことができます。
以下に例を示します。

右上隅のボタンを使用して、遷移セットを最小化することもできます。

すべての遷移
同じ階層レベルの任意の状態から遷移を行う必要がある ことを定義する場合、Any Transitions が非常に便利です。
階層については、このドキュメントでさらに説明します。
右クリックメニューから新しい「任意の遷移」を作成できます。
ここで、「任意の遷移」のターゲットを定義する必要があります。

上記のサンプル画像では、階層のそのレベルにあるすべての状態は、ANYノードからの遷移を考慮します。
ANY Transitionを無視する状態のリストを定義することができます。 Excluded List メニューからこれらを選択します。

ポータル遷移
このタイプの遷移は、HFSMを強制的に状態から 階層の任意のレベル の他の状態に移行させることを目的としています。
右クリックメニューから新しいポータル遷移を作成できます。

ここで、このポータルがHFSMを使用する状態を定義する必要があります。
ドロップダウンメニューをクリックして選択します。
ターゲット状態の名前は、次の階層に基づいていることに注意してください。

ポータルのターゲットを定義したら、その遷移を考慮する状態を定義するだけです。

構成された決定
単一の決定を使用して遷移を定義する以外に、いくつかの複合決定を作成することもできます。
Bot SDKには、使用できる3つの論理的な決定が既に付属しています。
以下は、AND、OR、およびNOTの決定に基づいた構成決定のサンプルです。




イベント
quantum_code プロジェクトで新しい決定を作成、コンパイル、セットアップなどせずに遷移を評価したい場合は、イベントを利用できます。
これらは非常に簡単な方法で動作します。イベントがトリガーされると、現在の状態の遷移はそのイベントがリッスンされているかどうかを確認します。
いずれかの遷移がそのイベントをリッスンする場合、それが取得されます。
コードの面では、これはイベントをトリガーするために必要なことです。
任意の quantum_code スクリプトで、次を実行します:
C#
HFSMManager.TriggerEvent(f, &guy->Fields.HFSMAgent.Data, (Entity*)guy, "SomeEventName");
これらの呼び出しをアクション/決定に追加することができます。また、システム内など、他のロジックでより自由に呼び出しを行うこともできます。
新しいイベントを作成するには、イベントセッションで、左側のパネルにある**(+)** ボタンをクリックする必要があります。

それを行うと、新しいイベントを作成するように求められます。
編集または削除 したい場合は、イベントをダブルクリックしてメニューを表示できます。
遷移サブグラフにイベントを配置するには、イベントをドラッグアンドドロップします。
次に、決定に対して行ったことと同様に、イベントのアウトバウンドスロットを遷移のイベントインバウンドスロットにリンクできます。

注: 決定とは異なり、複合イベントの定義はなく、遷移は接続された複数のイベントを受け入れません。
1つだけのイベント で定義された決定を伴う遷移は、有効な遷移 と見なされます。
イベントと決定 の両方を設定することで遷移を定義できます。
これがある場合、その遷移は、イベントがトリガーされ、決定条件の結果が真である場合にのみ発生します。

アクションを定義する
ステートマシンのフロー作成方法について(ステートと遷移で)お話ししましたので、ステートのアクションを定義する方法について見ていきましょう。
本件の詳細についてはこちらを参照してください。: Defining Actions
ミュート
自分のAIをテストする場合、ノードをミュートしていくつかのロジックを一時的に無効化することが便利な場合があります。ノードのミュートについての詳細はこちらを参照してください。: Muting
階層
状態のサブグラフ上に、新しい状態のセットを作成できます。
NewState サブグラフ上にあり、AnotherStateという新しい状態を作成するとします。
これを行うと、これら2つのアクションの間に関係が作成されます。NewStateは親であり、AnotherStateは子です。
それを行うと、親と子状態のアクションと遷移の両方が実行されます。
これにより、ステートマシンを別のステートマシン内にカプセル化できます。
これは、たとえば、3つの動作レベルを持つボス を持っている場合に非常に役立ちます。簡単なモードで開始し、HPの半分に達すると少し難しくなり、HPが10%になるとさらに難しくなります。
上のグラフで3つの主要な状態を作成できます。これらの各状態には、ボスの難易度を定義する独自の状態マシンがあります。
これにより、HFSMの組織がより整理されます。
子状態を作成するには、任意の状態のサブグラフに移動して、空のスペースを右クリックし、Create New Stateオプションを選択します。
これにより、左側のメニューで視覚化できる階層の複雑なレベルを持つことができます。

注: これらのボタンをクリックして、階層をナビゲートできます。
また、これらの状態のいずれかを右クリックして、新しいPortal Transitionを作成することもできます。
重要: HFSMの階層のすべてのレベルに対して、デフォルト状態を定義することもできます。これが、親状態間を遷移するときに入力される子状態の定義です。デフォルト状態を定義するには、任意の状態ノードを右クリックして、Make Default Stateを選択します。
HFSMのコンパイル
作成したHFSMを実際に使用するには、実行した内容をコンパイルする必要があります。
コンパイルするには、2つのオプションがあります。

- 左ボタンは現在開いているドキュメントのみをコンパイルするために使用されます
- 右ボタンはプロジェクトにあるすべてのAIドキュメントをコンパイルするために使用されます
HFSMファイルは、"Assets/Resources/DB/CircuitExport/HFSM_Assets"にあります。

ボットが使用するAIの設定
最終的に作成されたAIを使用するには、コンパイルされたアセットを参照するだけです。
GUIDに基づいてアセットを読み込むか、目的のAIアセットを指すAsset Linkを作成することでそれを行うことができます。

HFSMコーディング
DSLの観点から言えば、HFSMAgent をエンティティの構造体として、または好きな場所で使用できます。
- HFSMAgentは、フィールドまたはエンティティのコンポーネントとして使用できます。
- エンティティを必要とせずに、構造体またはグローバルスペースで宣言できます。
ゲームフローの作成、ゲームの開始時に実行するアクションの定義、ゲームの現在の状態を変更するタイミングの定義など、エンティティの範囲外のアクションをHFSMで実行できるため、重要です。
最初に、例証するために、HFSMAgentコンポーネントをエンティティフィールドに追加します。
C#
entity Hero[6]{
use Transform2D;
use DynamicBody;
use Prefab;
fields{
player_ref Player;
HFSMAgent HFSMAgent;
}
}
次に、アプリケーションに適合する任意の時点で、そのエンティティに対してHFSMManager.Initメソッドを呼び出す必要があります。
C#
HFSMManager.Init(f, &guy->Fields.HFSMAgent.Data, (Entity*)guy, data.HFSMRoot);
パラメータは次のとおりです:
- フレーム。
- すべてのHFSMAgentに含まれるHFSMDataへのポインター。
- ターゲットエンティティへのポインター。
- Unity側で作成された HFSMRoot アセット;
エンティティのHFSMAgentが初期化されたので、必要なときにUpdateメソッドを呼び出すだけです。
C#
HFSMManager.Init(frame, &myEntity->HFSMAgent.Data, (Entity*)myEntity, data.HFSMRoot);
これにより、HFSMは初期状態のデータを実行し、他の状態へのアクション/遷移を実行します。
これにより、AIはVisual Editorで作成したフラックスに従うはずです。
ActionsとDecisionsのコーディング
自分のActionを作成するには、こちらのインストラクションに従います。Coding Actions
自分のDecisionの作成は、とても似ています。
ただし、AIAction
から継承する新しいクラスを作成する代わりに、HFSMDecision
抽象クラスから継承させます。
また、Update
メソッドを実装するのではなく、Decide
メソッドを実装する必要があります。
自分の必要に応じて、true
/false
を返すのに使用します。
これらのクラスは[Serializable]
としてマークする必要があります。
C#
namespace Quantum
{
[Serializable]
public class TrueDecision : HFSMDecision
{
public override unsafe bool Decide(Frame frame, Entity* entity)
{
// insert the decision code here
return true;
}
}
}
フィールド値を定義する
Actions/Decisionsフィールドの値設定に関する代替案についての詳細は、こちらを参照してください。Defining fields values:
AIParam
AIParamの使用方法についての詳細はこちらを参照してください。これは、様々な方法で定義できる柔軟なフィールドを用意する場合に便利です。手動での設定、またはBlackboard/Constant/Configノードから設定します。: AIParam
デバッガ
Bot SDKには、独自のデバッグツールが付属しています。開発者は、実行時にHFSMエージェントをクリックして、Visual Editorで強調表示された最新のエージェントのフローを確認できます。こちらは、Bot SDKサンプルプロジェクトで動作するデバッグツールのサンプルです:

上記のgifに示されているように、エージェントの現在の状態と、その状態に至った最新の3つの遷移を確認できます。
さらに、階層ビューで現在の状態を調べることもできます。矢印が表示されている状態は、HFSMが現在その状態にあることを表しています。現在のエージェントの階層の深さを確認する際にグラフを確認する必要がないので便利です。

デバッガの使用
プロジェクトでデバッガを使用するための手順:
フィールド上またはコンポーネントとして
HFSMAgent
を持つQuantumエンティティを表すプレハブを選択します。そこに
HFSMDebugComponent
を追加。Visual Editorで、画面の右上隅にあるバグアイコンをクリックします。アイコンが緑色になっているとき、デバッグは アクティブ です。

DeterministicConfig
ファイルでExpose Verified Status In Simulation
をtrue
に設定。
PS: デバッガを使用していない時は、これを有効にする必要はありません!

- 実行時に、Bot SDKウィンドウを開いた状態で、階層上のエージェントであるゲームオブジェクトを選択します。デバッグは機能しているはずです。
PS: 現在、DSLグローバルにあるエージェントなど、エンティティにリンクされていないエージェントをデバッグすることはできません。今後のバージョンで追加する予定です。