Gameware Navigation には、空間内の 2 点間で、レベル ジオメトリに対して高パフォーマンス衝突テスト(レイキャスト)を行うための、軽量で複雑性の低いシステムが含まれています。
多くの場合、これらのテストは物理サブシステムで実行されます。ただし、多くのゲーム(ほとんどの場合 MMO)では、ネットワークの通信ラグ、技術的な複雑性、ランタイム パフォーマンスのオーバーヘッドなどにより、本格的な物理システムの統合に問題や困難が生じる可能性があります。プロジェクトがこれに当てはまる場合で、それでもこれらの種類の衝突テストをゲーム レベルのジオメトリに対して行う必要があるときには、Gameware Navigation 衝突システムを活用できるかもしれません。
ビルトイン衝突システムは、地形用の NavData から分離されている事前生成されたデータに依存します。したがって、データ生成プロセス中に提供した地形の静的要素との衝突のみを検出することができます。実行時に追加した動的オブジェクトを地形の NavData に統合しても、それらのオブジェクトを考慮することはできません。
衝突データを生成するために C++ NavData 生成 API を使用します。まだ NavData 生成 API をゲーム エディタ、レベル デザイン ツール、ビルド プロセスに統合していない場合は、「統合フェーズ 6: NavData 生成 API を使用する」を参照してください。
NavData 生成コードの中で、地形内にある希望する各セクタの衝突データ生成をアクティブにする必要があります。
セクタに NavData を生成する際には、そのセクタ用の NavData 生成システムに対して渡した三角形からそのセクタの衝突データも自動的に生成されます。各セクタのデータは .ColData ファイルでディスクに書き込まれます。そのセクタに対して生成された .NavData ファイルと同じ場所にあり、同じファイル名になります。
// Create a sector... Kaim::GeneratorSectorConfig sectorConfig(Kaim::KyGuid::GetDefaultGuid(), generationName); Kaim::GeneratorSector* sector = env.m_generatorInputOutput.AddSector(sectorConfig); ... // Activate collision data generation sector->SetColDataBuildMode(Kaim::GenFlags::SECTOR_COLDATA_BUILD_ENABLED); ... // Generate NavData and collision data KyResult result = m_generator->Generate(m_generatorInputOutput);
NavData 生成システムに地形の各セクタを構成する個々の三角形を提供する代わりに、高さフィールド(heightfield)と三角形化されたメッシュを提供することができます。
高さフィールド(heightfield)は、単純な単層の地形の高度を表すために最適化された方法です。地形メッシュを構成するすべての三角形を含める代わりに、高さフィールド(heightfield)は単一の原点と、原点の周囲の規則的なグリッドでサンプリングした高度値のセットから構成されています。このデータは完全に三角形化されたメッシュよりもはるかにコンパクトで複雑性が低いため、衝突テストでのランタイム メモリの消費を抑え、パフォーマンスを大きく向上させることができます。
高さフィールド(heightfield) を使用することの欠点は、高さフィールド高さフィールド(heightfield)は通常、グリッド内のサンプルの間隙で発生する高さの局所的な変化に対する精度が低いことです。このため、高さフィールドから生成された NavMesh、および高さフィールドに対して行われた衝突テストの精度が低くなる可能性があります。この精度の不足を補うために、地形の小さな特徴に対する高い忠実性が必要となる場所で、地形のより複雑な領域に対する三角形化されたメッシュも提供することができます。
効率性と精度の最善のバランスを得るには、高さフィールド(heightfield)を野原などの広い開けた領域を表すために使用し、三角形化されたメッシュを市街地などの高い精度が必要となる領域を表すために使用します。例:
セクタに高さフィールド(heightfield)とインデックス化されたメッシュを渡すには、地形ジオメトリを NavData 生成システムに渡すために NavData 生成パイプラインで使用する GeneratorInputProducer 内の GeneratorInputProducer::Produce() の実装を更新する必要があります。
セクタに高さフィールド(heightfield)を提供するには:
このアプローチを使用すると、NavData が高さフィールドや三角形化されたメッシュを基に生成されることに注意してください。そのため、個々の三角形を直接 ClientInputConsumer に提供する必要はありません。
各 World は、World::m_collisionWorld クラス メンバーの中に CollisionWorld クラスのインスタンスを保持します。このクラスはメモリにロードした衝突データを集約したり、そのデータに対して行った衝突テストを管理する役割を持ちます。これは、World を初期化した後に渡す必要のある ICollisionInterface を実装するクラスのインスタンスのメソッドを呼び出すことで行われます。
Gameware Navigation には、オープンソースの Bullet の物理/衝突テスト システムに依存する ICollisionInterface の実装が含まれています。詳細については、www.bulletphysics.org を参照してください。
デフォルトの ICollisionInterface 実装を使用するには:
m_navigationWorld = *KY_NEW Kaim::World(databaseCount); Kaim::Ptr<Kaim::ICollisionInterface> visInterface = *KY_NEW CollisionInterface(m_navigationWorld); m_navigationWorld->m_collisionWorld->SetCollisionInterface(visInterface);
地形に対して作成した衝突データに対して衝突テストを行う必要がある場合、衝突データをメモリにロードして衝突ワールドに追加する必要があります。これは通常、そのセクタに必要な NavData と他の種類のデータをメモリーにストリーミングしたり、メモリーからストリーミングするのと同時に地形の各セクタに対して行います。このプロセスは NavData を Database にストリーミングしたり、 Database からストリーミングするのと非常に似ています。
Kaim::Ptr<Kaim::CollisionData> colData = *KY_NEW Kaim::CollisionData; if (Kaim::Result::Fail(colData->Load(GetAbsoluteInputFileName(fileName).c_str(), &m_fileOpener))) return KY_NULL; GetWorld()->m_collisionWorld->AddCollisionData(colData);
World 内にロードした衝突データに対して衝突テストを実行するには、CollisionRayCastQuery クラスのインスタンスを設定して起動します。
たとえば、次のコードはポイント A とポイント B の間の直線パスに沿って衝突をテストします。
Kaim::CollisionRayCastQuery query; query.BindToWorld(m_navigationWorld); query.Initialize(pointA, pointB); query.PerformQuery(); if (query.GetResult() == Kaim::RayHit) ... // A collision was found if (query.GetResult() == Kaim::RayDidNotHit) ... // No collision was detected
World によって保持されたキュー(またはフレームごとの最大時間の割り当てを使用して作成および設定したカスタム キュー)内で CollisionRayCastQuery を非同期的で実行するためにクエリー システムによって提供されたメカニズムを利用することもできます。ゲームでいくつかの衝突テストを同じフレームで要求する必要がある可能性がある場合は、これらのアプローチが CPU のピークを回避するために役立ちます。
詳細は、「クエリ システムを使用する」を参照してください。