Nota: tutto quanto segue presuppone che la superficie della palla sia priva di attrito (quindi non inizierà a girare o rimbalzare diversamente perché lo è).
Al momento della collisione, la palla toccherà l'angolo. Quando gli oggetti solidi si scontrano, una forza agirà lungo la cosiddetta superficie normale, cioè perpendicolare alla superficie nel punto di collisione.
Dal momento che è una palla, perpendicolare alla superficie è verso il centro della palla. Ok, quindi conosciamo la direzione della forza, per quanto riguarda la sua grandezza? Supponendo una collisione elastica (e che il rettangolo non può muoversi), la palla deve rimbalzare alla stessa velocità con cui ha avuto un impatto.
Sia (nDx, nDy) la velocità dopo la collisione, (oDx, oDy) la velocità prima della collisione e (x, y) la posizione della palla nel punto di collisione. Supponiamo inoltre che l'angolo con cui la palla si scontra sia a (0,0).
Esprimendo le nostre intuizioni come formule, abbiamo:
(nDx, nDy) = (oDx, oDy) + c * (x, y)
length (nDx, nDy) = length (oDx, oDy)
Che equivale a:
nDx = oDx + c * x
nDy = oDy + c * y
nDx^2 + nDy^2 = oDx^2 + oDy^2
Sostituendo le prime due equazioni nell'ultima, otteniamo:
(oDx + c * x)^2 + (oDy + c * y)^2 = oDx^2 + oDy^2
Espandersi usando il thorem binomiale
(a+b)^2 = a^2 + 2ab + b^2
rendimenti:
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
Questa equazione quadratica per c
ha due soluzioni, una delle quali è 0. Ovviamente, questa non è la soluzione a cui siamo interessati, poiché generalmente la direzione della palla cambierà a seguito della collisione. Per ottenere l'altra soluzione, dividiamo entrambi i lati per c e otteniamo:
(2 * oDx * x + 2 * oDy * y) + (x^2 + y^2) * c = 0
Questo è:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
Riassumendo, abbiamo:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
nDx = oDx + c * x
nDy = oDy + c * y
Modifica : nel codice:
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;
}
Alcune considerazioni sull'implementazione: Sebbene sia possibile approssimare (x, y) con la posizione della palla dopo la fase di simulazione, questa approssimazione cambierà l'angolo di deflessione e quindi sarà molto evidente, quindi i tuoi passaggi di simulazione devono essere molto fini (forse tali che la palla non si muove di oltre 1/20 del suo diametro per passo). Per una soluzione più accurata, è possibile calcolare il tempo in cui si verifica la collisione e suddividere quella fase di simulazione in quel momento, ovvero eseguire una fase parziale fino al punto di collisione e un'altra fase parziale per il resto della fase.
Modifica 2: calcolo del punto di impatto
Sia r il raggio, (x0, y0) la posizione e (dx, dy) la velocità della palla all'inizio della fase di simulazione. Per semplicità, supponiamo inoltre che l'angolo in questione si trovi in (0,0).
Sappiamo:
(x,y) = (x0, y0) + (dx, dy) * t
Vogliamo
length(x,y) = r
Questo è
(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
Questa è un'equazione quadratica in t. Se è discriminante
D = b^2 - 4 * a * c
è negativo, non ha soluzioni, ovvero la palla non colpirà mai l'angolo nel suo percorso attuale. Altrimenti, le sue due soluzioni sono date da
t1 = (-b - sqrt(D)) / (2 * a)
t2 = (-b + sqrt(D)) / (2 * a)
Siamo interessati al momento in cui è iniziata la collisione, che è la prima volta t1
.
Il tuo metodo diventerebbe:
// 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;