Я использую такое решение для эмуляции движения и соударения пятнадцати шаров (Object Pascal):
for i:=1 to 15 do // просчитываем соударения шаров
for j:=i+1 to 16 do begin
dist:=sqrt(sqr(balls[i].x-balls[j].x)+sqr(balls[i].y-balls[j].y)); //расстояние между центрами шаров
if dist<diametr then begin //если расстояние меньше диаметра, значит есть факт соударения
a:=balls[i].x-balls[j].x; //вспомогательные переменные типа extended
b:=balls[i].y-balls[j].y;
p1:=a*b/sqr(dist);
p2:=sqr(a/dist);
p3:=sqr(b/dist);
d1:=balls[i].dy*p1+balls[i].dx*p2-balls[j].dy*p1-balls[j].dx*p2;
d2:=balls[i].dx*p1+balls[i].dy*p3-balls[j].dx*p1-balls[j].dy*p3;
balls[i].dx:=balls[i].dx-d1; //меняем значение приращения координаты шаров при движении
balls[i].dy:=balls[i].dy-d2;
balls[j].dx:=balls[j].dx+d1;
balls[j].dy:=balls[j].dy+d2;
p3:=(diametr-dist)/2; //при соударении шары всегда "проникают" друг в друга, поэтому раздвигаем их
p1:=p3*(a/dist);
p2:=p3*(b/dist);
balls[i].x:=balls[i].x+p1;
balls[i].y:=balls[i].y+p2;
balls[j].x:=balls[j].x-p1;
balls[j].y:=balls[j].y-p2;
end;
end;
for i:=1 to 15 do
balls[i].x:=balls[i].x+balls[i].dx; //эмулируем движение
balls[i].y:=balls[i].y+balls[i].dy;
end;