计算两个移动的球将碰撞的 x/y 坐标点

10

我正在尝试制作一个基本的台球游戏,并希望能够预测一杆球撞击另一个球后的去向。

首先,我认为需要计算球杆是否会撞击到任何物体,如果碰撞了,需要计算出碰撞点。我可以计算出直线和球的碰撞点,但是不知道两个球之间的碰撞点。

所以,给定2个球的x/y位置和速度,我该如何计算它们相撞的点?

(PS:我知道可以通过在每一步中计算两个球之间的距离来实现这一点,但我希望有更加优雅和高效的方法。)

设置示例:试图计算红点的位置:

http://dl.dropbox.com/u/6202117/circle.PNG

3个回答

14

需要注意以下几点:

  • 当两个半径均为 r 的球碰撞时,它们的中心点距离为 2r
  • 可以假定第一个球沿直线运动(第一次近似,但从这里开始),并且可以找到此路径与第一球到第二球方向之间的角度 alpha
  • 你知道静止球的中心吧?

现在你有一些几何问题要解决。

按照以下步骤进行构造:

  1. 将第一个(移动)球的当前中心标记为点 A
  2. 将静止球的中心标记为点 B
  3. 构造线段 AB
  4. A 沿着运动方向构造射线 R
  5. 围绕点 B 构造一个半径为 2r 的圆。
  6. B 垂直于 R 画出一条线段,将其相交点标记为 C
  7. 已知距离 AB,可以用正弦定律找到 ABR 之间的角度 alpha,然后找到线段 BC 的长度。
  8. 根据该长度确定是否存在 0、1 或 2 个解。如果有 0 或 1 个解,则完成了。
  9. 在圆上距离点 A 更近的位置构建点 D,再次使用正弦定律找到距离 AD 的长度。
  10. 碰撞点是线段 BD 的中点。

现在你知道了一切。

从这些内容中构建高效代码需要自己动手实践。


顺便提一下——如果两个小球都在运动,这种构造方法是行不通的。但你可以转换到一个其中一个小球静止的参考系中来解决问题,然后再转回去。只要确保在逆变换之后解的结果位于允许的范围内就行了...

物理学家们总是会说出类似这样的评论。我试图抵制,但我真的做不到。


我真是个笨蛋。之前有好几个人跟我解释过这个问题,但现在才明白。由于某种原因,我一直认为做2r会导致碰撞出现问题。感谢帮助,从这里开始我应该能够解决这个问题了。 - user352151
1
完成这种事情几次后,你会自动地拿起笔记本或白板。这就是你永远沉溺于编程世界的时刻... - dmckee --- ex-moderator kitten
1
这个答案让我感觉像是回到了高中几何课堂,这是不是很糟糕...但有点喜欢呢? - userx
刚才查看了你的个人资料,dmckee。中微子-干得好。听起来经过多年努力终于开始有所回报了。我真的很喜欢这个答案,期待能看到更多你的作品。 - duffymo

12

@dmckee的回答示意图如下:

alt text

编辑

针对@ArtB巫师的回答,上述图中D点的解决方案可以写成:

1/2 {(Ax+Bx+2 d Dx Cos[alpha]- Dx Cos[2 alpha]+ 2 Dy (Cos[alpha]-d) Sin[alpha]), 
     (Ay+By+2 d Dy Cos[alpha]- Dy Cos[2 alpha]- 2 Dx (Cos[alpha]-d) Sin[alpha])
     }  

在哪里

Dx = Ax - Bx 
Dy = Ay - By   

And

d = Sqrt[4 r^2 - (Dx^2 + Dy^2) Sin[alpha]^2]/Sqrt[Dx^2 + Dy^2]  

HTH!


1
我正在查看@dmckee的解决方案,需要花费相当多的工作来理解它。以下是我的笔记,供那些可能正在寻找更实用答案的人参考,这些笔记直接摘自他/她的帖子,因此功劳归于他/她,但任何错误都是我的责任。我通常使用类似Pascal的赋值运算符(即:= )来区分显示我的工作和实际必要的代码。我使用标准的Y = mX + b 格式和准面向对象符号。我对段和结果线都使用BC。话虽如此,这应该是“几乎”可以复制粘贴的Python代码(删除“;”,用适当版本替换“sqrt”和“sqr”等)。
  1. A.x和A.y是x和y的位置,A.r是A的半径,A.v是速度,其中A.v.x是其x分量,A.v.y是其y分量。
  2. B也是一样,但没有速度(或更准确地说,从A的速度中减去B的速度,使B相对静止)。
  3. AB.m := (b.y - a.y) / (b.x - a.x); AB.b := A.y - AB.m * A.x;
  4. R.m := A.v.y / A.v.x; R.b := A.y - R.m * A.x;
  5. 不必要
  6. BC.m := -A.v.x/A.v.y; 这是垂直斜率的标准方程,BC.b := B.y - BC.m * B.x; 现在C是AB与BC相交的点,所以我们知道它们是相等的,因此让我们将C.y等于AB.m * C.x + AB.b == BC.m * C.x + BC.b;所以C.x := (AB.m - BC.M) / (BC.b - AB.b);然后只需插入C.x即可得到C.y := AB.m * C.x + AB.b;
  7. 您可以忽略正弦定律,因为我们有AB和BC,因此我们可以使用勾股定理来获得BC的长度,BC.l := sqrt( sqr(B.x-C.x) + sqr(B.y-C.y) );
  8. 如果BC.l > A.r + B.r,则没有解,这些圆不相交,因为C是A相对于B的近地点。如果BC.l == A.r + B.r,则只有一个解,即C == D。否则,如果BC.l < A.r + B.r,则有两个解。您可以这样想,如果没有解,则子弹错过了,如果有一个解,则子弹擦伤了,如果有两个解,则既有入口又有出口。距离A更近的那个是我们想要的。
    1. 现在,数学变得丑陋,所以我会展示我的工作,以防我做错了什么。
    2. D是AC上距离B A.r + B.r(也就是2r)的点,因此:sqrt( sqr(D.x - B.x) + sqr(D.y - B.y) ) == 2r
    3. 因此,sqr(D.x - B.x) + sqr(D.y - B.y) == 4*r*r。现在有两个变量(即D.xD.y)和一个方程式是麻烦的,但我们还知道D在线上AC上,因此D.y == AC.m*D.x + AC.b
    4. 我们可以替换D.y,得到sqr(D.x - B.x) + sqr(AC.m * D.x + AC.b - B.y) == 4*r*r
    5. 这扩展成可爱的:sqr(D.x) + 2*D.x - sqr(B.x) + sqr(AC.m*D.x) + 2*AC.b*D.x - 2*AC.m*D.x*B.y + sqr(AC.b) - 2*AC.b*B.y + sqr(B.y) == 4*r*r是我可能犯错的部分如果我真的犯错了)。
    6. 我们可以

      我希望我只是为了卡尔玛或死灵法师徽章而发帖,但我真的需要解决这个问题,并想与大家分享。唉,我现在想躺下了。


现在这真是令人尴尬。好吧,至少我尝试过了。感谢提供一个比我的混乱更简单的替代方案。 - Sled
不用谢。记得在你的评论中以@用户名开头,这样你的对话方就会收到通知。我刚刚回来交叉检查了我的答案! - Dr. belisarius
1
根据您的应用程序,您可能不需要知道构造中每个点的位置。如果您以向量术语编写数学公式,则可能会发现这更容易:如果我一开始就尝试将所有内容都写成组件形式,我总是会迷失方向。 - dmckee --- ex-moderator kitten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接