1. プロジェクトの概要とセットアップ [0]

thumbnail

1.1. プロジェクトの目的と構成 [0]

  1. プロジェクトの開始: 講演者は、Unreal Engineプロジェクトをゼロから構築する長期的な旅に着手したことを説明する [1]。
  2. 学習目標: オープンワールドマップストリーミング、ゲームプレイアビリティシステム、ステートツリー、アセットレジストリなど、強力な機能をC++中心で探求し実験することが目標である [2]。
  3. アセット: すべて無料のアセット(Fabストアから)のみを使用する [2]。
  4. GitHubリポジトリ: 進行中のプロジェクトであり、最新コードを取得するためにGitHubリポジトリのリンクを説明欄に提供する [4]。
  5. 動画の構成: 各機能について、実装が確定するごとに専用の動画を作成する予定である [5]。

1.2. C++コードのフォルダ構成 [12]

  1. ソースフォルダの確認: コードの内部構造を確認するためにソースフォルダに移動する [13]。
  2. パブリックディレクトリ: すべてのヘッダーファイル(インターフェース、再利用可能な構造体、クラス定義)が格納される場所である [15]。
    • 他のモジュールがインクルードする場合、このフォルダを参照する [17]。
  3. プライベートディレクトリ: より重い実装ファイル(CPPファイル)が格納される [18]。
    • これにより、モジュールの内部がカプセル化され、外部モジュールにはパブリックフォルダのみが公開され、実装の詳細が保護される [19]。
  4. 機能ベースのフォルダ分け: コードをAI、コントローラー、ステートツリー、キャラクターなどの機能ベースのフォルダにグループ化し、関連コードを素早く見つけられるようにする [21]。
  5. ヘッダー内実装: クラスが非常に小さい場合、実装をヘッダー内に直接保持し、ファイルのもつれを減らしイテレーションを高速化する [22]。

1.3. ステートツリープラグインの有効化とアセット作成 [26]

  1. プラグインの有効化: ステートツリーで作業を開始する前に、ステートツリープラグインが有効になっていることを確認する必要がある [27]。
  2. プラグインウィンドウ: エディット > プラグインを開き、「state tree」で検索する [28]。
  3. 有効化: 「state tree」と「gameplay state tree」のチェックボックスをオンにする [30]。
  4. 再起動: エディタの再起動が求められるため、実行してプラグインをアクティブ化する [32]。
  5. アセット作成: コンテンツブラウザで右クリックし、「Artificial Intelligence」 > 「State Tree」を選択して新しいアセットを生成する [34]。
  6. 既存アセットの使用: 今回のセッションでは、サンプルプロジェクトに既に追加されているプリセットのステートツリーを使用して構造を探求し、強化していく [37]。

2. ステートツリーの基本概念と構造 [41]

thumbnail

2.1. ステートツリーの定義と動作原理 [41]

  1. 定義: ステートツリーは、ビヘイビアツリーとステートマシンの利点を統合した、強力に強化されたAIシステムの子孫である [41]。
  2. 構造: ビヘイビアツリーの階層的セレクターと、従来のステートマシンのステートおよび遷移フローを組み合わせたエレガントなフレームワークである [42]。
    • コアは、ルートから始まり下に分岐するステートのツリーである [43]。
    • 各ノードは、実際のビヘイビアが発生するリーフステートにつながる子ステートセレクターを持つ [44]。
  3. 実行ステップ:
    • 開始時、暗黙的にルートステートに入り、そのエンター条件を評価する [46]。
    • 条件が通過すると、子ステートに降下し、条件をチェックし、リーフステートに到達するまで続行する [47]。
    • ルートからリーフまでのアクティブなブランチ内のすべてのタスクは並行して実行され、遷移が発火するまでアクティブ状態を維持する [48]。
  4. 遷移: タスク完了、ティックごと、またはカスタム条件によってトリガーされ、ツリー内の任意の他のステートを指すことができる [49]。
  5. 利点: この組み合わせにより、デコレーター、ブラックボード、およびそれらに伴う煩雑さなしに、明確で再利用可能なフローでAIロジックを構造化できる [50]。
  6. 本質: ステートツリーは、AIをデータ駆動型、モジュール化され、視覚的な方法でオーサリングするための手段を提供する [52]。
    • セレクターの利点とステートロジックが組み込まれており、UE5 AI開発者にとって強力で直感的である [53]。

