web-dev-qa-db-fra.com

collision cercle-cercle

Je vais développer un jeu de balle en 2D où deux balles (cercles) se heurtent. Maintenant, j'ai le problème de déterminer le point de collision (en fait, de déterminer s'ils entrent en collision sur l'axe des x/l'axe des y). J'ai une idée que lorsque la différence entre la coordonnée y de 2 boules est supérieure à la différence de coordonnée x, elles se heurtent sur leur axe y, sinon elles se heurtent sur leur axe x. Mon idée est-elle correcte? J'ai implémenté cette chose dans mes jeux. Normalement, cela fonctionne bien, mais parfois, cela échoue. Quelqu'un peut-il me dire si mon idée est juste? Si non, alors pourquoi, et y a-t-il un meilleur moyen?

Par collision dans l'axe des x, je veux dire le 1er, 4e, 5e ou 8e octant du cercle, l'axe y signifie le 2e, 3e, 6e ou 7e octant du cercle.

Merci d'avance!

26
russell

La collision entre les cercles est facile. Imaginez qu'il y ait deux cercles:

  • C1 avec centre (x1, y1) et rayon r1;
  • C2 avec centre (x2, y2) et rayon r2.

Imaginez qu'il y ait une ligne entre ces deux points centraux. La distance entre les points centraux et le bord de l'un ou l'autre cercle est, par définition, égale à leurs rayons respectifs. Alors:

  • si les bords des cercles se touchent, la distance entre les centres est r1 + r2;
  • toute plus grande distance et les cercles ne se touchent pas ou ne se heurtent pas; et
  • moins et ensuite se heurter.

Ainsi, vous pouvez détecter une collision si:

(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2

ce qui signifie que la distance entre les points centraux est inférieure à la somme des rayons.

Le même principe peut être appliqué à la détection de collisions entre sphères en trois dimensions.

Edit: si vous voulez calculer le point de collision, une trigonométrie de base peut le faire. Vous avez un triangle:

        (x1,y1)
        |\
        | \
        |  \ sqrt((x2-x1)^2 + (y2-y1)^2) = r1+r2
|y2-y1| |   \
        |    \
        |   X \
(x1,y2) +------+ (x2,y2)
         |x2-x1|

Les expressions |x2-x1| et |y2-y1| sont des valeurs absolues. Donc pour l'angle X:

        |y2 - y1|
sin X =  -------
         r1 + r2

        |x2 - x1|
cos X =  -------
         r1 + r2

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Une fois que vous avez l'angle, vous pouvez calculer le point d'intersection en les appliquant à un nouveau triangle:

  +
  |\
  | \
b |  \ r2
  |   \
  |  X \
  +-----+
     a

où:

        a
cos X = --
        r2

alors

a = r2 cos X

À partir des formules précédentes:

       |x2 - x1|
a = r2 -------
        r1 + r2

Une fois que vous avez a et b, vous pouvez calculer le point de collision en termes de décalage (x2, y2) de (a, b) selon le cas. Vous n'avez même pas besoin de calculer des sinus, des cosinus ou des sinus ou cosinus inverses pour cela. Ou des racines carrées d'ailleurs. Donc c'est rapide.

Mais si vous n'avez pas besoin d'un angle ou d'un point de collision exact et que vous voulez simplement l'octant, vous pouvez l'optimiser davantage en comprenant quelque chose sur les tangentes, à savoir:

  • 0 <= tan X <= 1 pour 0 <= X <= 45 degrés;
  • tan X> = 1 pour 45 <= X <= 90
  • 0> = tan X> = -1 pour 0> = X => -45;
  • tan X <= -1 pour -45> = X => -90; et
  • tan X = tan (X + 180) = tan (X-180).

Ces quatre plages de degrés correspondent à quatre octants du cercle. Les quatre autres sont décalés de 180 degrés. Comme démontré ci-dessus, la tangente peut être calculée simplement comme:

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Perdez les valeurs absolues et ce rapport vous dira dans lequel des quatre octants se trouve la collision (par les plages de tangentes ci-dessus). Pour déterminer l'octant exact, comparez simplement x1 et x2 pour déterminer lequel est le plus à gauche.

L'octant de la collision sur l'autre single est décalé (l'octant 1 sur C1 signifie l'octant 5 sur C2, 2 et 6, 3 et 7, 4 et 8, etc.).

107
cletus

Comme le dit cletus, vous voulez utiliser la somme des rayons des deux boules. Vous voulez calculer la distance totale entre les centres des boules, comme suit:

Ball 1:  center: p1=(x1,y1)  radius: r1
Ball 2:  center: p2=(x2,y2)  radius: r2

collision distance: R= r1 + r2
actual distance:    r12= sqrt( (x2-x1)^2 + (y2-y2)^2 )

Une collision se produira chaque fois que (r12 <R). Comme le dit Artelius, ils ne devraient pas entrer en collision sur les axes x/y, ils se heurtent à un angle particulier. Sauf que vous ne voulez pas vraiment de cet angle; vous voulez le vecteur de collision. Voici la différence entre les centres des deux cercles lorsqu'ils se heurtent:

collision vector: d12= (x2-x1,y2-y1) = (dx,dy)
actual distance:  r12= sqrt( dx*dx + dy*dy )

Notez que vous avez déjà calculé dx et dy ci-dessus lorsque vous calculez la distance réelle, vous pouvez donc aussi bien les suivre à des fins comme celle-ci. Vous pouvez utiliser ce vecteur de collision pour déterminer la nouvelle vitesse des balles - vous allez finir par mettre à l'échelle le vecteur de collision par certains facteurs, et l'ajouter aux anciennes vitesses ... mais, pour revenir à la collision réelle point:

collision point:  pcollision= ( (x1*r2+x2*r1)/(r1+r2), (y1*r2+y2*r1)/(r1+r2) )

Pour savoir comment trouver la nouvelle vitesse des balles (et en général pour donner plus de sens à la situation dans son ensemble), vous devriez probablement trouver un livre de physique du lycée, ou l'équivalent. Malheureusement, je ne connais pas de bon tutoriel Web - des suggestions, quelqu'un?

Oh, et si vous voulez toujours vous en tenir à l'axe x/y, je pense que vous avez raison:

if( abs(dx) > abs(dy) ) then { x-axis } else { y-axis }

Quant à savoir pourquoi cela pourrait échouer, il est difficile de le dire sans plus d'informations, mais vous pourriez avoir un problème avec vos balles se déplaçant trop vite et se passant l'une à côté de l'autre en un seul pas. Il existe des moyens de résoudre ce problème, mais le plus simple est de s'assurer qu'ils ne se déplacent pas trop vite ...

10
comingstorm

Ce site explique la physique , dérive l'algorithme , et fournit code pour les collisions de boules 2D.

Calculez l'octant après que cette fonction calcule ce qui suit: position du point de collision par rapport au centre de masse du corps a; position du point de collision par rapport au centre de masse du corps a

/**
This function calulates the velocities after a 2D collision vaf, vbf, waf and wbf from information about the colliding bodies
@param double e coefficient of restitution which depends on the nature of the two colliding materials
@param double ma total mass of body a
@param double mb total mass of body b
@param double Ia inertia for body a.
@param double Ib inertia for body b.
@param vector ra position of collision point relative to centre of mass of body a in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector rb position of collision point relative to centre of mass of body b in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector n normal to collision point, the line along which the impulse acts.
@param vector vai initial velocity of centre of mass on object a
@param vector vbi initial velocity of centre of mass on object b
@param vector wai initial angular velocity of object a
@param vector wbi initial angular velocity of object b
@param vector vaf final velocity of centre of mass on object a
@param vector vbf final velocity of centre of mass on object a
@param vector waf final angular velocity of object a
@param vector wbf final angular velocity of object b
*/
CollisionResponce(double e,double ma,double mb,matrix Ia,matrix Ib,vector ra,vector rb,vector n,
    vector vai, vector vbi, vector wai, vector wbi, vector vaf, vector vbf, vector waf, vector wbf) {
  double k=1/(ma*ma)+ 2/(ma*mb) +1/(mb*mb) - ra.x*ra.x/(ma*Ia) - rb.x*rb.x/(ma*Ib)  - ra.y*ra.y/(ma*Ia)
    - ra.y*ra.y/(mb*Ia) - ra.x*ra.x/(mb*Ia) - rb.x*rb.x/(mb*Ib) - rb.y*rb.y/(ma*Ib)
    - rb.y*rb.y/(mb*Ib) + ra.y*ra.y*rb.x*rb.x/(Ia*Ib) + ra.x*ra.x*rb.y*rb.y/(Ia*Ib) - 2*ra.x*ra.y*rb.x*rb.y/(Ia*Ib);
  double Jx = (e+1)/k * (Vai.x - Vbi.x)( 1/ma - ra.x*ra.x/Ia + 1/mb - rb.x*rb.x/Ib)
     - (e+1)/k * (Vai.y - Vbi.y) (ra.x*ra.y / Ia + rb.x*rb.y / Ib);
  double Jy = - (e+1)/k * (Vai.x - Vbi.x) (ra.x*ra.y / Ia + rb.x*rb.y / Ib)
     + (e+1)/k  * (Vai.y - Vbi.y) ( 1/ma - ra.y*ra.y/Ia + 1/mb - rb.y*rb.y/Ib);
  Vaf.x = Vai.x - Jx/Ma;
  Vaf.y = Vai.y - Jy/Ma;
  Vbf.x = Vbi.x - Jx/Mb;
  Vbf.y = Vbi.y - Jy/Mb;
  waf.x = wai.x - (Jx*ra.y - Jy*ra.x) /Ia;
  waf.y = wai.y - (Jx*ra.y - Jy*ra.x) /Ia;
  wbf.x = wbi.x - (Jx*rb.y - Jy*rb.x) /Ib;
  wbf.y = wbi.y - (Jx*rb.y - Jy*rb.x) /Ib;
}
8
Leftium

Je suis d'accord avec les réponses fournies, elles sont très bonnes.
Je veux juste vous signaler un petit écueil: si la vitesse des balles est élevée, vous pouvez simplement manquer la collision, car les cercles ne se croisent jamais pour des pas donnés.
La solution est de résoudre l'équation sur le mouvement et de trouver le moment correct de la collision.

Quoi qu'il en soit, si vous implémentiez votre solution (comparaisons sur les axes X et Y), vous obtiendrez le bon vieux ping-pong! http://en.wikipedia.org/wiki/Pong
:)

1
avp

Le point auquel ils entrent en collision est sur la ligne entre les points médians des deux cercles, et sa distance de chaque point médian est le rayon de ce cercle respectif.

1
Carl Smotricz

Pour répondre plus directement à votre question: Oui, selon les règles et les exigences que vous exposez, ces balles se heurtent sur l'axe Y si la différence entre les Y est supérieure à la différence entre les X lorsque les balles se touchent.

Si c'est ce que vous implémentez, vous obtenez une réponse correcte à la question "Collision des axes X ou Y?". Mais je pense que la raison pour laquelle vous obtenez tant de réponses que vous ne semblez pas pouvoir utiliser est que non plus

  • vous posez la mauvaise question (pas ici - dans votre programme); ou

  • vous n'utilisez pas correctement la réponse.

Je suis sûr que beaucoup d'entre nous ont programmé des programmes de balles rebondissantes, et je soupçonne qu'aucun de nous n'a essayé de modéliser des collisions basées sur des octants et des axes. Je soupçonne donc que vous avez une nouvelle approche très originale ou que vous le faites simplement mal. Par conséquent, je recommande de revenir en arrière et de vérifier votre méthode et vos hypothèses.

0
Carl Smotricz