计算碰撞时球位置的最简单方法是什么?

What is the easiest way to calculate position of balls on collision?

我正在尝试用 java 脚本制作一些简单的台球游戏。我做到了,但我不喜欢检查两个球是否会在下一帧发生碰撞的方法。我希望有更简单的方法来计算发生碰撞时球的坐标。我找到了很多基于碰撞运动学的答案,如何处理碰撞后的速度和方向,但没有计算碰撞发生时的位置。

正如您在示例图中看到的那样,金球的移动速度比蓝球慢,并且每个球在下一帧必须移动的距离不会被视为碰撞。但是,如您所见,它们应该会发生碰撞(虚线)。

因此,我将每个动作划分为扇区并计算点之间的距离是否等于或小于球直径,当必须在每一帧中计算许多球(如斯诺克)时,这会减慢过程,加上这种方式并不总是 100% 准确,击球后球的角度可能不准确(差别不大,但在斯诺克中很重要)。

有没有更简单的方法来计算那些(XAC,YAC)和(XBC,YBC)值,知道每个球的起始位置和速度,而不用将球路径分成扇形并计算多次以找到合适的距离?

值得只预先计算一次碰撞事件(这种方法适用于可靠数量的球,因为我们必须处理所有 ~n^2 对球)。

第一个球的位置是A0,速度矢量是VA。 第二个球的位置是B0,速度矢量是VB.

为了简化计算,我们可以利用哈利略原理——使用与第一个球相连的移动坐标系。在该系统中,第一个球的位置和速度始终为零。第二球位置与时间为:

B'(t) = (B0 - A0) + (VB - VA) * t = B0' + V'*t

我们只需要求出碰撞二次方程的解distance=2R:

 (B0'.X + V'.X*t)^2 + (B0'.X + V'.Y*t)^2 = 4*R^2

在未知时间求解此方程 t,我们可能会遇到以下情况:无解(无碰撞)、单一解(仅触摸事件)、两个解 - 在本例中较小的 t 值对应碰撞的物理时刻。

示例(抱歉,在Python中,**是幂运算符):

def collision(ax, ay, bx, by, vax, vay, vbx, vby, r):
    dx = bx - ax
    dy = by - ay
    vx = vbx - vax
    vy = vby - vay
    #(dx + vx*t)**2 + (dy + vy*t)**2 == 4*r*r  solve this equation
    #coefficients
    a = vx**2 + vy**2
    b = 2*(vx*dx + vy*dy)
    c = dx**2+dy**2 - 4*r**2
    dis = b*b - 4*a*c
    if dis<0:
        return None
    else:
        t = 0.5*(-b - dis**0.5)/a  ##includes case of touch when dis=0
        return [(ax + t * vax, ay + t * vay), (bx + t * vbx, by + t * vby)]

print(collision(0,0,100,0,50,50,-50,50,10))  #collision
print(collision(0,0,100,0,50,50,-50,80,10))  #miss
print(collision(0,0,100,0,100,0,99,0,10))    #long lasting chase along OX axis


[(40.0, 40.0), (60.0, 40.0)]
None
[(8000.0, 0.0), (8020.0, 0.0)]

关于 MBo 的解决方案,这里是 java 脚本中的一个函数,它将计算碰撞时球的坐标和碰撞发生的时间:

calcCollisionBallCoordinates(ball1_x, ball1_y, ball2_x, ball2_y, ball1_vx, ball1_vy, ball2_vx, ball2_vy, r) {
    let dx = ball2_x - ball1_x, 
        dy = ball2_y - ball1_y,
        vx = ball2_vx - ball1_vx, 
        vy = ball2_vy - ball1_vy,
        a = Math.pow(vx, 2) + Math.pow(vy, 2), 
        b = 2 * (vx * dx + vy * dy), 
        c = Math.pow(dx, 2) + Math.pow(dy, 2) - 4 * Math.pow(r, 2), 
        dis = Math.pow(b, 2) - 4 * a * c;
    if (dis < 0) {
        //no collision
        return false;
    } else {
        let t1 = 0.5 * (-b - Math.sqrt(dis)) / a, 
            t2 = 0.5 * (-b + Math.sqrt(dis)) / a,
            t = Math.min(t1, t2);
        if (t < 0) {
            //time cannot be smaller than zero
            return false;
        }
        return {
            ball1: {x: ball1_x + t * ball1_vx, y: ball1_y + t * ball1_vy},
            ball2: {x: ball2_x + t * ball2_vx, y: ball2_y + t * ball2_vy},
            time: t
        };
    }
}