2.2. ステートツリーエディタのセクション [54]

  1. エディタの構成: エディタは3つの主要セクションで構成され、右側の詳細パネルは、ステートパネルで現在選択されているものを編集するために使用される [55]。
  2. アセット詳細セクション: ステートツリー全体に対してグローバルなすべてを扱う部分である [56]。
    • スキーマ (Schema): 作業しているステートツリーのタイプを定義する [58]。
      • プロジェクトでは、AIコントローラーと連携するState AI Component Schema(より高度)を使用している [60]。
      • オブジェクト向けのよりシンプルなState Tree Component Schemaも存在する [61]。
      • AIコンポーネントスキーマのみがコンテキストAIコントローラーにアクセスできる [62]。
      • 講演者は、デモのためにカスタムスキーマ(PAGAS enemy AI state tree schema)を作成した [63]。
    • コンテキスト (Context): スキーマ内で設定され、すべてのエバリュエーター、条件、タスクがジョブを完了するために参照できるクラス(例:カスタム敵キャラクタークラス、AIコントローラークラス) [66]。
    • パラメータ (Parameters): すべてのエバリュエーター、条件、タスクがアクセスできるグローバル変数 [69]。
    • エバリュエーター (Evaluators): 後ほど詳しく説明する [71]。
    • グローバるタスク (Global Tasks): ステートツリーの存続期間全体で実行されるタスク。継続的に実行されるため、絶対に必要な場合にのみ使用することが推奨される [72]。
    • テーマカラー (Theme Colors): ステートに色分けを行い、エディタ内で視覚的に素早く特定し整理できるようにする [75]。

3. カスタムC++ AIコントローラーの統合 [77]

thumbnail

3.1. AIコントローラーの役割とイベント駆動型設計 [77]

  1. コントローラーの場所: カスタムC++ AIコントローラーは、例のプロジェクトのコントローラーAIフォルダ内にある [78]。
  2. 使用: すべての敵がこのコントローラーを使用する [79]。
  3. 刺激 (Stimuli): このAIコントローラーは、敵の視覚、聴覚、ダメージ、一般的な知覚のための刺激を公開する [80]。
  4. マルチキャストデリゲート: 特定のイベント発生時にブロードキャストする2つのマルチキャストデリゲートを定義する [82]。
    • OnDamage: AIがダメージを受けたとき [83]。
    • OnSight: アクターが検出または見失われたとき [83]。
    • OnHearing: アクターが検出または見失われたとき [83]。
  5. 利点: これらのデリゲートにより、C++またはブループリントでイベント駆動型の反応を簡単にトリガーでき、変更を絶えずポーリングする必要がなくなる [84]。
  6. ヘルパー関数: 検出されたすべてのアクターの取得や、ダメージ/ノイズイベントの手動報告など、一般的なタスクを簡素化するヘルパーも存在する [86]。

3.2. ターゲット追跡の分離とモジュール化 [87]

  1. ターゲット追跡: AIコントローラーは、敵が取得したターゲットを追跡する [87]。
  2. 二重作業の懸念: ステートツリー内の知覚エバリュエーターもターゲットを追跡するため、二重作業のように見える可能性がある [89]。
  3. 重要な違い:
    • エバリュエーターの追跡は内部ステートツリーロジック用である [90]。
    • AIコントローラーの追跡はステートツリーの外側に存在し、他のシステムが簡単にアクセスできるようにする [92]。
  4. 柔軟性: この分離により柔軟性が得られる [93]。
    • 将来的に制御状態と戦闘状態を独自のステートツリーに分割する場合、モジュール化されたステートツリーを構築できる [94]。
  5. 保守性: マスターステートツリーからリンクステートツリーにターゲットを渡そうとするよりも、この方法がより信頼性が高く、モジュール化され、保守が容易であると経験的に判断されている [95]。

4. エバリュエーターの役割と実装 [98]

thumbnail

