I am trying to calculate the collision of 2 balls of equal mass, assuming the collision is perfectly elastic, for a computer physics simulation. Given the coordinates of both balls and their initial velocities at the time of the collision, I want to calculate the final velocities. I searched around for a while online and found a few different websites give a formula for doing this. The problem is that when running the simulation, it seemed that kinetic energy was not being properly conserved (some collisions where adding energy which makes no sense at all, some losing it). So my question is: Is their something wrong with this method? Here is pseudo code for the method:

function manage_bounce(ball, ball2) {
    dx = ball._x-ball2._x;
    dy = ball._y-ball2._y;
    collisionision_angle = Math.atan2(dy, dx);
    magnitude_1 = Math.sqrt(ball.xspeed*ball.xspeed+ball.yspeed*ball.yspeed);
    magnitude_2 = Math.sqrt(ball2.xspeed*ball2.xspeed+ball2.yspeed*ball2.yspeed);
    direction_1 = Math.atan2(ball.yspeed, ball.xspeed);
    direction_2 = Math.atan2(ball2.yspeed, ball2.xspeed);
    new_xspeed_1 = magnitude_1*Math.cos(direction_1-collisionision_angle);
    new_yspeed_1 = magnitude_1*Math.sin(direction_1-collisionision_angle);
    new_xspeed_2 = magnitude_2*Math.cos(direction_2-collisionision_angle);
    new_yspeed_2 = magnitude_2*Math.sin(direction_2-collisionision_angle);
    final_xspeed_1 = ((ball.mass-ball2.mass)*new_xspeed_1+(ball2.mass+ball2.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_xspeed_2 = ((ball.mass+ball.mass)*new_xspeed_1+(ball2.mass-ball.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_yspeed_1 = new_yspeed_1;
    final_yspeed_2 = new_yspeed_2;
    ball.xspeed = Math.cos(collisionision_angle)*final_xspeed_1+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball.yspeed = Math.sin(collisionision_angle)*final_xspeed_1+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball2.xspeed = Math.cos(collisionision_angle)*final_xspeed_2+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_2;
    ball2.yspeed = Math.sin(collisionision_angle)*final_xspeed_2+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_2;

1 Answer 1


I've simplified your code using trig identities and the fact that the masses of the balls are equal. I've also formatted the code so it looks like the result of a rotation matrix multiplication and added comments indicating what I think the goal of each section is.

function manage_bounce(ball, ball2) {
    // determine direction of balls with ball2 at origin
    dx = ball._x-ball2._x;
    dy = ball._y-ball2._y;
    collision_angle = Math.atan2(dy, dx);
    c = Math.cos(collision_angle);
    s = Math.sin(collision_angle);

    // Rotate coordinate system by -collision_angle so
    // x-axis aligns with line joining the balls' centers.
    // Recalculate velocity components in new coordinate system.
    new_xspeed_1 =  c*ball.xspeed + s*ball.yspeed;
    new_yspeed_1 = -s*ball.xspeed + c*ball.yspeed;
    new_xspeed_2 =  c*ball_2.xspeed + s*ball_2.yspeed;
    new_yspeed_2 = -s*ball_2.xspeed + c*ball_2.yspeed;

    // Exchange the velocities parallel to collision
    // direction (xspeed) and rotate (+collision_angle)
    // back to original coordinate system.
    ball.xspeed = c*new_xspeed_2 - s*new_yspeed_1;
    ball.yspeed = s*new_xspeed_2 + c*new_yspeed_1;
    ball2.xspeed = c*new_xspeed_1 - s*new_yspeed_2;
    ball2.yspeed = s*new_xspeed_1 + c*new_yspeed_2;

This looks correct. Since the masses of the balls are equal, the result should be an exchange of velocities parallel to the collision direction since this preserves momentum. Kinetic energy should be conserved since \begin{align} \sum K &= \frac{1}{2}mv_1^2 + \frac{1}{2}mv_2^2 \\ &= \left(\frac{1}{2}mv_{1x}^2 + \frac{1}{2}mv_{1y}^2\right) + \left(\frac{1}{2}mv_{2x}^2 + \frac{1}{2}mv_{2y}^2\right) \\ &= \left(\frac{1}{2}mv_{2x}^2 + \frac{1}{2}mv_{1y}^2\right) + \left(\frac{1}{2}mv_{1x}^2 + \frac{1}{2}mv_{2y}^2\right) \\ \end{align} from switching $v_{1x}$ and $v_{2x}$.

If this is pseudocode, try simplifying your actual code in the same way I have and see if any mistakes are revealed.

Edit: two more math simplifications:

r = Math.sqrt(dx*dx + dy*dy) // or r = Math.hypot(dx, dy) if available
c = dx/r // cos(collision_angle)
s = dy/r // sin(collision_angle)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.