0
votes

I'm trying to make some simple pool game in java script. I have made it but I do not love way of checking if two balls will collide in next frame. I would like to have more easier way to calculate coordinates of balls when collision occurs. I found lot of answers base on collision kinematics, how to handle velocities and directions after collision, but no calculating a position when collision occurs.

enter image description here

As you can see in sample diagram, gold ball is moving slower than a blue ball, and with distance that each ball will have to move on next frame will not be considered as collision. But, as you can see, they should collide (dashed lines).

In that cause I have divided each movement into sectors and calculating if distance between the points is equal or smaller than ball diameter, which is slowing down process when many balls (like in snooker) have to be calculated in each frame, plus that way is not always 100% accurate and balls can go in inaccurate angles after hit (not a big difference, but important in snooker).

Is there any easier way to calculate those (XAC,YAC) and (XBC,YBC) values with knowing start positions and velocities of each ball without dividing ball paths into sectors and calculating many times to find a proper distance?

2

2 Answers

1
votes

It is worth to precalculate collision event only once (this approach works well with reliable number of balls, because we have to treat all ~n^2 pairs of balls).

The first ball position is A0, velocity vector is VA. The second ball position is B0, velocity vector is VB.

To simplify calculations, we can use Halileo principle - use moving coordinate system connected with the first ball. In that system position and velocity of the first ball are always zero. The second ball position against time is :

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

and we just need to find solution of quadratic equation for collision distance=2R:

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

Solving this equation for unknown time t, we might get cases: no solutions (no collision), single solution (only touch event), two solutions - in this case smaller t value corresponds to the physical moment of collision.

Example (sorry, in Python, ** is power operator):

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)]
0
votes

Regarding to MBo's solution, here is a function in java script that will calculate coordinates of balls on collision and time in which collision will happen:

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
        };
    }
}