Je développe actuellement un clone de cassure et j'ai réussi à bloquer la détection de collision entre une balle (cercle) et une brique (polygone convexe) qui fonctionne correctement. J'utilise un test de détection de collision Circle-Line où chaque ligne représente et arête sur la brique polygone convexe.
La plupart du temps, le test Circle-Line fonctionne correctement et les points de collision sont résolus correctement.
La détection de collision fonctionne correctement.
Cependant, parfois, mon code de détection de collision retourne faux en raison d'un discriminant négatif lorsque la balle intersecte réellement la brique.
Échec de la détection de collision.
Je suis conscient de l'inefficacité de cette méthode et j'utilise des boîtes englobantes alignées sur l'axe pour réduire le nombre de briques testées. Ma principale préoccupation est s'il y a des bugs mathématiques dans mon code ci-dessous.
/*
* from and to are points at the start and end of the convex polygons edge.
* This function is called for every edge in the convex polygon until a
* collision is detected.
*/
bool circleLineCollision(Vec2f from, Vec2f to)
{
Vec2f lFrom, lTo, lLine;
Vec2f line, normal;
Vec2f intersectPt1, intersectPt2;
float a, b, c, disc, sqrt_disc, u, v, nn, vn;
bool one = false, two = false;
// set line vectors
lFrom = from - ball.circle.centre; // localised
lTo = to - ball.circle.centre; // localised
lLine = lFrom - lTo; // localised
line = from - to;
// calculate a, b & c values
a = lLine.dot(lLine);
b = 2 * (lLine.dot(lFrom));
c = (lFrom.dot(lFrom)) - (ball.circle.radius * ball.circle.radius);
// discriminant
disc = (b * b) - (4 * a * c);
if (disc < 0.0f)
{
// no intersections
return false;
}
else if (disc == 0.0f)
{
// one intersection
u = -b / (2 * a);
intersectPt1 = from + (lLine.scale(u));
one = pointOnLine(intersectPt1, from, to);
if (!one)
return false;
return true;
}
else
{
// two intersections
sqrt_disc = sqrt(disc);
u = (-b + sqrt_disc) / (2 * a);
v = (-b - sqrt_disc) / (2 * a);
intersectPt1 = from + (lLine.scale(u));
intersectPt2 = from + (lLine.scale(v));
one = pointOnLine(intersectPt1, from, to);
two = pointOnLine(intersectPt2, from, to);
if (!one && !two)
return false;
return true;
}
}
bool pointOnLine(Vec2f p, Vec2f from, Vec2f to)
{
if (p.x >= min(from.x, to.x) && p.x <= max(from.x, to.x) &&
p.y >= min(from.y, to.y) && p.y <= max(from.y, to.y))
return true;
return false;
}
la source
sqrt_disc = sqrt(disc);
. Merci beaucoup pour votre réponse ci-dessous, cela m'a beaucoup aidé.Réponses:
Le segment allant de A à B peut être calculé comme
P (t) = A + D · t où D est B - A et t va de 0 à 1
Maintenant, le cercle est centré sur l'origine (déplacez A et B si nécessaire pour mettre le centre à l'origine) et a un rayon r .
Vous avez une intersection si pour certains t vous obtenez que le P a la même longueur de r ou, de manière équivalente, que la longueur de P au carré est équivalente à r²
La longueur au carré d'un vecteur est obtenue en faisant le produit scalaire d'un vecteur par lui-même (c'est si vrai que si l'on trouve une opération appropriée pour le produit scalaire, il peut définir un nouveau concept cohérent de longueur)
P · P = ( A + D · t) · ( A + D · t) =
A · A + 2 A · D t + D · D t²
On veut trouver pour quel t on obtient P · P = r² donc on finit par se demander quand
A · A + 2 A · D t + D · D t² = r²
ou lorsque
D · D t² + 2 A · D t + A · A -r² = 0
c'est la très célèbre équation quadratique
at² + bt + c = 0
avec
a = D · D ; b = 2 A · D et c = A · A -r²
Nous devons vérifier si le déterminant b² - 4ac est positif et nous trouvons donc 2 valeurs de t qui nous donnent les points d'intersections P (t).
t doit être compris entre 0 et 1 sinon nous avons trouvé des solutions qui se situent sur la droite passant par A et B mais qui sont avant A ou après B
[ÉDITER]
Étant donné que d'autres questions peuvent trouver une aide à cette réponse, j'ai décidé d'essayer de simplifier le raisonnement dans cette modification en utilisant quelques images. Ceci est la condition de départ. Maintenant, concentrez-vous sur le segment A_B
D est le vecteur qui déplace A dans B donc si t est compris entre 0 et 1, D · t est une "fraction propre" de D donc le point A + D · t se situe dans le segment A_B : les points bruns viennent quand t est entre 0 et 1 et le vert foncé est lorsque t> 1.
Maintenant, nous pouvons simplifier les choses si nous déplaçons le centre du cercle dans l'origine. Cela peut toujours être fait car il s'agit simplement d'un changement de système de coordonnées qui préserve la géométrie, les angles, l'intersection, les mesures, etc.
Nous avons maintenant un moyen simple de calculer la longueur de P lorsque t varie et de dire pour laquelle t P franchit les limites du cercle.
Comme vous le voyez, P ' est de longueur supérieure à r tandis que P " est inférieur à r. Puisque la longueur du vecteur et r sont des nombres positifs, la relation d'ordre supérieur ou inférieur à ce qui est conservé est que nous calculons la relation entre les longueurs carré et le rayon carré. P * 1 et P * 2 sont le point qui rend le | P | ² égal à r²
Comme mentionné dans la section de pré-édition, nous arrivons à obtenir une équation quadratique où t est notre variable. Comme on le sait, les valeurs de solution de t vont du cas où t est un couple de nombres complexes - cela signifie pas d'intersection; le cas où t sont deux solutions égales - cela signifie qu'il y a une intersection; le cas où il y a deux solutions distinctes - cela signifie qu'il y a deux intersections.
Le discriminant est utilisé pour discriminer la condition précédente et un test de validité est effectué sur t pour voir s'il s'agit d'une intersection valide mais en dehors de notre segment - c'est-à-dire que la solution t doit être réelle et entre 0 et 1 pour être considérée comme une intersection appropriée qui tombe dans le segment A_B
la source