圆与圆的碰撞

发布于 2024-08-11 01:37:17 字数 293 浏览 2 评论 0原文

我将开发一个二维球类游戏,其中两个球(圆圈)碰撞。现在我遇到了确定碰撞点的问题(实际上是确定它们是否在 x 轴/y 轴上碰撞)。我有一个想法,当两个球的 y 坐标之差大于 x 坐标差时,它们会在 y 轴上发生碰撞,否则,它们会在 x 轴上发生碰撞。我的想法正确吗?我在我的游戏中实现了这个东西。通常情况下它运行良好,但有时会失败。谁能告诉我我的想法是否正确?如果没有,那为什么,还有什么更好的方法吗?

x 轴上的碰撞是指圆的第 1、第 4、第 5 或第 8 个八分圆,y 轴是指圆的第 2、第 3、第 6 或第 7 个八分圆。

提前致谢!

I am going to develop a 2-d ball game where two balls (circles) collide. Now I have the problem with determining the colliding point (in fact, determining whether they are colliding in x-axis/y-axis). I have an idea that when the difference between the y coordinate of 2 balls is greater than the x coordinate difference then they collide in their y axis, otherwise, they collide in their x axis. Is my idea correct? I implemented this thing in my games. Normally it works well, but sometimes, it fails. Can anyone tell me whether my idea is right? If not, then why, and is any better way?

By collision in the x axis, I mean the circle's 1st, 4th, 5th, or 8th octant, y axis means the circle's 2nd, 3rd, 6th, or 7th octant.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

扭转时空 2024-08-18 01:37:18

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

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-y1)^2 )

只要 (r12 < R),就会发生碰撞。正如 Artelius 所说,它们实际上不应该在 x/y 轴上碰撞,而是以特定角度碰撞。不过,你实际上并不想要那个角度;你想要碰撞向量。这是两个圆碰撞时中心之间的差异:

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 }

至于为什么它可能会失败,没有更多信息很难说,但你的球可能有问题移动得太快,在一个时间步内就擦肩而过。有很多方法可以解决这个问题,但最简单的方法是确保它们不会移动得太快......

As cletus says, you want to use the sum of the radii of the two balls. You want to compute the total distance between the centers of the balls, as follows:

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-y1)^2 )

A collision will happen whenever (r12 < R). As Artelius says, they shouldn't actually collide on the x/y axes, they collide at a particular angle. Except, you don't actually want that angle; you want the collision vector. This is the difference between the centers of the two circles when they collide:

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

Note that you have already computed dx and dy above when figuring the actual distance, so you might as well keep track of them for purposes like this. You can use this collision vector for determining the new velocity of the balls -- you're going to end up scaling the collision vector by some factors, and adding that to the old velocities... but, to get back to the actual collision point:

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

To figure out how to find the new velocity of the balls (and in general to make more sense out of the whole situation), you should probably find a high school physics book, or the equivalent. Unfortunately, I don't know of a good web tutorial -- suggestions, anyone?

Oh, and if still want to stick with the x/y axis thing, I think you've got it right with:

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

As for why it might fail, it's hard to tell without more information, but you might have a problem with your balls moving too fast, and passing right by each other in a single timestep. There are ways to fix this problem, but the simplest way is to make sure they don't move too fast...

狠疯拽 2024-08-18 01:37:18

这个网站解释了物理学推导算法,并提供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;
}

This site explains the physics, derives the algorithm, and provides code for collisions of 2D balls.

Calculate the octant after this function calculates the following: position of collision point relative to centre of mass of body a; position of collision point relative to centre of mass of body 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;
}
盗梦空间 2024-08-18 01:37:18

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

不管怎样,如果你能实现你的解决方案(X 轴和 Y 轴上的比较),你就会得到很好的老式乒乓球! http://en.wikipedia.org/wiki/Pong
:)

I agree with provided answers, they are very good.
I just want to point you a small pitfall: if the speed of balls is high, you can just miss the collision, because circles never intersect for given steps.
The solution is to solve the equation on the movement and to find the correct moment of the collision.

Anyway, if you would implement your solution (comparisons on X and Y axes) you'd get the good old ping pong! http://en.wikipedia.org/wiki/Pong
:)

山色无中 2024-08-18 01:37:18

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

The point at which they collide is on the line between the midpoints of the two circles, and its distance from either midpoint is the radius of that respective circle.

滥情空心 2024-08-18 01:37:17

圆圈之间的碰撞很容易。假设有两个圆:

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

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

  • 如果圆的边缘相接触,则圆心之间的距离为r1+r2;
  • 任何更大的距离,圆圈都不会接触或碰撞;如果
  • 再少,它们就会发生碰撞。

因此,如果满足以下条件,您就可以检测到碰撞:

(x2-x1)^2 + (y2-y1)^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 <= tan X <= 1 for 0 <= X < ;= 45 度;
  • tan X >= 1 对于 45 <= X <= 90
  • 0 >= tan X >= -1 对于 0 >= X => -45;
  • tan X <= -1 对于 -45 >= X => -90; tan
  • X = tan (X+180) = tan (X-180)。

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

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

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

另一个圆上碰撞的八分圆是偏移的(C1 上的八分圆 1 意味着 C2 上的八分圆 5、2 和 6、3 和 7、4 和 8 等)。

Collision between circles is easy. Imagine there are two circles:

  • C1 with center (x1,y1) and radius r1;
  • C2 with center (x2,y2) and radius r2.

Imagine there is a line running between those two center points. The distance from the center points to the edge of either circle is, by definition, equal to their respective radii. So:

  • if the edges of the circles touch, the distance between the centers is r1+r2;
  • any greater distance and the circles don't touch or collide; and
  • any less and they do collide.

So you can detect collision if:

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

meaning the distance between the center points is less than the sum of the radii.

The same principle can be applied to detecting collisions between spheres in three dimensions.

Edit: if you want to calculate the point of collision, some basic trigonometry can do that. You have a triangle:

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

The expressions |x2-x1| and |y2-y1| are absolute values. So for the angle X:

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

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

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

Once you have the angle you can calculate the point of intersection by applying them to a new triangle:

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

where:

        a
cos X = --
        r2

so

a = r2 cos X

From the previous formulae:

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

Once you have a and b you can calculate the collision point in terms of (x2,y2) offset by (a,b) as appropriate. You don't even need to calculate any sines, cosines, inverse sines, or inverse cosines for this. Or any square roots for that matter. So it's fast.

But if you don't need an exact angle or point of collision and just want the octant you can optimize this further by understanding something about tangents, which is:

  • 0 <= tan X <= 1 for 0 <= X <= 45 degrees;
  • tan X >= 1 for 45 <= X <= 90
  • 0 >= tan X >= -1 for 0 >= X => -45;
  • tan X <= -1 for -45 >= X => -90; and
  • tan X = tan (X+180) = tan (X-180).

Those four degree ranges correspond to four octants of the circle. The other four are offset by 180 degrees. As demonstrated above, the tangent can be calculated simply as:

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

Lose the absolute values and this ratio will tell you which of the four octants the collision is in (by the above tangent ranges). To work out the exact octant just compare x1 and x2 to determine which is leftmost.

The octant of the collision on the other circle is offset (octant 1 on C1 means octant 5 on C2, 2 and 6, 3 and 7, 4 and 8, etc).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文