web-dev-qa-db-ja.com

2D衝突検出用のクワッドツリー

2D衝突検出に四分木を使用しようとしていますが、それを実装する方法に少し困っています。まず、4つのサブツリー(各象限を表す1つ)を含む四分木と、単一のサブツリーに収まらないオブジェクトのコレクションがあります。

ツリー内のオブジェクトの衝突をチェックするとき、私はこのようなことをします(2D衝突検出のための QuadTreeのおかげで ):

  1. オブジェクトをチェックして、現在のノード内のオブジェクトとの衝突がないか確認します。
  2. スペースがオブジェクトと重なるサブツリーについては、再帰します。

四分木ツリー内のすべての衝突を見つけるには:

  1. 現在のノード内の各オブジェクトを、現在のノード内の他の各オブジェクトに対してチェックします。
  2. 現在のノードの各オブジェクトを各サブツリーと照合します。

四分木に挿入するには:

  1. オブジェクトが複数のサブツリーに収まる場合は、現在のノードに追加して戻ります。
  2. それ以外の場合は、サブツリーに含まれているサブツリーに再帰します。

四分木を更新するには:

  1. 各サブツリーに再帰します。
  2. 現在のノードの要素が現在のツリーに完全に収まらなくなった場合は、それを親に移動します。
  3. 現在のノードの要素がサブツリーに収まる場合は、その要素をサブツリーに挿入します。

よろしいですか?改善できますか?

33
bfops

四分木構造は最適ではありません。ノードごとに4つのサブツリーを格納するのは適切ですが、実際のオブジェクトは、内部ノードではなく、リーフ内にのみ格納する必要があります。したがって、実際のオブジェクトを保持するコレクションを葉に移動する必要があります。

operationsの実装を見てみましょう:

  1. 四分木にオブジェクトを挿入
    オブジェクトが現在のノードと交差するかどうかを確認します。もしそうなら、再帰します。リーフレベルに達した場合は、オブジェクトをコレクションに挿入します。
  2. 四分木からオブジェクトを削除
    オブジェクトを挿入する場合とまったく同じ手順を実行しますが、リーフレベルに達したら、コレクションから削除します。
  3. オブジェクトがクワッドツリー内のオブジェクトと交差するかどうかをテスト
    オブジェクトを挿入する場合とまったく同じ手順を実行しますが、リーフレベルに達したら、コレクション内のすべてのオブジェクトとの衝突を確認します。
  4. クワッドツリー内のすべてのオブジェクト間のすべての衝突をテスト
    四分木内のすべてのオブジェクトについて、単一オブジェクトの衝突テストを実行します。
  5. 四分木を更新
    位置が変更されたクワッドツリーからすべてのオブジェクトを削除し、再度挿入します。

これにはいくつかの利点があります

  • 葉にオブジェクトを格納するだけで、四分木の操作を非常に簡単に処理できます(特殊なケースが少ない)
  • 四分木は異なる深さのリーフを持つことができ、それによって四分木がカバーする空間領域に応じて四分木の密度を適応させることができます。この適応は実行時に発生する可能性があるため、オブジェクトとノードの比率を最適に保ちます。

のみ不利な点

  • オブジェクトは、クワッドツリー内のいくつかのコレクションに属することができます。重複なしにすべてのオブジェクトを列挙するには、四分木の外側に追加の線形コレクションが必要になります。
36
Dave O.

四分木は、衝突検出に常に最適なデータ構造であるとは限りません。クワッドツリーのオーバーヘッドは無制限になる可能性があり(ツリーの深さを制限しない場合)、最悪の場合はまったく速度を上げないでください。代わりに、スパースグリッドの使用を検討することをお勧めします。これにより、複数のツリーレベルをトラバースする余分なオーバーヘッドがなく、クアッドツリーよりもパフォーマンスが向上します。

さらに良いかもしれない他の完全に異なるアプローチもあります。たとえば、次のモジュールで行ったように、ZomorodianおよびEdelsbrunnerのアルゴリズムを実装してみることができます。

これらの問題をより詳細に議論するために私が書いたいくつかの記事もここにあります:

特に、前のセクションのベンチマークを見ると、調査されたすべてのライブラリーのクアッドツリーは、Rツリー、グリッド、セグメントツリーなどの他の衝突検出方法と比較して、パフォーマンスが非常に悪い傾向があります。

7
Mikola

まだどの程度のCPU効果があるのか​​はわかりませんが、Eclipseで私のコアデュオで問題なく動作しているようですが、それでも2400 fpsを超えていますlol ..

基本的に、衝突可能なオブジェクトに1つのリストを追加して、(四分木への挿入により)オブジェクトを関連付けた四分木ノードオブジェクトへの参照を格納します。また、各クワッドツリーノードにリストを追加しました。このリストには、そのノードの境界内であると見なされたオブジェクトへの参照が格納されています。したがって、各ノードには各オブジェクトが1つだけ出現します。各ノードには、親ノードへの参照も格納されます。衝突の精度をさらに上げるために最初のノードの後に​​それらのノードをチェックしたい場合は、近くのノードに移動します。

1つのセルで他のすべてのオブジェクトへの参照を取得するのは非常に簡単です。

list temp_checklist = object.cells[cell_index].objects
//('objects' being some sort of array or list of object references as described above)

それが誰かを助けることを願っています;)

0
Lazouskie