16
\$\begingroup\$

I initially tried out implementing rectangular intersection, which works well. However, when I have to apply the physics system, such as velocity, acceleration, and directional vectors, I would have to find a way to determine which side of the rectangles collide. Now, in my system, there is no rotated rectangle, so this simplified the problem. However, I couldn't find an easy way to determine which rectangle side collided. I have once deal with this problem before but failed miserably.

What I did in the past is determine the distance between each parallel rectangular sides and check if the distance is close to 0 (use some initially defined distance range) or is 0. However, for floating-point arithmetic, this proves to be unstable because of unknown time elapse. Sometime, the rectangles would actually intersect each other before it meets the defined range.

On the other hand, I was thinking about spawning multiple rectangles, each rectangle for each sides. However, after thinking again, it would be the same thing as having a parallel side with distance range checking, just that that distance range is the width of each mini-rectangle.

Therefore, any suggestion to this problem?

\$\endgroup\$
  • \$\begingroup\$ Are you using discrete or continuous position updates? (are you updating your velocity by the acceleration once every frame and then calculating the position, or using a function to extrapolate the position) \$\endgroup\$ – Casey Kuball May 31 '12 at 5:56
24
\$\begingroup\$

Adapted from my answer to "Which Side Was Hit?":

I suggest computing the Minkowski sum of B and A, which is a new rectangle, and checking where the centre of rectangle A lies relatively to that new rectangle (to know whether a collision is happening) and to its diagonals (to know where the collision is happening):

float w = 0.5 * (A.width() + B.width());
float h = 0.5 * (A.height() + B.height());
float dx = A.centerX() - B.centerX();
float dy = A.centerY() - B.centerY();

if (abs(dx) <= w && abs(dy) <= h)
{
    /* collision! */
    float wy = w * dy;
    float hx = h * dx;

    if (wy > hx)
        if (wy > -hx)
            /* collision at the top */
        else
            /* on the left */
    else
        if (wy > -hx)
            /* on the right */
        else
            /* at the bottom */
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I would like to add that 'top' and 'bottom' are relative to your coordinate system. In my game for example, (0,0) is in the top left, so they are inverted from your example. Just something to keep in mind. \$\endgroup\$ – Neikos Dec 24 '15 at 23:55
  • \$\begingroup\$ great solution, worked very well for my needs. \$\endgroup\$ – Opiatefuchs Jan 14 '17 at 7:01
  • 1
    \$\begingroup\$ Is there some glitch with dx becoming 0 or dy becoming 0 or both? Let me reason it out... if dx = 0 && dy == 0, that means both rectangles are on the same origin, then the algorithm returns bottom by default? if either of them is 0, then the correct result is expected. So, I think, this algorithm is correct except for the case where dx == 0 && dy == 0, which should be indeterminate and not bottom. So, beware & thanks. \$\endgroup\$ – Prasanth Mar 20 '17 at 12:56
  • 1
    \$\begingroup\$ Now, I was wondering what happens when dx == dy, w == h... then too, the code decides that the result is one side when it actually is indeterminate..imagine two squares intersecting such that one square's centre is at a corner of another square and the other square's centre is at corner of first square. Here, the side should be indeterminate -- it's not right or bottom. It's both?! \$\endgroup\$ – Prasanth Mar 20 '17 at 13:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.