4.1. エバリュエーターの役割と機能 [98]

  1. ニュースルームの比喩:
    • タスク: 記者(外に出て作業を行う) [99]。
    • 遷移: どのストーリーを次に実行するかを決定する編集者 [101]。
    • エバリュエーター: 背景で事実を収集し、他の全員が賢明な選択をできるようにするリサーチャー [102]。
  2. 具体的な定義: エバリュエーターは、軽量なC++またはブループリントクラスであり、スケジュール(通常はティックごと、またはカスタム間隔)で実行される [103]。
  3. 唯一のジョブ: 世界を観察し、簡単なロジックを処理し、その結果をステートツリーコンテキストに格納することである [104]。
    • AIの心拍モニターと見なせる [105]。
    • 例: プレイヤーが10メートル以内か?スタミナやヘルスが20%未満か?敵を発見したか? [106]。
  4. 利点: 毎フレームこれらのバイタルを更新するため、遷移が条件をチェックするとき、答えがすでに待機しており、高価なクエリや絡み合ったブループリントのスパゲッティが不要になる [108]。
  5. コスト: アクションを実行しないため、非常に安価でスレッドセーフであり、データを収集し、最新の状態に保ち、意思決定者に引き渡すだけである [110]。

4.2. サンプルプロジェクトのカスタムエバリュエーター [115]

  1. カスタムエバリュエーター: サンプルプロジェクトには3つのカスタムエバリュエーターが構築されており、AIの世界に関する重要な情報を収集する [115]。
    • コンテキストアクター(敵キャラクター)、プレイヤーキャラクター、およびそれら周辺のAI刺激を対象とする [117]。
  2. コンテキストアクターモニター: 敵の現在のヘルスを追跡する [118]。
    • 今後、スタミナ、ステータス効果、その他の特殊な条件などの追加メトリクスを監視するように拡張される予定である [120]。
  3. コンテキストアクター刺激トラッカー: ステートツリーの心拍のようなものであり、敵がダメージを受けたとき、対戦相手を見た/聞いたとき、およびそれらの感覚を失った/忘れたときを検出する [122]。
  4. プレイヤーモニター: プレイヤーの敵からの距離、ゲームプレイアビリティシステム、キャラクターレベル、現在攻撃中か、死亡しているかなどを記録する [125]。
  5. データフィード: すべてのエバリュエーターは、データをアウトパラメータとしてステートツリーにフィードバックする [127]。
    • このデータは継続的に更新され、条件やタスクが最新の情報に基づいて意思決定できるようにする [128]。

4.3. C++でのエバリュエーター作成方法 [130]

  1. 場所: プロジェクト内のstate trees/evaluatorsフォルダ内にすべてのエバリュエーターが存在する [131]。
  2. 基盤: すべてUnrealのUse State Tree Evaluatorブループリントベースクラスに基づいて構築されている [132]。
  3. オーバーライドする主要な関数:
    • TreeStart: ステートツリーが実行を開始するときに呼び出され、収集ロジック(初期化や追跡開始)を配置する場所である [133]。
    • TreeStop: ステートツリーが停止するときに呼び出され、デリゲートの登録解除や変数のリセットなどのクリーンアップを処理する [137]。
  4. GetDescription関数: エディタ内のエバリュエーターの上部バーに表示されるテキストを制御するオプションの関数であり、複雑なセットアップを読みやすくするためにカスタマイズ可能である [139]。
  5. プロパティの定義とカテゴリメタデータ:
    • Context: エバリュエーターに、ステートツリーのコンテキストからの値でこのプロパティを埋めるように指示する [142]。
      • 例: AIコントローラープロパティをAIコントローラーコンテキスト値に参照させるには、カテゴリをcontextに設定する [145]。
    • Input: ステートツリーデザイナーがエディタで値を割り当てる必要があることを意味する [146]。
    • Output: エバリュエーターによって入力され、ステートツリーの残りの部分で利用可能になることを意味する [147]。
      • これらはエディタ内でinまたはoutのバッジとして表示され、役割を一目で把握しやすくする [148]。
  6. 実装: 講演者はすべてのエバリュエーターにC++を使用しているが、ブループリントでも同じ基本概念を使用して構築できる [149]。

5. ステートツリーの構成要素の詳細 [151]

thumbnail

