Kollisionsrechteckantwort

10

Ich habe Schwierigkeiten, ein bewegliches Rechteck dazu zu bringen, mit mehr als einem Rechteck zu kollidieren.

Ich verwende SFML und es hat eine praktische Funktion namens, intersectsdie 2 Rechtecke nimmt und die Schnittpunkte zurückgibt. Ich habe einen Vektor voller Rechtecke, mit dem mein bewegliches Rechteck kollidieren soll. Ich durchlaufe dies mit dem folgenden Code (p ist das bewegliche Rechteck).

IsCollidingWithGibt einen Bool zurück, verwendet aber auch SFMLs intersects, um die Schnittpunkte zu ermitteln.

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

und der eigentliche Collide()Code:

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 );
    }

}

und der IsCollidingWith()Code ist:

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

Dies funktioniert gut, wenn nur 1 Rectin der Szene ist. Wenn es jedoch mehr als eine gibt Rect, verursacht dies ein Problem, wenn zwei Kollisionen gleichzeitig berechnet werden.

Irgendeine Idee, wie man damit richtig umgeht? Ich habe ein Video auf YouTube hochgeladen , um mein Problem zu zeigen. Die Konsole ganz rechts zeigt die Breite und Höhe der Kreuzungen. Sie können auf der Konsole sehen, dass versucht wird, 2 Kollisionen gleichzeitig zu berechnen. Ich denke, hier wird das Problem verursacht.

Schließlich scheint das Bild unten mein Problem gut zu veranschaulichen:

Rechteck kollidiert mit mehreren anderen Rechtecken

dotty
quelle
Die Videoverbindung ist unterbrochen.
XiaoChuan Yu
Werden die zurückgegebenen colliderObjekte von this->getCollider()aktualisiert this->move()?
XiaoChuan Yu
Könnten Sie bitte weitere Informationen hinzufügen? Was genau ist das Problem? Das YouTube-Video scheint vorhersehbares Verhalten zu zeigen, und es gibt nur ein weiteres Rechteck in der Szene.
Wackidev

Antworten:

3

Ihr Bild zeigt eines der vielen Probleme beim Versuch, mit konvexen Formen - insbesondere Rechtecken - eine flache Oberfläche wie einen Boden zu simulieren. Der Algorithmus führt dazu, dass Zeichen an den Innenkanten der Formen, aus denen der Boden besteht, hängen bleiben.

Eine einfache Lösung besteht darin, nur auf vertikale Kollision zu prüfen, diese zu korrigieren und dann erneut auf horizontale Kollision zu prüfen. Es sei denn, Sie fallen und versuchen, eine Wand herunterzurutschen. In diesem Fall möchten Sie zuerst nach horizontalen Kollisionen suchen. Woher wissen Sie, wann Sie welche zuerst überprüfen müssen? Sie können dies basierend darauf tun, welche Komponente Ihrer Geschwindigkeit größer ist (wenn die horizontale Bewegung größer ist, überprüfen Sie zuerst die vertikalen Kollisionen, andernfalls die horizontalen Kollisionen).

Was noch einfacher und leistungsfähiger sein kann, ist stattdessen eine Liste von Kanten für Ihre Welt zu erstellen. Das heißt, setzen Sie für Ihre Boxen, aus denen der Boden besteht, eine Flagge, die angibt, dass nur die Oberkante tatsächlich kollidierbar ist, und ignorieren Sie dann Kollisionen mit den anderen Kanten. Sie werden nicht in der Lage sein, die Kollisionsroutine von SFML dafür zu verwenden, aber ehrlich gesagt ist einfach Boxkollisionen möglicherweise der einfachste Code, den Sie jemals in einem Spiel schreiben werden. Diese Technik funktioniert besonders gut, wenn Ihre Welt an einem Gitter ausgerichtet ist. Ich würde mir die hervorragenden Metanet-Tutorials (http://www.metanetsoftware.com/technique.html/) für diese Technik ansehen.

Sie werden auf viele andere Probleme stoßen, wenn Sie versuchen, ein einfaches 2D-Plattformspiel wie Sie zu erstellen. Die mit Abstand beste Ressource, die ich dafür gesehen habe, ist die folgende, die Sie lesen und dann erneut lesen sollten:

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

Sean Middleditch
quelle
1

Vielleicht wäre eine einfache Lösung, mit jedem Rechteck nach Kollisionen zu suchen und sich in die entgegengesetzte Bewegungsrichtung zurückzuziehen, bis keine Kollisionen mehr erkannt werden. Wenn dies das Problem löst, sollte auch die Implementierung recht einfach sein.

Arex
quelle
+1, ich habe tatsächlich hier darüber geschrieben: gamedev.stackexchange.com/questions/38252/…
Markus von Broady
0

Ich denke nicht, dass die Berechnung von 2 Kollisionen ein Problem ist, sondern nur ein Leistungsproblem. Damit die Kollision korrekt gehandhabt werden kann, muss sie möglicherweise zweimal getestet werden. Wenn Sie Ihr Diagramm verwenden, denken Sie, wenn A zuerst gegen B getestet wird, muss es auch gegen die anderen Boxen getestet werden und kann durchaus mit einem anderen kollidieren.

Hoffe das ist hilfreich?

james82345
quelle
0

Das ist nicht wirklich eine optimale Methode, sollten Sie es frühesten Zeitpunkt zu bestimmen versuchen , wenn oder der erste Punkt entlang der Bewegungsbahn - Objekte , wo Kollisionen auftreten und die Objekte in diese Position (oder die Position , in der berechneten Zeit) bewegen, versuchen, Richtig basierend auf den Penetrationspositionen nach der Bewegung ist sehr problematisch, aber Sie können Ihren aktuellen Prozess mit einer kleinen Änderung verwenden. Suchen Sie einfach weiter nach Kollisionen, bis keine mehr vorhanden sind.

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]);
      }
   }
}

Beachten Sie, dass es Situationen gibt, in denen dies zu einer Endlosschleife führt (stellen Sie sich eine Situation vor, in der das Verschieben der Box aus einer Kollision zu einer anderen Sammlung führt und das Verschieben der Box aus dieser Kollision sie wieder in dieselbe Kollisionsposition wie zuvor bringt).

Matthew R.
quelle