## Sphere/Rectangle collision detection

sinclair44
Unregistered

Post: #1
I'm writing a Pong clone, and am having trouble with the collision detection, as I'm only working on completing Algebra I as of right now (I'm most of the way through). I have an NSRect for the paddle, an NSPoint for the center of the ball, and a float for the radius of the ball.

How do I tell if the two intersect? Thanks!

(P.S. - I was going to use CocoaBlitz until I saw it didn't have sprite collision detection!)
Member
Posts: 177
Joined: 2002.08
Post: #2
For Pong, you can take a lot of shortcuts that are much easier than doing a true rectangle-circle intersection test. The real test will probably involve trig and "real" geometry.

And you should really be using float or double for math, not int.
Member
Posts: 57
Joined: 2002.04
Post: #3
If the paddles move vertically on the left and right sides of the screen, couldn't you just test the points of the ball furthest to the left and to the right, since these should be the only points that would come in contact with the paddles? (Actually, I guess there is the possibility that the ball could hit the corner of the paddle; if you tested, say, eight points around the circumference of the circle, you should be able to detect these collisions as well. It wouldn't be precise, but considering how infrequently this happens in Pong and how fast the ball is usually moving, it shouldn't be noticeable.)
sinclair44
Unregistered

Post: #4
Quote:Originally posted by Mark Levin
For Pong, you can take a lot of shortcuts that are much easier than doing a true rectangle-circle intersection test. The real test will probably involve trig and "real" geometry.

And you should really be using float or double for math, not int.

Woops, typo: it is a float!

So, how could I write such a shortuct routine? I've never done such before (that's why this is 2D ) so have no idea where to start.
dougcosine
Unregistered

Post: #5
one thing you could do is make the "ball" a square like in Atari's original pong:

this makes it much easier.
for the paddle on the right (i'm going to assume you'd make the position of the ball be the position of it's top left corner:
what you want to know first is whether the ball is in an area where it could hit a paddle, so for the right paddle you'd want something like
[sourcecode]if ballx + ballsize >= rpaddlex[/sourcecode]
in which ballx is the x coordinate of the top left corner of the ball, ballsize is the width of the ball, and rpaddlex is the x coordinate of the top left corner of the right paddle. this checks if the right side of the ball (ballx + ballsize) is at or past the left side of the paddle (rpaddlex).

and for the left paddle it would be
this checks if the left side of the ball (ballx) is at or past the right side of the paddle (lpaddlex + paddlewidth)

next you want to check if the ball is at the same height as the paddle (this will be the same for both paddles)
if the top of the ball is above the bottom of the paddle and the bottom of the ball is below the top of the paddle.

if you really wanted to use a circle for your ball it'll be a little more complex. as long as the center of the ball is above the bottom of the paddle and below the top of the paddle you can just add/subtract the radius to the x coordinate of the ball and see if that's past one of the paddles. however, if the center of the ball is below or above the paddle you'll have to use the pathagorean theorum!

i don't know if you know what that is so i'll tell you.

for any right triange (a triangle with on angle of 90degrees) a^2 + b^2 = c^2 in which a and b are the lengths of the sides touching the right angle and c is the the length of the side opposite the right angle.

here's an interesting image!:

we can use this! we can find the distance from the corner of the paddle to the center of the ball and if this length is less than or equal to the radius they have collided!

just pretend that in that picture that where c and b intersect is the top left corner of the right paddle and where a and c intersect is the center of the ball. if c is more than the radius of the ball they haven't hit, if it's less they have.
Member
Posts: 63
Joined: 2005.12
Post: #6
If you're still interested in pursuing the circle-vs.-rect route, here's another way to go about it.

The first thing you need is a function to find the closest point on an axis-aligned rect to a given query point. To find this closest point, simply clamp the x and y components of the query point to the respective [min, max] range for the rect; the result is the point on the rect closest to the query point. (If this isn't clear, try drawing diagrams of a couple of test cases, and it should quickly become clear why this works.)

Once you have this support function in place, the test for circle-rect intersection proceeds as follows:

1. Find the point on the rect closest to the circle center
2. If the distance between these points is less than the circle radius (you can also use the squared distance if you prefer):
3. Compute the normalized vector from the closest point to the circle center. This is the collision normal.
4. Resolve the intersection (i.e. move the circle out of the rect) by moving the circle along this normal by a distance equal to the circle radius minus the distance from the closest point to the circle center (again, drawing a couple of diagrams should make it clear why this resolves the collision, if it's not clear already). It's advisable to add a small epsilon to this 'push' distance so that the ball does not register as colliding again on the next update.
5. You can then use the collision normal for collision response. Most likely you'll want to reflect the ball's velocity vector around the normal, as this will give you a fairly realistic bouncing effect.

This method will work as long as the ball does not move more than half its radius (or a little less, to be safe) per update. If it moves faster than that (fast enough that the ball can go from not intersecting the paddle to having its center within the paddle rect in one update, or - worse yet - fast enough to go all the way through the paddle in one update), you'll have to use another approach. However, a maximum displacement per update that is less than the ball radius seems like a reasonable restriction for a Pong game (since the update rate will likely be high relative to the ball speed).

[Edit: Some of this is also covered in dougcosine's post, above.]