5.1. ステート、ティックレート、条件、タスク、遷移 [151]

  1. ステート (State): 振る舞いロジックの自己完結型ユニットと見なされる [151]。
    • 選択されると、ルートからリーフまでのアクティブなブランチ上のすべてのステートが同時にアクティブになる [153]。
    • それぞれ独自のタスクと潜在的な遷移を持つ [155]。
  2. カスタムティックレート (Custom Tick Rate): ステートツリーが毎フレーム実行されるのではなく、再評価する頻度を制御する [156]。
    • 例: ティックレート0.25は、1秒間に4回更新されることを意味し、ロジックが絶え間ないチェックを必要としない場合にオーバーヘッドを削減するのに役立つ [158]。
  3. 条件 (Conditions): ロジックをゲートする論理チェックである [161]。
    • エンター条件: ステートがアクティブになるかどうかを制御する [162]。
    • 遷移条件: ステートが別のステートに移行するかどうかを決定する [163]。
    • ステートはエンター条件が通過した場合にのみアクティブになり、遷移は条件が満たされたときに発火する [164]。
  4. タスク (Tasks): ステートがアクティブな間に実行される条件またはビヘイビアである [165]。
    • すべてのアクティブなステートのブランチ全体で並行して実行される [166]。
    • ターゲットの設定、アニメーションのトリガー、コンテキスト値の更新など、他のステートツリー部分が使用できる出力を生成することもできる [167]。
  5. 遷移 (Transitions): ステートツリーがあるステートから別のステートへ移動する方法とタイミングを定義する [169]。
    • タスクの成功または失敗、あるいはカスタムイベントに基づいてトリガーされる [170]。
    • ステートツリーはリーフステートからルートに向かって遷移をチェックし、最初に有効なものが次の選択を導く [171]。

6. ステートツリーの具体的なウォークスルー(パトロールと戦闘) [174]

thumbnail

6.1. ルートとアイドルステートのセットアップ [174]

  1. ルートからの分岐: ルートから3つの主要ステートを作成し、ビルド中にステートツリーを整理するのに役立つ構造を採用する [174]。
  2. アイドルステート (Idle State): ツリーが最初に来るステートであり、フォールバックステートでもある [176]。
    • 目的: 他のステートが失敗した場合に、ツリーが自動的にルートに戻って再開する際に、ツリーが確実に移動できるステートを提供するため [178]。
    • 設定:
      • アニメーションブループリントがアイドル状態であるため、遅延タスクは不要で、キャラクターは立っている [182]。
      • 最大歩行速度を200に設定 [184]。
      • カスタムティックレートを0.25に設定(1秒間に4回タスクを処理) [185]。
  3. 遷移: 他の2つの主要ステート(パトロールまたは戦闘)に遷移することを意図している [187]。
    • これらのステートはイベント駆動型であるため、イベントが発火しない限り、ツリーは常にルートとアイドルの間を行き来する [188]。
  4. イベント処理: アイドル処理中にイベントが発火した場合、タスクを実行し、遷移をチェックする [189]。
    • 戦闘イベント: 遷移は戦闘に移動するよう指示される [190]。
    • パトロールイベント: 優先度「normal」でパトロールに移動するよう指示される [192]。

6.2. パトロールステートと移動ロジック [194]

  1. パトロールステート: 最初のステートであり、エンター条件としてパトロールイベントを必要とする [194]。
  2. エンター条件:
    • 組み込み条件の他に、カスタムカテゴリPGGASで作成された2つのカスタム条件(Compare Gameplay TagsとCharacter Armed)がある [197]。
    • require enter to eventは各ステートに組み込まれており、クリックで有効にできる [201]。
    • イベントが選択されると消費されるように設定されている [204]。
  3. 移動ステート (Move to Random Location):
    • カスタムティックレート: 0.3(約3回/秒) [206]。
    • タスク: 3つのタスクを実行する [209]。
    • タスク実行順序の注意点 (Gotcha): 新しいステートを作成すると、タスクセクションはデフォルトでAnyに設定される [210]。
      • 複数のタスクがある場合、Any設定では最初のタスクが完了したときに遷移を試みる可能性があり、通常は望ましくない [213]。
      • ほとんどの場合、タスクが実行順序通りに完了するまで遷移を試みないように、設定をAllにする必要がある [218]。
    • タスク実行:
        1. 俳優の最大歩行速度を200に設定 [221]。
        1. Get Random Location Around Actorタスクを呼び出し、半径100ユニットで移動可能な場所を取得する(アウトパラメータとして出力) [222]。
        1. Move Toタスクを使用して、前のタスクから取得したランダムな場所に移動する [226]。
      • 宛先をランダムロケーションタスクに設定すると、ステートツリーはそのタスクからの結果を待機する [228]。
    • 遷移: すべてのタスクが完了した後(On State Complete)、次のステートにジャンプする [230]。
  4. 見回しステート (Look Around State):
    • タスク: 単純な遅延タスクを使用し、5秒間(±1.5秒の誤差)一時停止する [237]。
    • 遷移: 完了後、Move to Random Locationステートに戻り、パトロールシーケンスを繰り返す [242]。

