多くの正方形のタイルベースの効率的な衝突検出?


9

現在私はタイルベースのゲームの独自のテイクに取り組んでいます(Terrariaを考えてくださいが、空想的ではありません(それは言葉だと思いますか?そうでない場合は申し訳ありません))。

とにかく、私は現在、衝突検出が機能しています(コーナーケースの場合でも!)。これは私にとって大きな一歩でした。スプライトがブロックを通過しないのを見るのは非常にうれしいことです。しかし、それから私はベンチマークするという考えを持っていました。悪いアイデア。

1,000平方、問題ありません。10,000の正方形、3つの文字は少し遅れました。3文字で100,000の正方形(本当に巨大な地図)はプレイできませんでした。

プレイヤー、キャラクター、アイテムなどから遠すぎるブロックも考慮したくないという問題がありますが、それらを常にメモリからロードしたくありません。

ここまでが私のアルゴリズムです。自由に非難してください。

foreach (Block in level)
{
    if (distance from block to player > a specified amount)
        ignore this block;
    else
    {
        get the intersection depth between the two bounding boxes
        if (depth of intersection != Zero-vector)
        {
            check y size vs x size
            resolve on smallest axis
        }
    }
}

お気づきのように、レベルサイズが大きくなると、このアルゴリズムの次数はNブロック増加します。プレイヤーの近くにもないブロックも考慮しません。

リストの代わりに(0,0)から(mapWidth、mapHeight)までのブロックの二重配列を使用して、人の位置に応じて危険ゾーンを計算することを考えています(たとえば、プレーヤーの位置が(10、20)にある場合) (0、10)から(20、30)のようになります。

どんな考えや配慮も素晴らしいです、ありがとう。


1
そしてstackexchangeへようこそ!:-) QA全体とレピュテーションシステムがどのように機能するかを知らない場合は、FAQを必ずお読みください。
David Gouveia

確かに、これらのタイルは16 x 16ピクセルより大きく、1920 x 1080では8,100タイルです。確かに、移動可能なエンティティがどこにあるかを知っており、グリッド内のタイルをチェックできるのは、範囲内にある可能性があるタイルのみです(1つが160 * 160で、中心がタイル(12、12)の場合)。タイル間でのみチェックする必要があります(6 、6)と(18,18)で合計150タイルまで可能です。確かに重力下のタイルは落下するだけなので、その下にある次のタイルを探すだけです。
DampeS8N 2011

16x16は小さすぎると思いますか?tilewidth / heightを参照するものはすべて静的定数であるため、タイルのサイズを変更することは難しくありません。私がしなければならないのは、それらをPaint.NETで拡大することだけです。
ロス

衝突コードを共有していただけませんか?:/
ashes999

回答:


7

はい、あなたは正しく考えています。位置によってタイルにインデックスを付けることができるため、タイルの2D配列を使用する必要があります。

Block[,] level = new Block[width, height];

また、プレーヤーは周囲のタイルとのみ衝突できるため、実行する必要がある衝突チェックの数は非常に少なくなります。もちろん、これはプレーヤーのサイズによって異なります。プラットサンプルはこのようにそれを行います。

int leftTile = (int)Math.Floor((float)characterBounds.Left / tileWidth);
int rightTile = (int)Math.Ceiling(((float)characterBounds.Right / tileWidth)) - 1;
int topTile = (int)Math.Floor((float)characterBounds.Top / tileHeight);
int bottomTile = (int)Math.Ceiling(((float)characterBounds.Bottom / tileHeight)) - 1;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {
        // Handle collisions with the tile level[x,y] just like you were doing!
    }
}

それでも問題が解決しない場合は、サンプルを確認してください。


これは非常に優れた小さなアルゴリズムです。Platformerサンプルについては聞いたことがありませんでした(私は持っているべきですが、私は無知です)。ありがとうございました!
ロス

@ロス本当に?あなたのソリューションがサンプルにどれほど似ているかに驚かれることでしょう。:-)リスト部分を除いて、その他はすべてほぼ同じです(境界ボックスを交差し、交差深度を取得し、最小軸で解決します)。
David Gouveia

1
おお、私はそれを見ただけだ。>。<2日前に知ってほしい!! XNAは初めてですが、2Dグラフィックスを掘り下げました(OpenGLのみで、ゲームプログラミングはそれほど多くありません)。コーディングに真っ先に行く前に、最初に多くのリソースをチェックする必要があると思います。
ロス

1

私の答えはあなたの答えだと思います!;-)

プレーヤーの位置(およびサイズ)がある場合、周囲のタイルのインデックスを計算できます(これらは詳細にチェックされる唯一のタイルです)。このように、マップの大きさに関係なく、プレーヤーの実際のサイズに依存するだけなので、チェックするタイルの可能性が高くなります。

衝突に関するチュートリアルをriemers.netで確認してください


リーマーのことは聞いたことがありますが、見回すことができませんでした。ありがとうございます。
ロス

1

多数の衝突を処理する場合、通常はより高度な構造を採用する必要があります、クアドツリーやハッシュマップなどのそれらの衝突をチェックします。

タイルは静的なので、四分木を使用することをお勧めします。クワッドツリーはクワッドで構成されます。各クワッドは4つの長方形で構成され、これらの各長方形はクワッドです。これは、指定されたサイズまで再帰的に続きます。各クワッドには、画面のその領域に存在するタイルのリストを含めることができます。そうすれば、衝突をチェックしているときに、

  1. チェックをすぐ近くのチェックに制限する
  2. チェックを移動しているオブジェクトのみに制限する

画面外のタイルを見たくない場合は、次のようにすることができます

public bool CheckCollision(myPosition) {
    if(quadNodes.Count > 0) {
        // This is not a leaf, keep checking
        foreach(Quad node in quadNodes) {
            if(node.Position is insideViewport && nearPlayer)
                // Continue recursion
            }
        }
    }
    else {
        // This is a leaf, do checks
        foreach(Tile tile in tileList) {
            if(collision)
                return true;
        }
        return false;
    }
}

うーん、3D衝突検出でOctreesを聞いたことがありますが、高度なデータ構造が2D衝突検出に使用されているのを見たことがありません。どうもありがとうございました!
ロス、

1
彼のゲーム(Terrariaを想定)は等間隔のタイルで構成されているため、グリッドの使用は四分木よりもはるかに簡単で高速です。クワッドツリーは、グリッドがフィットしにくく、すべてが任意のサイズである、より複雑な世界に適しています。
David Gouveia

1
純粋にグリッドベースのゲームであれば、キャラクターのサイズまでは正しいです。Terrariaには、グリッド形式に簡単に収まらないモンスターもいることは知っています。基本的な世界はタイルでできているが、他のオブジェクトは異なり、別のオブジェクトを構築することを避けるためにそれらを同様の構造に格納できるという仮定の下で実行していました。私は、タイルにグリッドを使用し、他の任意のオブジェクトに(必要に応じて)異なる構造を使用できると思います。
Mike Cluck、2011

1
それが私が提案しようとしていたことです:)グリッドは地形との衝突を処理するために使用する必要がありますが、クワッドツリーはオブジェクト間の衝突を処理するために使用できます。
David Gouveia

そうだね。現在、すべての境界ボックスは2 ^ power次元を持っています。これにより、衝突検出がはるかに簡単になります。グリッドは今のところ私のニーズに合います。
ロス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.