Gameware Navigation には、メモリにロードした NavData に対して使用する高性能なランタイム クエリのセットが用意されています。これらのクエリを使用して、次のような地形およびキャラクタの移動の可能性に関する幅広い知覚上の質問に回答することができます。
各タイプのクエリは、独自のクラスにカプセル化されています。完全なリストについては、IQuery クラスを実装するクラスを参照してください。各クエリ タイプの入力と出力を含む完全な説明については、クラスの説明を参照してください。
それぞれのクエリは、1 つの Database に現在ロードされている NavData の完全なセットを考慮します。1 つのクエリを複数の Databases に対して同時に実行することはできません(ただし、異なる Databases に対してクエリの複数のコピーを平行して実行することはできます)。また、1 つのクエリを Database にロードされる一部のセクタに制限することもできません。
クエリの各クラスは、アトミックまたはタイム スライスのいずれかです。
すべてのクエリは、作業メモリ(一時データを記録するために計算時に使用するバッファ)を必要とします。たとえば、AStarQuery では、NavData のパスを検索するときに、調べる候補ノードのリストを記録するために作業メモリを使用する必要があります。
クエリを処理するたびに、計算時に使用するためにそのクエリに対して WorkingMemory クラスのインスタンスを提供することができます。インスタンスを提供しない場合、クエリは、クエリが調べるように設定されている Database が保持している共有バッファを使用します。
作成した各クエリは、2 つのモードのいずれかで実行することができます。
データ生成プロセスの後処理フェーズなど、ゲーム ループ外でクエリを起動する場合は、ブロックの方法を使用する必要があります。
この呼び出しではその他の設定パラメータの値はリセットされないため、新しい入力データでクエリーを初期化するたびに再設定する必要はなく、同じクエリーを複数回実行する際に同じ設定値を再利用できます。
たとえば、次のコードは RayCastQuery を設定します。
Kaim::RayCastQuery<Kaim::DefaultTraverseLogic> rayCastQuery; rayCastQuery.BindToDatabase(m_world->GetDatabase(0)); // Optional configuration ... rayCastQuery.SetDynamicOutputMode(Kaim::QUERY_SAVE_TRIANGLES); rayCastQuery.Initialize(start, move2D);
同じ Database に対して同じ設定を使用してクエリーを再実行する場合に行う必要があるのは、Initialize() を呼び出して新しい入力値を提供することだけです。
多くのタイプのクエリでは、調べる NavData に関連付けられているカスタム NavTag を考慮することができます。これらのクエリはすべて、テンプレート引数として述部を受け取ります。クエリは NavTag 間のトランジションを検出すると、この述部からクラス メソッドを呼び出し、新しい NavTag を拒否するかどうかや、トランジションを交差できるかどうかを特定します。
この述部は、PathFollower クラスによって受け取られるものと同じで、AStarQuery によって使用されるカスタマイザとほとんど同じメソッドに依存しています。述語クラスに実装する必要があるインタフェースの要件の詳細については、「NavTag を禁止、回避、優先する」を参照してください。
NavTag の設定の詳細については、「カスタム データでタグ付けする」も参照してください。
クエリの起動は、即時に実行するか非同期に実行するかによって異なります。
即時モードでクエリを起動するには、PerformQueryBlocking() メソッドを呼び出します。
rayCastQuery.PerformQueryBlocking();
World の更新処理中にクエリを起動しない限り、任意のスレッドから即時クエリを起動することに問題はありません。
World の次の更新時に非同期にクエリを起動するには、World::PushAsyncQuery() メソッドを呼び出し、クエリ オブジェクトを渡します。World ではキューにクエリが配置され、CPU 割り当てが許可されると即座にクエリが実行されます。
m_world->PushAsyncQuery(&rayCastQuery);
独自の CPU 割り当てを使用して独自の QueryQueue オブジェクトを設定し、クエリの処理を管理することができます。QueryQueue を処理すると、CPU 割り当てができなくなるまで順番にキューの先頭にあるクエリを実行します。そして、(通常は次のフレームで)再度処理するまで計算を一時停止します。
詳細については、QueryQueue クラスを参照してください。
即時モードのクエリの実行と同様に、World の更新処理中に処理しない限り、任意のスレッドから QueryQueue を処理することに問題はありません。
ただし、非同期モードのクエリの実行と同様に、キューが現在のフレームでの処理を終了した後すぐに各クエリの結果が得られるという保証はありません。
GetResult() メソッドを呼び出すと、いつでもクエリの現在の結果を取得することができます。
すべてのクエリは、クエリ クラスに固有の列挙によって処理の状態と結果を示します。この列挙にはクエリ クラスと同じ名前が含まれ、接尾語 Result が付きます。たとえば、RayCastQuery では RayCastQueryResult が生成されます。
非同期にクエリを起動する場合、結果コードを使用すると、クエリが処理を正常に終了したかどうかを確認することができます。一般的に、DONE が含まれる列挙値はすべて、クエリの計算が完了していることを示します。たとえば、RayCastQuery では、処理を完了するまでに RAYCAST_NOT_INITIALIZED または RAYCAST_NOT_PROCESSED を返し、その後 RAYCAST_DONE_START_OUTSIDE、RAYCAST_DONE_ARRIVALPOS_FOUND_MAXDIST_REACHED、RAYCAST_DONE_LACK_OF_WORKING_MEMORY のいずれかを返すことがあります。
クエリのタイプと処理の結果によっては、クエリのその他のデータ メンバーから追加の出力を取得できる場合もあります。以下を参照してください。
NavMesh を通じて伝達する一部のクエリのタイプでは、交差するデータを記録することができます。たとえば、クエリは、伝達中に交差するトライアングルのリスト、または異なる NavTag と交差するサブセグメントのリストを記録できることがあります。クエリの後、交差したデータのリストを取得し、交差した地形のプロパティをクエリで検索することができます。たとえば、トライアングルに関連付けられている NavTag、高度の変更などに基づいてキャラクタが決定することができます。
これらのクエリにはすべて、SetDynamicOutputMode () メソッドが含まれています。これは、記録する必要がある出力データのタイプをクエリに伝えるために呼び出す必要があります。デフォルトでは、交差したデータは記録されません。SetDynamicOutputMode() を呼び出し、DynamicOutputMode 列挙から目的の値を渡すことにより、クエリに交差したデータを記録するように明示的に指示する必要があります。
交差したデータは、GetQueryDynamicOutput() メソッドを呼び出すことによって取得できます。これは、QueryDynamicOutput オブジェクトへのポインタを返します。このオブジェクトのメソッドにより、保存されたデータにアクセスできます。出力データをゲームの座標系に変換して戻すことを忘れないようにします(必要な場合)。
たとえば、次のコードは、交差する NavMesh のトライアングルを取得するように RayCastQuery を設定する方法を示しています。
Kaim::RayCastQuery<Kaim::DefaultTraverseLogic> rayCastQuery; rayCastQuery.BindToDatabase(m_world->GetDatabase(0)); ... // enable saving triangles rayCastQuery.SetDynamicOutputMode(Kaim::QUERY_SAVE_TRIANGLES); rayCastQuery.Initialize(start, dir2D, maxdist); rayCastQuery.PerformQueryBlocking(); // retrieve data Kaim::QueryDynamicOutput* qoutput = rayCastQuery.GetQueryDynamicOutput(); // iterate through the list of triangles KyUInt32 numberOfTriangles = qoutput->GetNavTrianglePtrCount(); for (KyUInt32 i_triangle = 0; i_triangle < numberOfTriangles; i_triangle++) { const Kaim::NavTrianglePtr thisTriangle = qoutput->GetNavTrianglePtr(i_triangle); // handle the triangle here. }
各フレームで任意のクエリの SendVisualDebug() メソッドを呼び出して、そのクエリに関する視覚的なデバッグ データをレンダリングすることができます。Navigation Lab をゲームに接続している間は、クエリは自動的に表示リストを作成し、Navigation Lab に送信します。
表示リストの内容と、その結果 Navigation Lab に表示されるデータは、クエリのタイプによって異なります。クエリに表示される視覚的なデータの意味を解釈するには、sdk¥include¥gwnavruntime¥queries¥blobs ディレクトリの QueryDisplayListBuilder クラスにあるインライン実装を参照してください。
クエリを非同期に実行する場合や、処理するためにキューに配置する場合は、クエリが完了したときに通知を受け取ると便利です。処理の現在の状態を特定するのにクエリ結果をポールする必要がありません。
クエリを実行のために World にプッシュする場合、クエリが処理されると、World の更新時にオブジェクトの IOnDone::OnDone() メソッドが自動的に呼び出されます。独自の QueryQueue を使用する場合、オブジェクトはクエリが処理された後、次回 QueryQueue::FlushQueries() を呼び出すときに呼び出されます。
クエリ クラスの m_onDone メンバーは、IOnDone::OnDone() メソッドが呼び出されると KY_NULL にリセットされます。同じクエリ インスタンスを再起動し、通知を再度受け取る場合は、m_onDone メンバーを再設定する必要があります。
Gameware Navigation API のクエリの多くは、クエリを実行し、クエリの結果についてビジュアル フィードバックを提供する Navigation Lab にも公開されています。これは、地形用に生成された NavData をテストし、各クエリのさまざまな入力および出力を理解するのに役立ちます。
Navigation Lab でのクエリの実行の概要については、「Navigation Lab で作業を開始する」を参照してください。