2Dプラットフォーマーの衝突処理


8

2Dプラットフォーマー(マリオタイプ)ゲームを作成しようとしていますが、衝突の適切な処理に問題があります。私はこのゲームをC ++で書いており、入力、画像の読み込み、フォントの読み込みなどにSDLを使用しています。また、グラフィックを表示するためにSDLと組み合わせてFreeGLUTライブラリを介してOpenGLを使用しています。

私の衝突検出方法は、AABB(Axis-Aligned Bounding Box)です。必要なのは、衝突が発生した側を検出し、衝突を適切に処理する簡単な方法です。したがって、基本的に、プレーヤーがプラットフォームの上部に衝突した場合は、プレーヤーを上部に移動します。側面に衝突がある場合は、プレーヤーをオブジェクトの側面に戻します。底に衝突がある場合は、プラットフォームの下にプレーヤーを再配置してください。

私が試してみました多く、このような浸透深さを見つけようと侵入深さによって後方プレーヤーを再配置するようにこれを行うためのさまざまな方法を、。残念ながら、私が試したことは何も正しく動作していないようです。プレイヤーの動きが非常にグリッチになり、望まないときにプレイヤーの位置を変えます。その理由の1つは、おそらくこれはとても単純なものだと思っているためですが、考えすぎています。

誰かが彼らが助けることができると思っている場合は、以下のコードを見て、可能であればこれを改善するのを助けてください。これを処理するためにライブラリを使用しないでください(自分で学びたいので)、または可能であればSAT(分離軸定理)のようなものを使用しません。よろしくお願いします!

void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
    if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
    {
        de2dObj ballPrev;
        ballPrev.coords[0] = ball.coords[0];
        ballPrev.coords[1] = ball.coords[1];
        ballPrev.coords[2] = ball.coords[2];
        ballPrev.coords[3] = ball.coords[3];
        ballPrev.coords[0] -= ball.xspeed;
        ballPrev.coords[1] -= ball.yspeed;
        ballPrev.coords[2] -= ball.xspeed;
        ballPrev.coords[3] -= ball.yspeed;

        int up = 0;
        int left = 0;
        int right = 0;
        int down = 0;

        if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
        {
            left = 1;
        }

       if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
        {
            right = 1;
        }
        if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
        {
            up = 1;
        }
        if(block[i].coords[1] < ballPrev.coords[1] && ball
        {
            down = 1;
        }

        cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;

        if (left == 1)
        {
            ball.coords[0] = block[i].coords[0] - 18.0f;
            ball.coords[2] = block[i].coords[0] - 2.0f;
        }
        else if (right == 1)
        {
            ball.coords[0] = block[i].coords[2] + 2.0f;
            ball.coords[2] = block[i].coords[2] + 18.0f;
        }
        else if (down == 1)
        {
            ball.coords[1] = block[i].coords[3] + 4.0f;
            ball.coords[3] = block[i].coords[3] + 20.0f;
        }
        else if (up == 1)
        {
            ball.yspeed = 0.0f;
            ball.gravity = 0.0f;
            ball.coords[1] = block[i].coords[1] - 17.0f;
            ball.coords[3] = block[i].coords[1] - 1.0f;
        }
    }
    if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
    {
        ball.gravity = -0.5f;
    }
}
}

このコードの一部が何を意味するかを説明するには:

ブロック変数は基本的に、ブロックまたはプラットフォームの量を格納する整数です。forループを使用してすべてのブロックをチェックしていますが、ループが現在オンになっている番号は整数iで表されています。座標系は少し奇妙に見えるかもしれませんので、説明する価値があります。coords [0]は、オブジェクトのx位置(左)を表します(x軸上で開始)。coords [1]は、オブジェクトのy位置(上)を表します(y軸上で開始)。coords [2]は、オブジェクトの幅とcoords [0](右)の幅を表します。coords [3]は、オブジェクトとcoords [1](下)の高さを表します。de2dCheckCollisionは、AABB衝突検出を実行します。ほとんどのゲームと同様に、アップは負のy、ダウンは正のyです。

うまくいけば、私が誰かが私をうまく助けるのに十分な情報を提供してくれた。欠落している重要な問題がある場合は、お知らせください。必要な情報を提供します。最後に、助けることができる人にとっては、コードを提供することは非常に役立ち、非常に高く評価されます。

あなたの助けをありがとう!

