圆圈碰撞

时间:2009-11-15 05:58:17

标签: algorithm collision-detection

我打算开发一个两维球(圆圈)相撞的二维球类游戏。现在我有确定碰撞点的问题(事实上,确定它们是否在x轴/ y轴上碰撞)。我知道当2个球的y坐标之间的差异大于x坐标差异时,它们会在y轴上发生碰撞,否则它们会在x轴上发生碰撞。我的想法是否正确?我在游戏中实现了这个功能。通常它运作良好,但有时,它失败了。谁能告诉我我的想法是否正确?如果没有,那么为什么,并且有更好的方法吗?

通过x轴的碰撞,我的意思是圆的第1,第4,第5或第8个八分圆,y轴表示圆的第2,第3,第6或第7个八分圆。

提前致谢!

6 个答案:

答案 0 :(得分:104)

圆圈之间的碰撞很容易。想象一下有两个圆圈:

  • C1,中心(x1,y1)和半径r1;
  • C2,中心(x2,y2)和半径r2。

想象一下,在这两个中心点之间有一条线。根据定义,从中心点到任一圆的边缘的距离等于它们各自的半径。所以:

  • 如果圆的边缘接触,则中心之间的距离为r1 + r2;
  • 任何更大的距离,圆圈不接触或碰撞;和
  • 任何少,然后碰撞。

所以你可以检测碰撞:

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

表示中心点之间的距离小于半径之和。

同样的原理可用于检测三维球体之间的碰撞。

编辑:如果你想计算碰撞点,一些基本的三角学可以做到这一点。你有一个三角形:

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

表达式|x2-x1||y2-y1|是绝对值。所以对于角度X:

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

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

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

获得角度后,您可以通过将它们应用于新三角形来计算交点:

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

其中:

        a
cos X = --
        r2

所以

a = r2 cos X

从以前的公式:

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

一旦你有a和b,就可以根据(x2,y2)偏移量计算碰撞点(a,b)。你甚至不需要为此计算任何正弦,余弦或反正弦或余弦。或者任何平方根。所以它很快。

但是如果你不需要精确的角度或碰撞点而只想要八分圆,你可以通过了解切线的内容来进一步优化,这是:

  • 0&lt; = tan X&lt; = 1,0 <= X <= 45度;
  • tan X> = 1,45 <= X <= 90
  • 0&gt; = tan X&gt; = -1,0> = X =&gt; -45;
  • tan X&lt; = -1,-45&gt; = X =&gt; -90;和
  • tan X = tan(X + 180)= tan(X-180)。

这四度范围对应于cirlce的四个八分圆。其他四个偏移180度。如上所述,切线可以简单地计算为:

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

丢失绝对值,此比率将告诉您碰撞中的四个八分圆中的哪一个(通过上述切线​​范围)。要计算出确切的八分圆,只需比较x1和x2,以确定哪个是最左边的。

另一个单方面碰撞的八分圆是偏移的(C1上的八分圆1表示C2上的八分圆5,2和6,3和7,4和8等)。

答案 1 :(得分:10)

正如克莱图斯所说,你想要使用两个球的半径之和。您想要计算球中心之间的总距离,如下所示:

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 )

每当(r12

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

请注意,在计算实际距离时,您已经计算了上面的dx和dy,因此您可能会出于这样的目的跟踪它们。您可以使用此碰撞向量来确定球的新速度 - 您将最终通过某些因素缩放碰撞向量,并将其添加到旧速度......但是,要回到实际的碰撞点:

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

要弄清楚如何找到球的新速度(并且通常在整个情况下更有意义),你应该找到一本高中物理书或同等学历。不幸的是,我不知道一个好的网络教程 - 建议,任何人?

哦,如果仍然想要坚持使用x / y轴的东西,我认为你已经做到了:

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

至于它可能失败的原因,没有更多的信息很难说,但是你的球可能会移动太快,并且在一个时间步中彼此正确地传递。有办法解决这个问题,但最简单的方法是确保它们不会移动得太快......

答案 2 :(得分:6)

此网站explains the physicsderives the algorithm,并提供code for collisions个2D球。

在此函数计算以下函数后计算八分圆:碰撞点相对于主体a的质心的位置;碰撞点相对于身体质心的位置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;
}

答案 3 :(得分:1)

它们碰撞的点位于两个圆的中点之间的线上,它与任一中点的距离是相应圆的半径。

答案 4 :(得分:1)

我同意提供的答案,他们非常好 我只是想指出一个小陷阱:如果球的速度很高,你可以错过碰撞,因为圆圈从不相交给定的步骤。
解决方案是解决运动方程并找到正确的碰撞时刻。

无论如何,如果你要实施你的解决方案(在X轴和Y轴上进行比较),你就会得到很好的乒乓球! http://en.wikipedia.org/wiki/Pong
:)

答案 5 :(得分:0)

更直接地回答你的问题:是的,根据你规定的规则和要求,如果Y的差异大于球触碰时X的差异,那些球会在Y轴上碰撞。

如果这是你正在实施的,那么你得到的问题是“X或Y轴碰撞?”的正确答案。但我认为你在这里获得如此多的答案,你似乎无法使用的原因是

  • 你问的是错误的问题(不在这里 - 在你的程序中);或

  • 您没有正确使用答案。

我相信我们很多人已经设定了弹跳球程序,我怀疑我们都没有尝试过基于八度和轴的碰撞模型。所以我怀疑你要么有一个非常原创的新方法,要么就是你做错了。因此,我建议回去检查你的方法和假设。