6.3. 戦闘ステートのロジック [244]

  1. エンター条件: 戦闘ステートに入るには、state tree.event.agイベントが必要である [244]。
  2. 武器の描画: 戦闘シーケンスでこのステートに一度だけ入るべきであり、武器がホルスターに収まっている場合にのみ実行される [245]。
    • カスタム条件: Is Character Armed条件を使用する [250]。
      • 条件はコンテキストアクターをキャラクターに、AIコントローラーをAIコントローラーにマッピングする [253]。
      • 反転 (Inverting): 条件が武装している場合にtrueを返すため、武装していない場合(つまり、falseが返されたとき)に入りたいので、結果を反転させる [255]。
    • カスタムタスク: Play Montageカスタムタスクを実行する [261]。
      • モンテージを再生するための組み込みタスクがないため、カスタムタスクが必要である [263]。
      • モンテージがほぼ完了するか完了するまで、タスクが成功または失敗としてマークされないように設定する [264]。
  3. コンテナステート (AttackDefense): 次のステートはコンテナステート(グループ)であり、自動的に次のステートに進む [266]。
  4. プレイヤー死亡チェック: Is Player Deadをチェックする [270]。
    • プレイヤーが死亡した場合、ゲームは終了し、ステートツリーは成功して停止する [271]。
  5. 逃走ステート (Flee): 敵のヘルスを監視するエバリュエーターの例として使用される [275]。
    • エンター条件: ヘルスが20以下の場合に逃走する [277]。
      • エバリュエーター(ヘルスモニター)を選択し、プロパティとしてCurrent Healthを選択し、値20に対してLess or Equalを設定する [280]。
    • タスク: EQSクエリを実行する [288]。
      • クエリロジック: プレイヤーから離れたパスを生成する(プレイヤーコンテキストを使用) [290]。
      • クエリオーナー: AIコントローラー [298]。
      • 結果の保存: EQSクエリの結果は結果値を返すため、グローバルパラメータに設定する必要がある(将来の拡張のためにグローバルを選択) [299]。
    • 移動設定: 逃走中は最大歩行速度を400に設定し、Move Toタスクの宛先として、EQSクエリの結果(グローバルパラメータ)を使用する [303]。
    • ループ: 完了後、トップのAttackDefenseステートにループバックし、継続的に再評価することで、敵は必要に応じて逃走を続けることができる [307]。

6.4. 防御ロジックとターゲット喪失処理 [309]

  1. 防御ステート (Defense): プレイヤーが攻撃中であるというプレイヤーモニターエバリュエーターからの情報に基づいてトリガーされる [309]。
    • エンター条件: is player attackingがtrueの場合 [313]。
    • ブロックステート (Block): ゲームプレイアビリティを実行し、ブロックを実行する [314]。
    • 完了後、トップコンテナに戻り、最初からやり直す [316]。
  2. ターゲット喪失処理: 敵がターゲットを保持しているかを確認する [318]。
    • 条件: Is Object Valid条件を使用し、コントローラーのAcquired Targetをチェックする [320]。
      • 外部コードがターゲットを変更する可能性があるため、エバリュエーターのコピーではなく、AIコントローラーのターゲットを使用することが推奨される [323]。
    • ターゲット喪失時: ターゲットが無効(ヌルポインタ)の場合、敵はターゲットを見失った(視覚/聴覚喪失など)と見なされ、パトロールまたはアイドルステートに移動する [326]。
    • タスク: Set Focusカスタムタスクを実行し、フォーカスを消去する(エバリュエーターとAIコントローラーの両方のターゲットを削除) [333]。
    • 遷移: Patrolステートツリーイベントを送信し、パトロールブランチの実行を開始する [336]。
  3. 攻撃への移行: ターゲットを保持している場合、Set Focusステートに進み、フォーカスを設定し、Perform Attackステートに直接遷移する [339]。

