circle-circle collision

russell picture russell · Nov 15, 2009 · Viewed 48.9k times · Source

I am going to develop a 2-d ball game where two balls (circles) collide. Now I have the problem with determining the colliding point (in fact, determining whether they are colliding in x-axis/y-axis). I have an idea that when the difference between the y coordinate of 2 balls is greater than the x coordinate difference then they collide in their y axis, otherwise, they collide in their x axis. Is my idea correct? I implemented this thing in my games. Normally it works well, but sometimes, it fails. Can anyone tell me whether my idea is right? If not, then why, and is any better way?

By collision in the x axis, I mean the circle's 1st, 4th, 5th, or 8th octant, y axis means the circle's 2nd, 3rd, 6th, or 7th octant.

Thanks in advance!

Answer

cletus picture cletus · Nov 15, 2009

Collision between circles is easy. Imagine there are two circles:

  • C1 with center (x1,y1) and radius r1;
  • C2 with center (x2,y2) and radius r2.

Imagine there is a line running between those two center points. The distance from the center points to the edge of either circle is, by definition, equal to their respective radii. So:

  • if the edges of the circles touch, the distance between the centers is r1+r2;
  • any greater distance and the circles don't touch or collide; and
  • any less and then do collide.

So you can detect collision if:

(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2

meaning the distance between the center points is less than the sum of the radii.

The same principle can be applied to detecting collisions between spheres in three dimensions.

Edit: if you want to calculate the point of collision, some basic trigonometry can do that. You have a triangle:

        (x1,y1)
        |\
        | \
        |  \ sqrt((x2-x1)^2 + (y2-y1)^2) = r1+r2
|y2-y1| |   \
        |    \
        |   X \
(x1,y2) +------+ (x2,y2)
         |x2-x1|

The expressions |x2-x1| and |y2-y1| are absolute values. So for the angle X:

        |y2 - y1|
sin X =  -------
         r1 + r2

        |x2 - x1|
cos X =  -------
         r1 + r2

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Once you have the angle you can calculate the point of intersection by applying them to a new triangle:

  +
  |\
  | \
b |  \ r2
  |   \
  |  X \
  +-----+
     a

where:

        a
cos X = --
        r2

so

a = r2 cos X

From the previous formulae:

       |x2 - x1|
a = r2 -------
        r1 + r2

Once you have a and b you can calculate the collision point in terms of (x2,y2) offset by (a,b) as appropriate. You don't even need to calculate any sines, cosines or inverse sines or cosines for this. Or any square roots for that matter. So it's fast.

But if you don't need an exact angle or point of collision and just want the octant you can optimize this further by understanding something about tangents, which is:

  • 0 <= tan X <= 1 for 0 <= X <= 45 degrees;
  • tan X >= 1 for 45 <= X <= 90
  • 0 >= tan X >= -1 for 0 >= X => -45;
  • tan X <= -1 for -45 >= X => -90; and
  • tan X = tan (X+180) = tan (X-180).

Those four degree ranges correspond to four octants of the cirlce. The other four are offset by 180 degrees. As demonstrated above, the tangent can be calculated simply as:

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Lose the absolute values and this ratio will tell you which of the four octants the collision is in (by the above tangent ranges). To work out the exact octant just compare x1 and x2 to determine which is leftmost.

The octant of the collision on the other single is offset (octant 1 on C1 means octant 5 on C2, 2 and 6, 3 and 7, 4 and 8, etc).