Sphere/Rectangle collision detection
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!)
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!)
For Pong, you can take a lot of shortcuts that are much easier than doing a true rectanglecircle 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.
And you should really be using float or double for math, not int.
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.)
Quote:Originally posted by Mark Levin
For Pong, you can take a lot of shortcuts that are much easier than doing a true rectanglecircle 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.
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
[sourcecode]if ballx <= lpaddlex + paddlewidth[/sourcecode]
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)
[sourcecode]if bally <= paddley + paddleheight and bally + ballsize >= paddley[/sourcecode]
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.
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
[sourcecode]if ballx <= lpaddlex + paddlewidth[/sourcecode]
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)
[sourcecode]if bally <= paddley + paddleheight and bally + ballsize >= paddley[/sourcecode]
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.
If you're still interested in pursuing the circlevs.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 axisaligned 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 circlerect 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.]
The first thing you need is a function to find the closest point on an axisaligned 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 circlerect 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.]
Possibly Related Threads...
Thread:  Author  Replies:  Views:  Last Post  
Optimize the collision detection  alaslipknot  1  4,980 
May 12, 2013 08:02 PM Last Post: SethWillits 

Collision detection tutorial  ThemsAllTook  7  26,029 
Nov 5, 2011 05:20 PM Last Post: SethWillits 

Help with Collision Detection..(i'm almost there)  carmine  1  5,976 
Jun 29, 2011 12:33 PM Last Post: ThemsAllTook 

Time Delta, collision detection  mk12  19  20,403 
Sep 8, 2010 06:40 PM Last Post: AnotherJake 

Collision detection for pinball game  johncmurphy  0  5,697 
Sep 6, 2009 02:46 PM Last Post: johncmurphy 