より高速な2D衝突検出


13

最近、ペースの速い2Dシューティングゲームに取り組んでいますが、大きな問題に遭遇しました。衝突検出。確かに、動作していますが、非常に遅いです。私の目標は、画面上に多くの敵を配置し、お互いに触れないようにすることです。すべての敵がプレイヤーエンティティを追いかけています。それらのほとんどは同じ速度を持っているので、遅かれ早かれ、プレイヤーを追いかけている間にすべて同じスペースを取ることになります。プレイヤーにとっては、1人の敵だけに追われているように見えるので、これは本当に楽しい要素を減らします。彼らが同じスペースを取るのを防ぐために、衝突検出(非常に基本的な2D検出、私が知っている唯一の方法)を追加しました。

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

これは正常に機能します。敵のエンティティが200未満である限り。300〜350の敵エンティティに近づくと、フレームレートが大幅に低下し始めます。最初にレンダリングが悪いと思ったので、描画呼び出しを削除しました。これはまったく役に立ちませんでしたので、もちろん、それが更新方法であることに気付きました。更新方法の唯一の重い部分は、この各敵ループから全敵の部分です。300人の敵に近づくと、ゲームは90000(300x300)ステップのイタレーションを行います。私の〜

私はこの衝突検出にアプローチする別の方法があるに違いないと確信しています。方法はわかりませんが。私が見つけたページは、2つのオブジェクト間の衝突を実際に行う方法、またはオブジェクトとタイル間の衝突をチェックする方法に関するものです。私はすでにこれらの2つのことを知っています。

tl; dr?エンティティのロット間の衝突検出をどのようにアプローチしますか?

クイック編集:助けになる場合は、C#XNAを使用しています。


そもそも90Kに到達するためにどうやってそれを手に入れたのだろうかと思っています。鉱山は20Kでチョークします(ただし、SAT MTVの完全な検出を行っています)。しかし、私はすべての敵をループすることが可能と思われる唯一のものです。しかし、あなたがする必要があるのは、彼らがすでにチェックされているかどうかをチェックすることです。
妄想論理


@MarkusvonBroadyがリンクした質問には非常に良い答えがあります。
サイファー

回答:


11

あなたはすでに頭の中であなたの問題を直撃しました、あなたは他のすべてのエンティティに対してすべてのエンティティをチェックさせています。必要なのは、可能性のある衝突候補がより適切に選択された、ある種の「詳細レベル」システム(非常に単純なシーングラフ、レンダリング以外のものに使用するだけです)です。

私は通常、このようなシステムに対して3つのコレクションを実行します。そして、あなたが持っていることを目指しているエンティティの数について話しているとき、追跡データ(他のすべてのエンティティのエントリを持つエンティティごとに3つのリスト)がすぐに出ることができるので、これのために完全なシーングラフを使用する必要さえあります制御の。

基本的には3つのリストがあります。最初のものは、フレームごとにインタラクションで確認するエンティティの非常に小さなリストである必要があります。問題のエンティティのX範囲内にあるため、これを決定します。前述のように、このリストのポイントは、他のこのフレームと合理的に衝突する可能性のあるすべてのエンティティを含めることです。

次のリストは、バッファ範囲内にあり、あまり労力をかけずにエンティティの範囲内に移動できるものです。この範囲を引数としてX * 1.5と呼びます。これはタイムスライスリストであり、フレームごとにほんの少数を更新しますが、スムーズに動作するように見えるように十分な速度でそれらを通過するようにします。

