I am working on an Android game and I have two objects A and B (both rectangles) and when they collide I simply want to know which side of B was hit. I have detected the collision fine, but I am having trouble figuring out which side of the rectangle B took the hit? Any ideas? Thanks!
4 Answers
You can calculate the centroid (it's easy to calculate, google for a formula) of both rectangles and compare them.
I'm saying this, because it's a general solution, i have no idea how you do your collision detection, there are plenty of variables here like size and speed of the rectangles (if your rectangles move too fast and you're not doing sweep testing, then you might "overshoot" and it'll look like the collision was from the other side). It's not the most elegant solution either, but you only do this once when the collision happens, so it shouldn't be too bad, though that depends on the amount of collisions. You're not giving enough information.
-
\$\begingroup\$ I will look into this. It seems like it might do the trick. I only have two objects colliding and the collision detection is done through bounding boxes. \$\endgroup\$ Feb 17, 2012 at 14:30
I suggest computing the Minkowski sum of B and A, which is a new rectangle, and checking where the centre of A lies relatively to the diagonals of that rectangle:
float wy = (A.width() + B.width()) * (A.centerY() - B.centerY());
float hx = (A.height() + B.height()) * (A.centerX() - B.centerX());
if (wy > hx)
if (wy > -hx)
/* top */
else
/* left */
else
if (wy > -hx)
/* right */
else
/* bottom */
Edit: use Minkowski sum and fix variable names
-
\$\begingroup\$ But what happens when object A is coming down on top of object B where the center x of object A is less than the center x of object B \$\endgroup\$ Feb 17, 2012 at 14:58
-
\$\begingroup\$ Correct. I thought "side" only meant left or right. I will update my answer. \$\endgroup\$ Feb 17, 2012 at 15:07
-
\$\begingroup\$ Hmmm... I have done exactly what you posted and it seems to sort of work haha. I have found that it has problems with corners as well as problems with the top and bottom. I'll play around with this a bit though. Thanks! \$\endgroup\$ Feb 17, 2012 at 15:39
-
\$\begingroup\$ @Alex_Hyzer_Kenoyer: I am pretty confident this algorithm works properly for rectangles. But I see in another comment that A may actually be a ball, not a rectangle. Could that be the problem? If so, you should change the question (or maybe ask another one), because it changes the complexity of the problem. \$\endgroup\$ Feb 17, 2012 at 16:00
-
\$\begingroup\$ My plan is to make this collision work with a ball hitting a rectangle. Right now I just wanted to play around with the rectangle on rectangle collision. I have gotten it very close. I have a ball image bouncing around the screen and it bounces off of the rectangle correctly but there is obviously some problem because my image is a circle... Do you think I should just go down the road of asking a question about a ball hitting a rectangle? \$\endgroup\$ Feb 17, 2012 at 16:09
Compare A and B to see where they are in regards to each other.
A width 20 height 20 A xmin + pos, xmax + pos A ymin + pos, ymax + pos
Same above for B.
if A xmax + pos (left side) < B xmin + pos A is on left of B, B left side hit..
etc etc.
Are you using the Rect class? http://developer.android.com/reference/android/graphics/Rect.html
If so, some simple comparisons will left you know which side collided... From the Rect class, you have attributes for the top (or North), the bottom (or South), the left (or West), and the right (or East).
For example, this test will determine if rectB's left side crossed rectA's right side:
if ((rectB.left >= rectA.left) && (rectB.left <= rectA.right))
Remember that rectB could collide with two sides. Image rect B's lower left hand corner crossing over rect A's upper right...rect B would've crossed over rectA's top and right edges.
Remember that if rectB is completely inside rectA, that would look like it crossed over all four sides of rectA!
-
\$\begingroup\$ This does work for me, though like you said with the corners it is not perfect... I have changed my image to a ball, and I guess I will need to take into account that the ball has very small point of contact so I can't do this completely with rectangles. Though I think I am getting close. Thanks! \$\endgroup\$ Feb 17, 2012 at 14:31
-
\$\begingroup\$ You could use a bounding rectangle around your other shapes and/or sprites \$\endgroup\$– ambFeb 17, 2012 at 14:47
-
\$\begingroup\$ @Alex_Hyzer_Kenoyer: You need to calculate the time-of-impact over the last frame, this will give you the exact collision point between the two rectangles. Based on how deep the collision is, and the velocities of the two objects, you should be able to calculate how long ago they would have collided, which will give you an accurate picture over which side(s) the collision happened on. \$\endgroup\$ Feb 17, 2012 at 15:07
RectF
. There is a function Android calledRectF.intersects(RectF one, RectF two)
that I use to determine if they are colliding. From here I just can't seem to get determine which side of object B (the stationary rect) is being hit by object A (the moving rect). \$\endgroup\$