Archiv verlassen und diese Seite im Standarddesign anzeigen : Kollision zweier Kreise
burning ugly
18.11.2011, 21:39
Hey Leute,
Ich hab vor einiger Zeit begonnen kleinere 2D-Spiele mit C++ zu schreiben. Nun versuch ich mich als Übung an einem Pong.
Damit das Spiel spannender wird sollen aber 2 Kugeln gleichzeitig im Spiel sein. Nun sitz ich aber grade fest und komm nicht weiter.
Das Problem ist die Kollision der beiden Kugeln.
Die Abfrage, ob sie kollidieren ist kein Problem:
a = Abstand zwischen den beiden Kreismittelpunkten
r1, r2 = Radien der Beiden Kuglen
if (r1 + r2 <= a) { ... }
Das Problem ist nun folgendes: In welche Richtung prallen die Kugeln voneinader ab?
Anmerkung: Das Pong an sich habe ich schon fertig programmiert, es geht mir jetzt "nur" darum eine zweite Kugel ins Spiel zu bringen.
Die Klasse, welche ich für die Kugel benutze, enthält folgendes:
double x, y (--> Position des Mittelpunktes)
double r (--> Radius)
double vx, vy (--> Geschwindigkeitsvektor)
Danke schon mal im voraus §wink
Das ganze ist ein sog. elastischer Stoß (http://de.wikipedia.org/wiki/Elastischer_Sto%C3%9F), es gilt der Impulserhaltungssatz: p = m * v (fett gedruckt steht für Vektor).
Im Prinzip reichen die Formeln, die dort zum eindimensionalen Stoß zu finden sind, du musst die beiden Bewegungsvektoren lediglich in zwei Komponenten zerlegen: parallel zur Stoßnormalen (Gerade durch die beiden Kreismittelpunkte) und senkrecht zu ihr und mit diesen Komponenten jeweils diese Berechnung ausführen.
Die Zerlegung erreichst du durch eine Projektion der Bewegungsvektoren auf die Stoßnormale und die Berührungsebene.
Also ich würde dafür ja gleich ne Physik-Engine (http://de.wikipedia.org/wiki/Physik-Engine) nehmen.
Also das halte ich ja für ganz schönen Overkill. So, also ob man nicht nur mit Kanonen sondern Atombomben auf Spatzen schießt :D
Die Berechnungen ansich sind simpel, wenn man sich da ein bisschen reinarbeitet ist das nicht wirklich schwer umzusetzen :)
Satans Krümelmonster
18.11.2011, 22:59
die steigung der kollisionsgeraden ist definiert durch
α = atan((x1-x2)/(y2-y1))
wobei der punkt (x1,y1) der mittelpunkt des einen kreises und (x2,y2) der mittelpunkt des anderen kreises ist.
an dieser geraden musst du dann die geschwindigkeiten spiegeln.
die neuen geschwindigkeitskomponenten lassen sich (laut wikipedia (http://de.wikipedia.org/wiki/Spiegelungsmatrix)) wie folgt ausrechnen:
vx' = vx cos(2 α) + vy sin(2 α)
vy' = vx sin(2 α) - vy cos(2 α)
burning ugly
19.11.2011, 13:07
Hab jetzt mal alles soweit wie möglich programmiert und es funktioniert auch.
if ( sqrt( (Ball[0].x-Ball[1].x)*(Ball[0].x-Ball[1].x) + (Ball[0].y-Ball[1].y)*(Ball[0].y-Ball[1].y) ) <= (Ball[0].r + Ball[1].r) )
{
double a = atan( (Ball[0].x - Ball[1].x) / (Ball[0].y - Ball[1].y) );
for (int i = 0; i < 2; ++i)
{
Ball[i].vx = Ball[i].vx * cos(2*a) + Ball[i].vy * sin(2*a);
Ball[i].vy = Ball[i].vx * sin(2*a) + Ball[i].vy * cos(2*a);
}
}
Nur manchmal sind die Geschwindigkeiten nach der Kollision viel zu hoch, oder die Kugeln überlappen sich und bleiben dabei stehen §kratz
http://upload.worldofplayers.de/files7/CRMipong.png http://upload.worldofplayers.de/files7/pong2.png
(Zum Vergleich: die Startgeschw. beträgt ca. 5)
Was kann ich dagegen tun?
Es sieht so aus, als ob die Kollision zu spät bemerkt wird (auf dem ersten Bild überlappen sich die Bälle ja sehr stark), ggf. solltest du nicht erst bei der tatsächlichen Überschneidung der Kreise von einer Kollision ausgehen sondern schon kurz davor.
burning ugly
19.11.2011, 13:26
Das war wohl das Problem. Jetzt scheints zu funktionieren.
Danke für die schnelle Hilfe :gratz
Noch eine kleine Sachen bzgl. Programmierstil:
Da du für die Kreise ja ohnehin eine Klasse verwendest und kein Struct, solltest du so Sachen wie die Berechnungs des Abstands zwischen zwei Kreisen auch als Methode implementieren, das ist a) übersichtlicher und b) kapselst du damit alle zusammengehörigen Daten und Operationen in der Klasse, wie es in der OOP ja auch gedacht ist :)
Satans Krümelmonster
19.11.2011, 13:32
du solltest meine formeln mal richtig abschreiben. :D
beim winkel hast du im zähler erst eins, dann zwei und im nenner erst zwei und dann eins.
und bei der geschwindigkeit vy hast du vor dem cosinus ein minus.
burning ugly
19.11.2011, 13:46
Wäre auch zu schön gewesen, wenn ichs gleich beim ersten Mal grade richtig gemacht hätte :D
Danke für den Hinweis ;)
@dc2: Danke, werd ich machen. Hab eh vor den ganzen Code einmal richtig gut aufzuräumen :)
Headcool
23.11.2011, 10:26
Bezüglich physikalische Berechnungen, wie es eben Kollisionsberechnungen sind, sollte gesagt werden, dass diese meistens öfter als grafische Dinge berechnet werden müssen. Ich würde alle 1/120-Sekunden die Kollisionsberechnung durchführen. Kommt allerdings auch auf die maximale Geschwindigkeit an. Könntest ja mal ein Video aufnehmen und Frame per Frame durschauen ob es zu kleinen Überlappungen kommt.
Powered by vBulletin® Version 4.2.2 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.