6.5. 攻撃と移動の注意点(Gotchas) [343]

  1. 注意点 (Gotchas): 期待通りに動作しない場合の2つの主な注意点 [344]。
      1. All/Anyタスク設定(前述) [345]。
      1. 遷移の適切な設定 [346]。
  2. エンター条件 vs 遷移条件: エンター条件が期待どおりに機能しない場合があるため、前のステートからの遷移条件を使用することが最善である [347]。
  3. 移動グループ (Move to Strafe / Strafe Target): ターゲットを設定し武器を引き抜いた後、敵と自分の距離を計算し、走るべきか、それともすでに交戦中で横移動(Strafe)すべきかを決定する [351]。
    • 距離情報: プレイヤーモニターエバリュエーターから距離情報を使用する [355]。
    • 遷移条件:
      • プレイヤー距離が250ユニットより大きい場合: Close Distanceステートに遷移する [356]。
      • プレイヤー距離が250ユニット未満の場合: すでに攻撃範囲内であるため、Strafingステートに遷移する [358]。
  4. Close Distance:
    • タスク1: スピードを更新し、ターゲットアクター(プレイヤー)に向かって移動する(宛先ではなくターゲットアクターを使用) [360]。
      • 250ユニットより大きい場合、125ユニット以内に近づくように指示される [364]。
  5. Strafe (横移動):
    • タスク: Strafe EQS Query(ドーナツクエリ)を実行する [366]。
      • パラメータ: 内部半径、外部半径、リングごとのポイントを設定する [367]。
      • クエリ設定: これらのパラメータは、ステートツリーとキャラクターに基づいて値を更新でき、異なるキャラクタータイプ(例:遠距離)に合わせて調整可能である [369]。
    • 結果: クエリ結果をStrafe EQS Resultグローバルパラメータに設定し、Move Toタスクを使用してその宛先に移動する [374]。
    • パラメータ設定: パラメータはグローバル変数から設定することも、ステート上のパラメータを設定してフィードすることも可能である [376]。
  6. 攻撃への移行: わずか4分の1秒のポーズの後、Perform Attackステートに直接遷移する [380]。

6.6. 攻撃の実行とループの完了 [384]

  1. Perform Attack: カスタムタスクを作成して使用する [384]。
    • GASとの連携: Perform Blockカスタムタスクと同様に、GAS(ゲームプレイアビリティシステム)を呼び出す [385]。
    • 攻撃能力タグ: 攻撃アビリティタグの配列を入力として設定する(例:ソードスラッシュ、ソードスロー、ソードスラッシュスピンの3つ) [387]。
    • 選択: ランダム設定では、評価された配列からランダムに攻撃を選択して実行する [395]。
      • シーケンシャル設定: すべての攻撃を順番に実行する。低レベルの敵に予測可能なパターンを持たせたい場合に有用である [398]。
  2. ループ完了: 完了後、AttackDefenseステートのトップに戻り、すべてを最初からやり直すことで、攻撃防御ループが作成される [400]。

6.7. 動作のデモと結果 [402]

  1. デモ実行: プレイして動作を確認する [402]。
  2. 知覚の表示: センサーが設定されていることが示される [403]。
  3. 動作:
    • 聴覚範囲内に入る [406]。
    • 視認すると剣を引き抜く [407]。
    • 直接近づき、一時停止、攻撃、一時停止、攻撃を繰り返す [408]。
    • 攻撃中、横移動(Strafing)を使用し、異なるアビリティを使用する [410]。
    • どちらかが死亡するまで、追跡と攻撃を継続する [413]。

7. C++での条件とタスクの作成方法 [414]

thumbnail

7.1. カスタム条件 (Is Character Armed) の実装 [414]

  1. 基盤: すべての条件はUStateTreeCondition BlueprintBaseに基づいており、Test Conditionというオーバーライド可能な関数を持つ [418]。
  2. ロジック:
    • コンテキストアクター(講演者はcharacterと呼ぶ)をチェックする [419]。
    • キャラクタークラス内のisWeaponEquipped関数を呼び出し、武器が装備されているかどうかを判断する [420]。
    • 反転設定に基づいてtrueまたはfalseを返す [426]。
  3. プロパティ: エバリュエーターと同様に、コンテキスト(アクター、AIコントローラー)プロパティにアクセスでき、反転するかどうかを制御するプロパティも持つ [429]。
  4. 説明 (Get Description):
    • Get Descriptionプロパティを設定することで、エディタで「Checks if context actor is armed」というテキストが表示される [431]。
    • この説明は、ツリーを視覚的に確認する際に非常に重要である [435]。