3番目のリストは「他のすべて」リストであり、これを避ける方法は価値があるかもしれません(エンティティリスト全体をスキャンし、進行する前に他のリストの1つにあるかどうかを確認するかもしれません?リストサイズに応じてこのリストのオブジェクトは、他の2つのリストのいずれかに確実に数フレーム以上を配置する必要があるため、ほとんどチェックされません。

これを維持するために必要なことは、衝突テストを行っているときに、エンティティが含まれるリストを必ず更新することです。範囲外に移動するものはダウングレードする必要があります。より積極的にチェックされたリスト。

あなたが物事を十分にシンプルに保つと仮定すると、これはあなたのニーズに合うはずです。既存のレンダリングシーングラフに追加情報を入力して(存在する場合)、クエリを実行して、合理的に範囲内にあるエンティティのリストを取得できます。とにかく(位置に基づく関連データのリストへの高速アクセス)。これは、潜在的により多くの作業を必要とする可能性があり、常に実行する必要があることと実際に行うべきことを常に検討する必要があります。

お役に立てれば。


1
これはあいまいな答えです。そして、いくつかの衝突を見逃すことを受け入れることができますか?ここで説明したクアッドツリーのように、もっと簡単に、表面分割を行うデータ構造を使用してください。クアッドツリーでさえ、オーバーヘッドを回避するために少し微調整が必​​要なので、あなたが話している「ソリューション」の複雑さを想像することはできません。基本的なプログラミング規則:正しいデータ構造を使用するだけです。
GameAlchemist

@VincentPielシーングラフは、クアッドツリーほど複雑ではありません。
サイファー

@ジェームス:明らかにそれはより複雑です。QuadTreeの全速度を把握する必要がない場合は、ネット上でQuadTreeライブラリを取得し、数時間で完全に機能させることができます。次のような質問はありません:最初のリスト、2番目、3番目に何を入れるか、どのようにエンティティを別のリストに入れるかを決めます... 車を所有できるのに、なぜ自転車を使うのですか?
GameAlchemist

@VincentPielここで私ではなく、Cypherに@コメントするつもりだったと思います。クワッドツリーは誰でもシーングラフの一種であり、毎秒Xフレームで実行していることを覚えておく必要があります。衝突が見落とされていることに気づいた場合、範囲のしきい値を調整して、バランスを改善する必要があります。私の解決策は、衝突する可能性のあるすべてのフレームのみをチェックし、残りのバックグラウンド/制限付き更新を行って、それらがより高い優先度の資格があるかどうかを確認する非常に単純なアプローチです。
ジェームズ

6

ソートされたデータ構造との衝突を処理する必要があるため、ひどいn ^ 2の代わりにn * log(n)回発生する可能性があります。そして、ご存じかもしれませんが、n * log(n)はほぼ線形です。1つの(古典的な)例はクワッドツリーです。ここには、グラフィックとコード(Java)を使用した非常にシンプルでよく書かれたチュートリアルがあります。

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq:どの言語でもQuadTreesの実装を見つけるのは非常に簡単です。それでも、ツリーの適切な「粒度」について考える必要があり、ツリーのサイズが大きくなるほど、ノード内に収まらないエンティティが増えます。
Rq 2:空間分割は衝突検出のためにのみ行われるため、自由に空間を分割できます。たとえば、4つのエガルパートに分割するのではなく、現在のレベルのエンティティの重心を新しい分割の中心として使用します。1)アルゴリズムはまだn * log(n)です、2)ツリーからシーンを「再構築」する可能性を失います-しかし、気にしません-3)よりバランスのとれたツリーがあり、オーバーヘッドが少ない。
Rq3:ツリーを取得したら、画面とエンティティ間の「衝突」によって...目に見えるエンティティが得られます!! log(n)のような時間で、nが大きい場合はどうでしょうか?(最悪の場合は、明らかにこのアプローチのn時間です。)


ええ、クアッドツリーは、まさにシーングラフの一種です。私はいつも、ここにいる人は他の人のライブラリを使用せずに自分で物事を書きたいと思っているだけです。
ジェームズ

0

バイナリスペースパーティションツリー、クアッドツリー、octree(3D用)は、コリジョンを適用するすべてのオブジェクトの更新呼び出しごとに生成(または、野心的な場合は維持)できるツリーです。


3
これは、コメントに適しています。回答にさらに追加することを検討してください。

0

クワッドまたはオクトツリーについて話すとき、私は非常に素朴です。しかし、私はこの方法でやるべきだと思う:

プレーヤーの構造/クラスを変更する必要があります。他のプレーヤー構造へのポインターの配列/ベクトルを追加します。

1秒ごとに2人のプレーヤー間の距離を確認します。1秒以内に到達できるほど低い場合は、そのプレーヤーのポインターを現在のプレーヤーの衝突配列に追加します。

ここで、互いのリスト内のプレーヤー間の衝突のみをチェックします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.