Hinweis: In allen folgenden Fällen wird davon ausgegangen, dass die Oberfläche des Balls reibungsfrei ist (sodass er sich nicht anders dreht oder abprallt).
Im Moment der Kollision berührt der Ball die Ecke. Wenn feste Objekte kollidieren, wirkt eine Kraft entlang der sogenannten Oberflächennormalen, dh senkrecht zur Oberfläche am Kollisionspunkt.
Da es sich um eine Kugel handelt, ist sie senkrecht zur Oberfläche zur Ballmitte gerichtet. Ok, wir kennen also die Richtung der Kraft, wie ist es mit ihrer Größe? Unter der Annahme einer elastischen Kollision (und dass sich das Rechteck nicht bewegen kann) muss der Ball mit der gleichen Geschwindigkeit zurückprallen, mit der er getroffen wurde.
Sei (nDx, nDy) die Geschwindigkeit nach der Kollision, (oDx, oDy) die Geschwindigkeit vor der Kollision und (x, y) die Position des Balls am Kollisionspunkt. Nehmen wir weiter an, dass die Ecke, mit der der Ball kollidiert, bei (0,0) liegt.
Indem wir unsere Erkenntnisse als Formeln ausdrücken, haben wir:
(nDx, nDy) = (oDx, oDy) + c * (x, y)
length (nDx, nDy) = length (oDx, oDy)
Welches ist gleichbedeutend mit:
nDx = oDx + c * x
nDy = oDy + c * y
nDx^2 + nDy^2 = oDx^2 + oDy^2
Wenn wir die ersten beiden Gleichungen in die letzte einsetzen, erhalten wir:
(oDx + c * x)^2 + (oDy + c * y)^2 = oDx^2 + oDy^2
Expandieren mit dem Binomial-Thorem
(a+b)^2 = a^2 + 2ab + b^2
ergibt:
oDx^2 + 2 * oDx * c * x + (c * x) ^ 2 + oDy^2 + 2 * oDy * c * y + (c * y) ^ 2 = oDx^2 + oDy^2
2 * oDx * c * x + 2 * oDy * c * y + (c * x) ^ 2 + (c * y) ^ 2 = 0
(2 * oDx * x + 2 * oDy * y) * c + (x^2 + y^2) * c^2 = 0
Diese quadratische Gleichung für c
hat zwei Lösungen, von denen eine 0 ist. Offensichtlich ist dies nicht die Lösung, an der wir interessiert sind, da sich die Richtung des Balls im Allgemeinen infolge der Kollision ändert. Um die andere Lösung zu erhalten, teilen wir beide Seiten durch c und erhalten:
(2 * oDx * x + 2 * oDy * y) + (x^2 + y^2) * c = 0
Das ist:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
Zusammenfassend haben wir:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
nDx = oDx + c * x
nDy = oDy + c * y
Bearbeiten : Im Code:
if (collision) {
float x = ballX - cornerX;
float y = ballY - cornerY;
float c = -2 * (ballDx * x + ballDy * y) / (x * x + y * y);
ballDx = ballDx + c * x;
ballDy = ballDy + c * y;
}
Einige Überlegungen zur Implementierung: Während Sie nach dem Simulationsschritt die Position des Balls (x, y) approximieren können, ändert diese Approximierung den Ablenkungswinkel und ist daher sehr auffällig. Daher müssen Ihre Simulationsschritte sehr fein sein (möglicherweise so, dass Der Ball bewegt sich nicht mehr als 1/20 seines Durchmessers pro Schritt. Für eine genauere Lösung können Sie den Zeitpunkt der Kollision berechnen und diesen Simulationsschritt zu diesem Zeitpunkt aufteilen, dh einen Teilschritt bis zum Kollisionspunkt und einen weiteren Teilschritt für den Rest des Schritts.
Bearbeiten 2: Berechnen des Aufprallpunkts
Sei r der Radius, (x0, y0) die Position und (dx, dy) die Geschwindigkeit des Balls zu Beginn des Simulationsschritts. Nehmen wir der Einfachheit halber an, dass sich die betreffende Ecke bei (0,0) befindet.
Wir wissen:
(x,y) = (x0, y0) + (dx, dy) * t
Wir wollen
length(x,y) = r
Das ist
(x0 + dx * t) ^ 2 + (y0 + dy * t) ^ 2 = r^2
x0^2 + 2 * x0 * dx * t + dx^2 * t^2 + y0^2 + 2 * y0 * dy * t + dy^2 * t^2 = r ^ 2
(dx^2 + dy^2) * t^2 + (2 * x0 * dx + 2 * y0 * dy) * t + (x0^2 + y0^2 - r^2) = 0
\____ _____/ \____________ ___________/ \_______ ________/
\/ \/ \/
a b c
Das ist eine quadratische Gleichung in t. Wenn es diskriminierend ist
D = b^2 - 4 * a * c
ist negativ, es gibt keine Lösungen, dh der Ball wird auf seinem gegenwärtigen Kurs niemals die Ecke treffen. Ansonsten sind seine beiden Lösungen gegeben durch
t1 = (-b - sqrt(D)) / (2 * a)
t2 = (-b + sqrt(D)) / (2 * a)
Wir interessieren uns für die Zeit, zu der die Kollision begann, also für die frühere Zeit t1
.
Ihre Methode würde werden:
// compute a,b,c and D as given above
if (D >= 0) {
t = (-b - sqrt(D)) / (2 * a);
if (0 < t && t <= ts) {
// collision during this timestep!
x = x + t * dx;
y = y + t * dy;
ts = ts - t;
// change dx and dy using the deflection formula
}
}
x = x + ts * dx;
y = y + ts * dy;