編集:私は、衝突前にボールが以前あった場所をチェックする新しいアルゴリズムでコードを更新しました。コーナーケースはその単一のプラットフォームで正しく動作しますが、オブジェクトの壁がある場合、それに対して実際にスライドできますが、スライド中に壁に向かって移動すると、それを通過し、基本的に壁の内側をブロックします。また、私が地面にいるとき、ボールが常に上下に動いているときに発生するジッタリング効果があります。


ジッタを解決しましたか?そうでない場合は、おそらくTheirPos-ourSize +- 11 を削除するのではなく、キャラクターを遠くに移動している問題であり、そうしている場合は1 を削除します。そのアルゴリズムを理解する方法がわからない場合は、私は喜んで助けてくれるでしょう、私は現時点では完璧です=](また、オブジェクトをチェックインする順序は何ですか?)
ultifinitus

回答:


6

コードを正しく理解できれば、速度に影響を与えずにボールを一定量オフセットすることで衝突を補正できます。ボールが揺れる動作をする理由は、その位置は衝突に基づいて修正されますが、その速度は衝突するオブジェクトに向けられているためです。この速度のため、ボールはまだ衝突ブロックに向かって移動しており、数フレーム後に再びオフセットして衝突します。

おそらくこれに対する最も簡単な解決策は、衝突時に速度がリセットされるようにし、ボールがオフセットされた後にブロックに向かって移動しないようにすることです。


5

ボールの動き/速度を処理するコードは表示しません。ボールを停止/バウンスしないと、次のフレームでボールがブロックに戻り、「移動」するため、ブロックの側面で「スタック」します。

そうでない場合は、問題をより具体的に示したり、より多くのコードを投稿したりできれば、誰かがより良い支援をすることができるかもしれません:-)


それが役立つ場合は、コードを更新し、衝突が発生する前にボールがどこにあったかをチェックする新しいアルゴリズムを追加しました。残っている唯一の問題は、私が地面にいるときに小さなジッター効果が発生することです。ボールが重力に引かれているかのようにボールが絶えず上下に動いていて、ボールは再びオブジェクトに落ちます。
defender-zone、

ボールを元の位置に戻したくない@ defender-zone。衝突が発生したときにボールと障害物の重なりを計算し、計算された量(重なり)だけボールを障害物から遠ざけます。
bummzack 2011年

4

まああなたはいつも私がしたことをすることができますが、実装が不十分だったのは私の側でした、私は「being」クラスにupdate_prev_pos()と呼ばれる単純なメソッドを持っています。後。私の衝突解決機能では、問題の辺の位置を調べます。サイドが以前にオブジェクトの外側にあった場合は、そのサイドを修正する必要があります。

衝突をチェックして解決するために、2パスメソッドを使用しています。私が行うことをお勧めするのは、すべてのx軸の衝突をチェックし、次にすべてのy軸の衝突をチェックすることです。そうすれば、すべきでないオブジェクトにスタックすることはありません。幸せな衝突=)


1

助けてくれてありがとう、みんな、そして遅れてごめんね。

私はこれらのアイデアをすべて考慮に入れ、問題を解決するのに役立ちました。誰もが、私はオリジナルと完全な問題を解決した方法を知りたい場合には、見てここに(より正確には、衝突の取り扱いに関する説明を含む)完全な答えをスタックオーバーフローに。私の質問に答えた人は本当に寛大で、図表を提供してくれたので、この問題を抱えている人たちにも役立つはずです。

この問題について私を助けてくれた以下の人々に感謝します:

  • DanTup-Danny Tuppeny
  • Bummzack
  • ゴーストオンライン
  • ULTIFINITUS

とても感謝しています!


5
回答としてマークするよりも、あなた自身の回答を作成するよりも、あなたを助けた人々にクレジットを与える方が良いと思います。少なくとも、賛成投票をしてください。ちょうど私の2セント。
DMan、2011年

それは良いアイデアです; 考えなかった。申し訳ありませんが、賛成するほどの評判はまだありません。でも私はそれを手に入れました。
defender-zone、

@ defender-zone-それはあなたに反するものではありません。私は自由を取り、あなたのためにすべての答えに賛成しました。
DMan、2011年

よろしくお願いします。どうやら、私はあなたの賛成投票のおかげで賛成投票に十分な評判を得たので、私もそうしました。また、私の回答を助けてくれた人々にも感謝しています。
defender-zone、

@ defender-zone-ハハ、それはかなり甘い。そんなことを覚えていませんでした!
DMan、2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.