Wie berechne ich die Kollisionsantwort zwischen einer Kugel und einer Ebene?

9

Ich versuche ein einfaches 3D-Spiel zu erstellen und muss den Spieler innerhalb der Grenzen der Spielwelt einschränken. Wenn der Spieler die Seiten der Welt trifft, möchte ich, dass das Schiff des Spielers leicht abprallt.

Tatsächlich versuche ich, den Spieler in einer Kiste zu fangen und ihn daran zu hindern, durch die Seiten zu entkommen ...

Ich habe es geschafft, die Grenzen der Spielwelt als eine Sammlung von Flugzeugen mit Normalen und Entfernungen vom Ursprung zu definieren. Der Spieler hat eine sphärische Begrenzungskugel und durch das Folgen dieser Website http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php konnte ich Kollisionen erkennen.

Ich kann jetzt nicht genau herausfinden, was zu tun ist, wenn eine Kollision erkannt wird. Das Beste, was ich schaffen kann, ist, dass der Spieler im Flugzeug stecken bleibt, direkt durch das Flugzeug fliegt oder wiederholt mit einer sehr schnellen Geschwindigkeit davon abprallt.

Der gesunde Menschenverstand sagt mir, dass ich den vom Flugzeug reflektierten Winkel unter Verwendung seiner Normalen berechnen und auf die Geschwindigkeit des Spielers anwenden muss. Ich denke jedoch, ich muss zuerst sehen, ob der Spieler das Flugzeug durchlaufen hat, was das Bit ist, das ich nicht kann trainieren.

Piku
quelle

Antworten:

4

Sie müssen einen Impuls auf Ihr Objekt anwenden, der eine sofortige Änderung der Geschwindigkeit darstellt. In der realen Welt würde über einen sehr kurzen Zeitschritt eine starke Kraft auf das Objekt ausgeübt, die seine Beschleunigung umkehrt und bewirkt, dass sich seine Geschwindigkeit ändert. Da wir jedoch in einer diskreten Welt arbeiten, müssen wir ein wenig schummeln, um diesen abrupten Richtungswechsel zu simulieren. Für eine Kugel und eine Ebene ist das ziemlich einfach. Die grundlegendste Kollisionsantwort besteht darin, die Geschwindigkeit der Kugel um die Normalen der Ebene zu reflektieren. Das Ergebnis ist dann die neue Geschwindigkeit der Kugel. Pseudocode würde ungefähr so ​​aussehen:

reflected = 2 * plane.normal * (plane.normal * sphere.velocity)
sphere.velocity -= reflected

Von dort aus können Sie eine Dämpfung hinzufügen (multiplizieren Sie mit einem Koeffizienten wie 0,9), um den Energieverlust durch Wärme oder Reibung zu berücksichtigen. Wenn Sie die Winkelgeschwindigkeit einbeziehen möchten (möglicherweise dreht sich Ihre Kugel), werden die Gleichungen etwas komplizierter.

Für weitere Informationen verweise ich Sie auf Chris Heckers Artikel über starre Körperdynamik . Wenn Sie noch nie von Chris Hecker gehört haben, ist er bekannt für seine Spielphysik sowie für seine Arbeit an der prozeduralen Charaktererzeugung und Animation in Spore.

Kevintodisco
quelle
4
Dies ist im Wesentlichen der richtige Weg. Die Berechnung des Aufprallzeitpunkts (TOI) kann jedoch zu genaueren Ergebnissen führen, wenn die Frameraten schwanken oder abfallen. Wenn Sie anhand der aktuellen Geschwindigkeit wissen, wie lange der Aufprall vergangen ist, können Sie eine Aufprallzeit berechnen. Auf diese Weise können Sie die Kugel zum Zeitpunkt des Aufpralls wieder in ihre Position zurückbringen und die Geschwindigkeit von dort aus anpassen. Nachdem Sie Position und Geschwindigkeit zum Zeitpunkt des Aufpralls vom Aufprallpunkt aus angepasst haben, bewegen Sie sich entlang der neuen Geschwindigkeit um die Zeit, die Sie subtrahiert haben, um zum TOI zu gelangen.
Nic Foster
OK, das scheint meistens zu funktionieren, aber es ist ein bisschen ... seltsam. Ich denke, ich mache das möglicherweise an der falschen Stelle in meinem Code. Sollte ich alle meine Objekte durchlaufen und testen, ob sie kollidieren, bevor ich sie verschiebe (basierend darauf, wo sie sich im nächsten Frame befinden) oder sie verschieben und anschließend auf Kollisionen testen?
Piku
@Piku, nein, erkenne nicht, ob sie kollidieren werden. Wenn eine Kollision auftritt, denken Sie daran, dass die Wahrscheinlichkeit sehr hoch ist, dass sich die beiden Objekte jetzt weit über den Ort hinaus überlappen, an dem die tatsächliche Kollision aufgetreten wäre. Sie müssen im Wesentlichen herausfinden, wo die Kollision aufgetreten ist, als ob Sie eine unendliche Bildrate haben (was Sie nicht tun), und das Objekt an die Position zurückbringen, an der die Kollision ursprünglich aufgetreten wäre. Wenn Sie die Objekte nicht so trennen, reagieren Sie kontinuierlich auf dieselbe Kollision und das Objekt bleibt hängen.
Jonathan Dickinson
@Piku und dazu ermitteln wir die Zeit in der Vergangenheit, in der die Kollision aufgetreten ist (TOI / Zeitpunkt des Aufpralls genannt). Sobald wir das haben, können wir die Geschwindigkeit des Objekts verwenden, um es zurück zu bewegen ( distance = speed * timenormalerweise mit einem extra kleinen Abstand, um Fehler zu vermeiden) und dann seine Geschwindigkeit auf das Kollisionsergebnis aktualisieren.
Jonathan Dickinson
@Piku auch wir finden nicht heraus, wo wir im nächsten Frame sein werden (ich habe das noch nie persönlich gesehen), aber im Allgemeinen machen wir Kollisionserkennung und -reaktion: NACH der Berechnung der neuen Position für DIESES Frame, aber VORHER Wir wenden die neue Position für DIESEN Rahmen an.
Jonathan Dickinson
1

