Due to so many email questions asking for help. I re-wrote this post to include more detail calculation steps:
Assume the radius for two ball are r1 and r2, and the coordinates are (x1,y1) and (x2,y2).
Usually, we calculate the distance between two balls d=sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
The collision should have occurred if d equal r1+r2; // if(d==r1+r2)
However, there is a finite time step dt in the simulation calculation,so most often we would not be able to find the above condition (exact time when two ball real occurred).
So we check if d<= r1+r2; Then we know the collision should have occurred.
The real collision should have occurred before you detected that the distance between two center of the balls d is less than the sum of those two balls r1+r2. (d< r1+r2)
The correct way is to find the time when the two ball really collide with each other.
Suppose the center of those two ball are x1,y2 and x2,y2
dx=x2-x1, dy=y2-y1; d=sqrt(dx*dx+dy*dy);
First calculate the component of velocity in the direction of (dx,dy)
vp1= vx1 *dx/d+vy1*dy/d;
Collision should have happened dt before you have detected r1+r2
and dt =(r1+r2-d)/(vp1-vp2);
and dt =(r1+r2-d)/(vp1-vp2);// the collision should have occurred at t-dt (Actually this is also an approximation).
So you should move those two ball backward
y2 -= vy1*dt;
Now the distance between center of the two balls is d'=r1+r2;
The following code take care of collision:
double dx = x2-x1, dy = y2-y1;
// where x1,y1 are center of ball1, and x2,y2 are center of ball2
double distance = Math.sqrt(dx*dx+dy*dy);
// Unit vector in the direction of the collision
double ax=dx/distance, ay=dy/distance;
// Projection of the velocities in these axes
double va1=(vx1*ax+vy1*ay), vb1=(-vx1*ay+vy1*ax);
double va2=(vx2*ax+vy2*ay), vb2=(-vx2*ay+vy2*ax);
// New velocities in these axes (after collision): ed<=1, for elastic collision ed=1
double vaP1=va1 + (1+ed)*(va2-va1)/(1+mass1/mass2);
double vaP2=va2 + (1+ed)*(va1-va2)/(1+mass2/mass1);
// Undo the projections
vx1=vaP1*ax-vb1*ay; vy1=vaP1*ay+vb1*ax;// new vx,vy for ball 1 after collision
vx2=vaP2*ax-vb2*ay; vy2=vaP2*ay+vb2*ax;// new vx,vy for ball 2 after collision
(ax,ay) is the unit vector in the direction connected two objects.
draw a line connect two object, assign the angle between this line and x-axis is θ,
then cosθ=ax, sin θ=ay
So vap1*ax=vap1*cosθ give x-component of vap1, and vap1*ay give y-component of vap1
Because vb1 and vb2 is in the direction perpendicular to the (ax,ay)
,then the angle between vb1 and x-axis is φ=θ+π/2
so cos φ=cos(θ+π/2)=-sinθ=-ay, sinφ=sin(θ+π/2)=cosθ=ax
to calculate x-component of vb1 we need to calculate vb1*cos φ=vb1*(-ay)=-vb1*ay
,and (y-component of vb1) = vb1*sinφ=vb1*ax
Because we have move time backward dt, we need to move time forward dt.
Now the distance between two ball will be larger than r1+r2.
If you did not correct the time dt (before you have found collision occurred, you will find balls clutch together. and they don't even let go.