衝突回避処理
パス フォローイング中のダイナミック回避は、次の要件を満たすように各フレームの速度を計算する処理です。
- すべての移動する Bot や静的 Bot、またはパスにある障害物を避ける
- 計算されたパスを追従する(パスから離れすぎない)速度を選択する
- NavMesh の境界と計算されたチャネルに従う
- 可能な限り安定している間は、回避の試みを最小化する
ダイナミック回避は次のステップで構成されています。
- 潜在的なコライダを収集します。「コライダを収集する」を参照してください。
- さまざまな条件で回避速度のセットを生成してスコアを付けます。「回避速度を生成する」を参照してください。
- 指定されたフレームに適用する最も適切な速度を選択します。「最終スコアのためのユーティリティ関数」を参照してください。
次のセクションでは、ダイナミック回避処理について説明します。
コライダを収集する
シーンのワールド要素全体に基づいて Bot の回避を計算するには時間がかかります。さらに、ほとんどの場合回避はローカルであり、近くのエンティティに基づくため、これでは役割を果たしません。
また、時間的な一貫性のため、指定されたフレームで回避するエンティティがそれ以降のフレームとほぼ同じである可能性もあります。したがって、NavMesh 伝播構造を活用して、近くにある潜在的なコライダのリストを構築できます。指定されたフレーム
レートでこのリストを更新するだけで済みます。次の図は、コライダ コレクションの範囲を示しています。回避できるエンティティが表示されています。
ColliderCollectorConfig でこの処理を設定できます。パラメータは次のとおりです。
- m_colliderCollectorRadius: 潜在的なコライダを収集する範囲の半径を Bot を中心としたメートル単位で定義します。
- m_colliderCollectorHalfHeight: 潜在的なコライダを収集する範囲の高さを Bot の上下の高度のメートル単位で定義します。
- m_colliderCollectorFramesBetweenUpdates: 潜在的なコライダの、2 回の連続するコレクション間のフレーム数を定義します。
回避速度を生成する
指定された任意の時間にある Bot にとって、そのエンティティはさまざまな速度になる可能性があります。パス フォローイングのため、また無秩序な動作を回避するため、回避速度のセットを固定された範囲に制限できます。
まず、グローバルなパス フォローイングの方向を決定する必要があります。この方向は、パス フォローイング処理と互換性を持つように計算されます。
- ショートカット モード: パス上のターゲットをサポートする現在のパス エッジの方向を取ります。次の図では、回避するために参照する方向が現在のパス エッジに対して平行になっています。
- チャネル モード: 現在のチャネル セクションの方向を取ります。次の図では、参照する方向が現在のセクションの 2 つのゲート間の方向に対して平行になっています。
ここで、パス フォローイング方向の周りに N 個の回避速度のサンプルを生成します。次の図には、生成した速度のサンプルが表示されています。速度はデフォルトで 1.0 にスコア付けされます。
これらの速度の値は Bot の設定内の希望するスピードに一致します。AvoidanceConfig で、これらの速度サンプルの数と角度スパンを設定できます。パラメータは次のとおりです。
- m_avoidanceAngleSpan: 回避速度のための角度スパン(度単位)
- m_avoidanceSampleCount: 回避速度のためのサンプル数
これで最適な速度を選択するためにスコア付け処理を実行できます。
衝突時間
回避は空間的にも時間的にもローカルです。範囲として使用する制限時間を指定したり、サンプルごとに収集されたコライダで衝突時間を計算することができます。次の図は、指定されたフレームに対して計算された衝突時間を示しています。
衝突が存在しない場合、または衝突が設定した制限時間を過ぎている場合は、制限時間としてサンプルのコストを設定できます。
NavMesh またはチャネルの境界
NavMesh またはチャネルの境界からの距離に基づいてサンプルをスコア付けできます。次の図では、NavMesh の外側へと導くサンプルのスコアが低くなっています。
衝突までの時間の比率
0.0 と 1.0f の間の比率を計算するために衝突時間を範囲で分けることができます。1.0f が最も安全な速度です。次の図は、衝突時間を比率で示しています。
時間範囲は、AvoidanceConfig で指定できます。パラメータは次のとおりです。
- m_minimalTimeToCollision: 障害物が別の障害物と N 秒以内に衝突する場合に回避を考慮します。
- m_safetyDistance: 近くまで移動しすぎるのを回避するための、コライダ周囲の安全距離。コライダから遠く離れている速度を選択する為に、安全距離によってコライダのサイズを少し拡張できます。
スムージング
有効なサンプルと無効なサンプルを分ける角度が小さいために、サンプリングが不正確になる場合があります。安全でないサンプルを選択しないようにするために、速度のサンプルに隣接するもので各速度サンプルの平均の衝突時間の比率を計算できます。次の図は、スムーズな衝突時間を示しています。
これで安全で衝突のない速度を選択することができます。ただし、いくつかの可能性があるため、他の 2 つの基準を検討して決定することができます。
希望する速度
パス フォローイングで既に希望する速度が生成されました。この速度に対するサンプルの距離に基づいて、サンプルをスコア付けするためにこの速度を利用できます。次の図は、希望する速度(緑)からの距離に基づいてサンプルをスコア付けするのに、希望する速度がどのように使用されるのかを示しています。
前の速度
さらなる安定のために、前に計算された速度と比較した同様の計算を実行できます。次の図は、スコア付けが前の速度(赤)に基づいている様子を示しています。
最終スコアのためのユーティリティ関数
各サンプルに次のユーティリティ関数を使用して、最終スコアを計算することができます。
Final Score = (A * CollisionTimeRatio) + (B * DesiredVelocityDistance) + (C * PreviousVelocityDistance)
A、B、C は設定可能な定数です(A + B + C = 1.0 の場合が最もよく理解される)。最終スコアを取得すると、単純にサンプルのスコアが最も高い速度を返します。次の図は、回避用に出力する、選択された最終スコアと最終速度を示しています。
AvoidanceConfig で A、B、C を設定することができます。パラメータは次のとおりです。
- m_timeToCollisionInfluence: 回避速度を選択する際の衝突までの時間による影響
- m_desiredVelocityInfluence: 回避速度を選択する際の希望する速度による影響
- m_previousVelocityInfluence: 回避速度を選択する際の前の速度による影響
停止
適切な回避ソリューションがない場合、エンティティに速度ゼロを返して、次の衝突時間が指定されたしきい値より低い場合に停止することができます。パラメータは次のとおりです。
- m_stopCollisionTime: stopCollisionTime 秒以内に衝突が避けられない場合、エンティティが停止します。停止後は、ぎくしゃくした動きを回避するためにこの決定を確定することをお勧めします。
- m_stopWaitTime: エンティティが停止した場合、再度移動する前に stopWaitTime 秒間待機します。
場合によっては、まず速度を落としたり、エンティティが停止する機能を無効にすることもできます。パラメータは次のとおりです。
- m_enableSlowingDown: true に設定した場合、減速された速度の候補が考慮されます。それ以外の場合は、長さが Bot::GetDesiredSpeed() である速度の候補のみが考慮されます。
- m_enableStop: true に設定した場合、考慮される速度の候補は null です。それ以外の場合は、AvoidanceSolver は 決して Bot を停止させることを考慮しません。これにより、Bot が強制的にコライダを貫通することがあります。
ブロックされている時間が長すぎる場合には、通過を強制することができます。パラメータは次のとおりです。
- m_enableForcePassage: true に設定した場合、一定時間経過後に他のソリューションが見つからない場合に、衝突に対するソリューションを許可します。
- m_waitPassageTimeLimit: m_enableForcePassage が true の場合に、m_waitPassageTimeLimit 秒の遅延の後にのみ通過を強制します。
- m_forcePassageTimeLimit: m_enableForcePassage が true に設定されている場合に、m_waitPassageTimeLimit 秒の遅延の後にのみ最大 m_forcePassageTimeLimit 秒の通過を強制します。