F = ma oder a = F / m. Berechnen Sie den Kollisionspunkt zwischen Kugel und Ebene. Dies ist normalerweise der Kugelmittelpunkt - normaler * Radius. Wenn Sie mehr Genauigkeit wünschen, berechnen Sie, wie weit die Kugel in die Ebene eingedrungen ist, und passen Sie Ihre Berechnung an. Dies ist natürlich weitgehend optional, es sei denn, Sie möchten eine wirklich genaue Physik. Berechnen Sie nun die Relativgeschwindigkeit entlang der Normalen. Für eine statische Ebene ist dies: Vball Dot N. Dann multiplizieren Sie VballDotN mit -1 und multiplizieren Sie mit Masse. In der Physik würden Sie dies zu diesem Zeitpunkt auch mit dem Restitutionskoeffizienten (Bounce-Faktor) multiplizieren. Multiplizieren Sie diesen Skalar mit N und Sie haben Ihre Kraft.

Teilen Sie beim Einstellen von Vball die Kraft erneut durch die Masse und Sie haben die endgültige Beschleunigung. Addieren Sie diese einfach zur Geschwindigkeit und Sie haben Ihre endgültige Geschwindigkeit nach der Kollision.

vec3 Vrel = Ball.getVelocity();
float vDotN = Vrel.Dot(CollisionNormal);
vec3 F = -(1.0f+Ball.getRestitution())*vDotN;
F*=Ball.getMass();
Ball.accelerate(F/Ball.getMass());

Diese Methode entspricht den Formeln der Kollisionsreaktion. Wenn Sie noch mehr Genauigkeit wünschen, sollten Sie die Reibung berücksichtigen, die dazu führt, dass sich der Ball dreht, aber ich weiß nicht, ob Sie das in Ihrem Spiel wollen. In diesem Fall berechnen Sie die Tangentialkraft folgendermaßen:

vec3 Ft = -(Ball.getvelocity()+(vDotN*CollisionNormal));
Ft*=Ball.getKineticFriction()+Wall.getKineticFriction(); //you could fudge these numbers
Ft*=Ball.getMass();
vec3 vec2Centre = Ball.getPosition()-ContactPoint;
vec3 Torque = cross(vec2Centre,Ft);
Ball.AngularAccelerate(Torque/Ball.getMomentofInertia(glm::normalize(Torque)));

Stellen Sie sicher, dass Sie Ft berechnen, bevor Sie lineare Effekte anwenden, da sonst die Reibung nicht genau ist.

Ian Young
quelle
Sollte Zeile 3 nicht sein : vec3 F = -CollisionNormal * (1.0f+Ball.getRestitution())*vDotN;?
Shital Shah
Ja, ich habe diesen Teil verpasst. Vielen Dank für den Hinweis.
Ian Young
0

Ich würde vorschlagen, zuerst die Entfernung vom Flugzeug zu berechnen. und dann, wenn der Abstand <= zum Radius die Kollisionsreaktion ausführt.

Sie können dies dann ändern, um die Entfernung zu berechnen. Wenn die Entfernung kleiner als der Radius ist (was bedeutet, dass sich das Objekt überlappt), verschieben Sie die Position der Kugeln und führen Sie dann die Kollisionsreaktion aus.

Roter Himmel
quelle