衝突長方形の応答


10

移動可能な長方形を複数の長方形と衝突させるのに問題があります。

私はSFMLを使用していて、intersects2つの四角形を取り、その交差部分を返すという便利な関数があります。移動可能な四角形を衝突させたい四角形でいっぱいのベクトルがあります。私は次のコードを使用してこれをループしています(pは移動可能な四角形です)。

IsCollidingWithブール値を返しますがintersects、交点を計算するためにSFMLも使用します。

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

そして実際のCollide()コード:

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

そしてIsCollidingWith()コードは:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

これRectは、シーンに1つしかない場合に正常に機能します。ただし、複数あるRect場合は、2つの衝突を同時に処理するときに問題が発生します。

これを正しく処理する方法はありますか?私の問題を示すために動画をYouTubeにアップロードしました。右端のコンソールには、交​​差点の幅と高さが表示されます。コンソールで一度に2つの衝突を計算しようとしていることがわかります。ここで問題が発生していると思います。

最後に、以下の画像は私の問題をうまく説明しているようです:

他の複数の長方形と衝突する長方形


ビデオリンクが壊れています。
XiaoChuan Yu

colliderによってthis->getCollider()更新されたオブジェクトはによって更新されますthis->move()か?
XiaoChuan Yu

もう少し情報を追加していただけませんか?正確には何が問題ですか?YouTubeビデオは予測可能な動作を示しているようで、シーンには長方形が1つしかありません。
Wackidev

回答:


3

あなたの画像は、床のような平らな表面をシミュレートするために凸状の形状、特に長方形を使用しようとする際の多くの問題の1つを示しています。このアルゴリズムにより、床を構成するシェイプの内側のエッジにキャラクターがスタックします。

そのための簡単な修正は、垂直方向の衝突のみを確認し、それを修正してから、水平方向の衝突を再度確認することです。落下して壁を滑り降りようとしているのでない限り、その場合はまず水平方向の衝突をチェックする必要があります。最初にどちらを確認するかはどのようにしてわかりますか?速度のどの成分が大きいかに基づいてそれを行うことができます(水平方向の動きが大きい場合は、最初に垂直方向の衝突を確認し、それ以外の場合は水平方向の衝突を確認します)。

さらに単純になり、パフォーマンスが向上するのは、代わりに世界のエッジのリストを生成することです。つまり、床を構成するボックスに対して、上端のみが実際に衝突可能であることを示すフラグを設定し、他の端との衝突を無視します。SFMLの衝突ルーチンを使用することはできませんが、正直なところ、単純にボックスの衝突は、ゲームでこれまでに書いたコードの中で最も簡単なビットです。この手法は、世界がグリッドに配置されている場合に特に有効です。そのテクニックについては、優れたメタネットチュートリアル(http://www.metanetsoftware.com/technique.html/)を調べてみます。

あなたは、あなたがそうであるような単純な2Dプラットフォーマーゲームを構築しようとする他の多くの問題に遭遇するでしょう。これまでのところ、私が最近見た中で最も優れたリソースは次のリソースです。これを読んでから、もう一度読んでください。

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/



0

2つの衝突を計算することは問題ではなく、パフォーマンスの問題だと思います。衝突を正しく処理するには、2回テストする必要がある場合があります。ダイアグラムを使用して、Aが最初にBに対してテストされるかどうかを考えます。次に、他のボックスに対してもテストする必要があり、他のボックスと衝突する可能性があります。

お役に立てれば幸いです。


0

これは、あなたがそこに早い時間を決定しようとする必要があり、実際には最適な方法ではなく、移動に沿った第1のポイントは、パスオブジェクトまたはしようとすると、衝突が発生し、その位置(あるいは計算された時の位置)にオブジェクトを移動します移動後の貫通位置に基づいて修正することは非常に問題がありますが、現在のプロセスをわずかな変更で使用できます。衝突がなくなるまで衝突をチェックし続けるだけです。

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

これにより無限ループが発生する状況があることに注意してください(ボックスを衝突から移動すると別のコレクションが発生し、ボックスをその衝突から移動すると、以前と同じ衝突位置に戻ります)。

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