Remarque: Tout ce qui suit suppose que la surface de la balle est sans frottement (elle ne commencera donc pas à tourner ou à rebondir différemment car elle l’est).
Au moment de la collision, le ballon touchera le coin. Lorsque des objets solides entrent en collision, une force agit le long de la dite surface normale, c'est-à-dire perpendiculairement à la surface au point de collision.
Comme c'est une balle, la surface est perpendiculaire au centre de la balle. Ok, donc nous connaissons la direction de la force, qu’en est-il de sa magnitude? En supposant une collision élastique (et que le rectangle ne puisse pas bouger), la balle doit rebondir à la même vitesse que celle avec laquelle elle est impactée.
Soit (nDx, nDy) la vitesse après la collision, (oDx, oDy) la vitesse avant la collision et (x, y) la position de la balle au point de la collision. Supposons en outre que le coin avec lequel la balle entre en collision est à (0,0).
Exprimant nos idées sous forme de formules, nous avons:
(nDx, nDy) = (oDx, oDy) + c * (x, y)
length (nDx, nDy) = length (oDx, oDy)
Ce qui équivaut à:
nDx = oDx + c * x
nDy = oDy + c * y
nDx^2 + nDy^2 = oDx^2 + oDy^2
En substituant les deux premières équations de la dernière, on obtient:
(oDx + c * x)^2 + (oDy + c * y)^2 = oDx^2 + oDy^2
Développer en utilisant le thorem binomial
(a+b)^2 = a^2 + 2ab + b^2
rendements:
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
Cette équation quadratique pour c
a deux solutions, dont l'une est 0. Évidemment, ce n'est pas la solution qui nous intéresse, car généralement la direction de la balle changera à la suite de la collision. Pour obtenir l'autre solution, nous divisons les deux côtés par c et obtenons:
(2 * oDx * x + 2 * oDy * y) + (x^2 + y^2) * c = 0
C'est:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
Pour résumer, nous avons:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
nDx = oDx + c * x
nDy = oDy + c * y
Edit : En 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;
}
Quelques considérations d’implémentation: Bien que vous puissiez approximer (x, y) la position de la balle après l’étape de simulation, cette approximation modifiera l’angle de déviation et sera donc très visible. Par conséquent, vos étapes de simulation doivent être très fines la balle ne bouge pas de plus de 1/20 de son diamètre par pas). Pour une solution plus précise, vous pouvez calculer l'heure à laquelle la collision se produit et scinder cette étape de simulation à ce moment, c'est-à-dire effectuer une étape partielle jusqu'au point de la collision et une autre étape partielle pour le reste de l'étape.
Edit 2: Calculer le point d'impact
Soit r le rayon, (x0, y0) la position et (dx, dy) la vitesse de la balle au début de l’étape de simulation. Par souci de simplicité, supposons en outre que le coin en question se situe à (0,0).
Nous savons:
(x,y) = (x0, y0) + (dx, dy) * t
Nous voulons
length(x,y) = r
C'est
(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
C'est une équation quadratique en t. Si c'est discriminant
D = b^2 - 4 * a * c
est négatif, il n’a pas de solution, c’est-à-dire que la balle ne frappe jamais le coin sur son parcours actuel. Sinon, ses deux solutions sont données par
t1 = (-b - sqrt(D)) / (2 * a)
t2 = (-b + sqrt(D)) / (2 * a)
Nous sommes intéressés par l'heure à laquelle la collision a commencé, c'est-à-dire l'heure la plus ancienne t1
.
Votre méthode deviendrait:
// 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;