概要
スマート オブジェクト は、AI エージェントやプレイヤーがインタラクト可能な、レベル内に配置されたオブジェクトです。これらのオブジェクトには、インタラクトに必要なすべての情報が含まれています。 スマート オブジェクトはグローバル データベースの一部であり、空間パーティショニング構造を使用します。そのため、ランタイム時に、エージェント周辺の検索やゲームプレイ タグなどの仕分け機能を使用してクエリできます。
大まかに言うと、スマート オブジェクトは、予約システムを通じて使用できる、レベル内の一連のアクティビティです。
重要な留意点は、スマート オブジェクトは実行ロジックを含まないことです。その代わり、スマート オブジェクトは、実装に応じて、インタラクターがインタラクトを行うために必要な情報すべてを提供します。各インタラクター (エージェントまたはプレイヤー) は、スマート オブジェクトに関する独自の実装ロジックを実行します。
スマート オブジェクトの要素
SmartObject サブシステム
SmartObject サブシステム は、レベル内で使用できるすべてのスマート オブジェクトを追跡する役割を持ちます。これは、スマート オブジェクト コンポーネントとコレクション間のリンクです。
このサブシステムは、スマート オブジェクト プラグインがアクティブな場合に自動的にレベル内に作成されます。
SmartObject Persistent Collection
SmartObject Persistent Collection は、レベルに配置されたアクタです。実行時にロードまたはアンロードされるかにかかわらず、常にシミュレーションの一部となるスマート オブジェクトのリストを保持します。
レベル内には、複数の SmartObject Persistent Collection を持つことも、全く持たないことも可能であることに注意してください。コレクションは SmartObject の寿命に影響するだけで、システムで使用されるかどうかには影響しません。
SmartObject Container
SmartObject Container はスマート オブジェクトのグループを追跡します。Smart Object Subsystem と Smart Object Persistent Collection の両方とも、これを使用して SmartObject 上で特定の操作を実行します。
よくある例としては、永続的なコレクションが SmartObject サブシステムに追加されると、SmartObject のグループをマージします。
SmartObject Component
SmartObject Component は、任意の アクタ に追加し、レベル内でそのアクタをスマート オブジェクトとしてマークできます。このコンポーネントは、所定のスマート オブジェクト テンプレートのコンフィギュレーションを格納する、スマート オブジェクト定義アセットをポイントします。
SmartObject コンポーネントを含むアクタは、ランタイム時に ストリーミング を使用してロードおよびアンロードできます。SmartObject コンポーネントがロードされた Smart Object Persistent Collection のいずれかに含まれている場合、ランタイム インスタンスはメモリ内でアクティブのままで、コンポーネントのストリーミング状態にかかわらず、シミュレーションの一部とみなされます。
SmartObject コンポーネントを含むアクタがランタイム時にスポーンされる場合、そのアクタはアンロードされた後はメモリ内でアクティブな状態ではなくなります。これは、コンポーネントが SmartObject Persistent Collection の一部となっていないためです。
スマート オブジェクト定義
スマート オブジェクト定義 は、複数のスマート オブジェクトのランタイム インスタンス間で共有される不変のデータを含むデータ アセットです。スマート オブジェクト定義は、ユーザーに必須のタグ、アクティビティ タグ、オブジェクト アクティベーション タグ、スマート オブジェクトとのインタラクトで使用されることがあるデフォルトの一連の動作定義をはじめとする、フィルタリング情報を格納します。
スマート オブジェクト定義は、特定のスマート オブジェクトに対してエージェントまたはプレイヤーが使用できる 1 つ以上のスロットを公開します。各スロットには、(エディタ配置からベイクされる) 親アンカーを基準とする位置と回転、およびいくつかのオーバーライド可能なプロパティが含まれています。オーバーライド可能なプロパティの一般的な例としては、ユーザーに必須のタグやスロットごとの特定の動作定義などがあります。
スマート オブジェクト動作定義
スマート オブジェクト動作定義 には、所定のインタラクションに対してエージェントまたはプレイヤーが必要とするデータが含まれます。現在使用可能な動作定義には、次のような種類があります。
- Mass Entity 動作 - Mass Entity で使用できるスマート オブジェクトの設定に使用するデータが含まれます。
- ゲームプレイ動作 - Gameplay Behavior プラグインで使用できるスマート オブジェクトの設定に使用するデータが含まれます。
ランタイム フロー
このセクションでは、エージェントがレベル内のスマート オブジェクトとインタラクトする仕組みを説明します。
エージェント データ
スマート オブジェクトを検索するために、エージェントは 1 つ以上のゲームプレイ タグを使用できます。また、オブジェクトの目的のタグを含むタグ クエリ (アクティビティの要件) も使用することが可能です。この情報は、条件に一致するレベル内のスマート オブジェクトを検索する際に使用されます。
スマート オブジェクト データ
スマート オブジェクト定義には、オブジェクトの説明に使用される 1 つ以上のアクティビティ タグを含めることができます。また、タグ クエリと目的のタグのリストを含めることも可能です。タグ クエリは、スマート オブジェクトの使用を要求しているユーザーがそのオブジェクトとのインタラクトを許可されているかどうかを判断するために使用される式です。
スマート オブジェクト定義には、すべてのスロットで使用されるデフォルト動作定義のリストが含まれています。スロットに特定の動作定義が割り当てられている場合、特定の動作によってデフォルトの動作がオーバーライドされます。
スマート オブジェクトを検索する
-
エージェントが、指定した間隔で近くのスマート オブジェクトを検索します。エージェントは、SmartObject サブシステムの FindSmartObjects メソッドを呼び出して検索を行います。このメソッドには、ユーザー タグ、アクティビティ タグ、動作定義クラス、検索領域が含まれています。
-
SmartObject サブシステムが、指定されたすべてのフィルタに一致する、検索領域内のすべてのスマート オブジェクトを検出します。
-
SmartObject サブシステムが、スマート オブジェクト結果をエージェントに返します。スマート オブジェクト結果は、条件に一致するスマート オブジェクトのすべてのハンドルとそれらの空きスロットを含む構造体の配列です。
上記の画像は、緑色の輪で示された 1 つの空きロットがある乗り物のスマート オブジェクトです。
スマート オブジェクトを要求する
-
エージェントが目的のスマート オブジェクト結果を選択し、SmartObject サブシステムの ClaimSmartObject メソッドを呼び出します。このメソッドは、スマート オブジェクトのスロットの要求を試みます。
-
SmartObject サブシステムが、スマート オブジェクトのスロットの要求を試みます。
-
スマート オブジェクトで使用可能なスロットが要求され、スロットの状態が Claimed (要求中) に設定されます。
-
SmartObject サブシステムが 要求ハンドル をエージェントに返します。
-
要求ハンドルが有効かどうかをエージェントが確認します。有効な場合、要求試行が成功し、次の手順に進むことができます。一方、要求ハンドルが無効の場合、エージェントはスマート オブジェクト結果から別のスマート オブジェクト スロットへの要求を試みることができます。
要求中のスロットは、それを要求したエージェントによってリリースされるまで、他のエージェントの要求を受けることはできません。
上記の画像では、エージェントによってスロット 0 が要求されています。
スマート オブジェクトに近づく
-
エージェントが SmartObject サブシステムの GetSlotLocation または GetSlotTransform メソッドを呼び出し、要求ハンドルを渡します。このメソッドは、要求されたスロットの位置またはトランスフォームを返します。
ユーザーは、次の C++ コードを使用してスロットのトランスフォームを取得することもできます。
FSmartObjectSlotView: FSmartObjectSlotView View = Subsystem->GetSlotView(ClaimHandle.SlotHandle); const FSmartObjectSlotTransform& SlotTransform = View.GetStateData<FSmartObjectSlotTransform>(); FTransform Transform = SlotTransform.GetTransform();
-
SmartObject サブシステムが、要求されたスロットの位置またはトランスフォームをエージェントに返します。
-
これで、エージェントがレベル内のスロットの位置に向かって移動を開始できます。エージェントは、目的地に到達するために、任意の移動方法を使用できます。
-
エージェントがスロットの位置に到着し、SmartObject サブシステムの Use メソッドを呼び出して要求ハンドルを渡します。
-
Use メソッドが、要求されたスロットの状態変化をトリガーします。スロットの状態が Claimed から Occupied (占有中) に変化します。
-
SmartObject サブシステムは、エージェントに 動作定義 構造体を返します。動作定義には、エージェントがスロットの位置で目的の動作を行うために必要なすべてのデータが含まれています。
上記の画像では、エージェントはスロットに到着すると目的の動作を開始します。スロットは Occupied 状態になり、赤色の輪で示されます。
スマート オブジェクトをリリースする
-
エージェントが、動作定義に記述されている目的の動作を実行します。
-
その動作が完了するか中断されると、エージェントが SmartObject サブシステムの要求ハンドルで Release メソッドを呼び出します。
-
SmartObject サブシステムが、スロットの状態を Occupied から Free (空き) に変更します。
-
これで、エージェントは自由に別のタスクを実行したり、別のスマート オブジェクトを検索したりできるようになります。
エージェントは、要求したスロットをリリースする責任を負います。リリースは、動作が完了するか中断されると行われます。
プロセスを中断する
上記で説明したプロセスは、エージェントまたはスマート オブジェクトで任意のタイミングで中断 (アボート) できます。
スマート オブジェクトの状態が変化した場合、Claimed または Occupied 状態のスロットすべてが自動的にリリースされ、OnSlotInvalidatedDelegate コールバックを通じて対応するエージェントに通知されます。一般的な例としては、ゲームプレイ中に破壊されるスマート オブジェクトがあります。
また、エージェントは、理由を問わず任意のタイミングでプロセスを中断できます。このシナリオでは、エージェントは、他のエージェントが要求できるようにスロットをリリースする責任を負います。一般的な例としては、エージェントが死んだり、優先度の高い他のタスクを実行したりといったことが挙げられます。