7.2. カスタムタスク (Play Montage) の実装 [438]

  1. 基盤: UStateTreeTask BlueprintBaseを使用する [440]。
  2. ティックの有効化: ShouldCallTick = trueを設定する必要がある。これにより、ティックイベントが実際に発火する [441]。
  3. プロパティ:
    • Context Property: Montage(再生するモンタージュを指定)とPlayRateを設定する [442]。
    • カテゴリ: Taskというカテゴリ名を使用しているが、InputやContext以外の単語であれば任意である [442]。
    • 入力値の指定: 入力として設定しない場合でも、プロパティを設定できる(直接設定するか、プロパティを使用するかの二通りがある) [449]。
  4. 説明のカスタマイズ: Get Description関数で、モンタージュ名と速度を組み込んだカスタム説明(例: "play montage [montage name] at speed of [rate]")を返すことができる [452]。
    • 良い説明を設定することで、数週間後にツリーに戻った際にも、タスクが何をしているかを即座に理解できる [460]。
  5. オーバーライドする関数:
    • Enter State: タスクが開始するときに呼び出され、セットアップとアクションの実行を開始する [462]。
      • 失敗処理: モンテージが設定されていない場合、失敗を返して続行しない [465]。
      • セットアップ: 俳優のスケルタルメッシュからアニメインスタンスを取得し、通知イベントとモンタージュイベントのバインディングを設定する [468]。
      • 再生: モンテージを再生する [473]。
      • 重要: モンテージ再生中は、ステートツリーにRunning状態であることを伝える必要がある [474]。これにより、タスクが完了したとマークされるのを防ぐ [477]。
    • Tick: モンテージが終了したかどうかを確認するフラグをチェックする [479]。
      • モンテージが終了していない場合、ステートツリーにまだ実行中であることを伝え続ける [480]。
      • 終了した場合、Succeededを返し、タスクが完了したことを示す [488]。
    • Exit State: バインディングをすべて解除し、モンタージュをフェードアウトさせて停止する [490]。
  6. イベント処理: モンテージが終了したときにフラグをtrueに設定し、Tick関数がタスクの終了を認識できるようにする [495]。

7.3. Perform Attack タスクとタスクベースの選択 [499]

  1. Perform Attack タスク: 敵が攻撃を実行するためのタスク [499]。
  2. 構造体の使用: ランダム/シーケンシャル選択のために、Ability Tag Selection Weightを持つ構造体(配列アイテムを表す)と、エディタで表示される値を持つInstance Data Structの2つの構造体を使用する [501]。
  3. タスクベースの選択:
    • ほとんどのタスクはUStateTreeTask Common Baseを使用するが、Play Montageタスクはイベントをトラップするためにクラスベース(UStateTreeBlueprint Base)を使用した [506]。
    • Common Base使用: インスタンスタイプとして構造体を指定し、エディタに表示させるためにGet Instance Data Typeを返す [512]。
  4. ロジック:
    • Enter State: 最終的にモンタージュを再生する [516]。
    • Tick: 俳優クラスのIs Attackingフラグをチェックする [518]。
      • ゲームプレイアビリティが実行されている間、このフラグはtrueであり、タスクは実行中であると見なされる [520]。
      • フラグがfalseになると、タスクは成功して終了する [521]。
  5. 結論: これらのコンポーネント(エバリュエーター、条件、タスク)を使用することで、構築、保守が容易で、非常にパフォーマンスの高い高度なステートツリーを作成できる [523]。

8. まとめと補足情報 [527]

thumbnail
  1. 動画の構成: 時間の制約により、以前計画されていたシリーズ動画を1本の長い動画にまとめたことが説明される [528]。
  2. コードの提供: すべてのコードはGitHubで提供されており、リンクは説明欄にある [530]。
  3. 結び: 視聴者への感謝と次回の挨拶 [531]。