# Calculate the intersection depth between a rectangle and a right triangle

I'm working on a 2D platformer built in C#/XNA, and I'm having a lot of problems calculating the intersection depth between a standard rectangle (used for sprites) and a right triangle (used for sloping tiles). Ideally, the rectangle will collide with the solid edges of the triangle, and its bottom-center point will collide with the sloped edge.

I've been fighting with this for a couple of days now, and I can't make sense of it. So far, the method detects intersections (somewhat), but it reports wildly wrong depths. How does one properly calculate the depth? Is there something I'm missing?

• Are the rectangles axis aligned? – FxIII Sep 21 '12 at 13:49
• Yes, the rectangles are axis-aligned. – Celarix Sep 21 '12 at 15:18
• Have a look at Seperate Axis Theorem, you can calculate the shortest distance to seperate 2 generic convex polygons. This system has the benefit of having your triangle and rectangle rotated / scaled however you want; however... it provides much more functionality than you're asking for but takes a fairly good knowledge of vector maths to understand it – Joe Shanahan Sep 23 '12 at 0:00
• @Joe: Thanks, that theory seems to solve one of my larger problems in this problem. – Celarix Sep 23 '12 at 19:02
• @Celarix I used this when I was learning it: dl.dropbox.com/u/22121701/Polygon%20collision.rar This is C++, not xna though. However I managed to get it to work in XNA without knowing C++. – Joe Shanahan Sep 23 '12 at 20:10

I think your first problem is that you haven't quite stated your objective precisely. How exactly is the rectangle supposed to collide with the triangle? What exactly do you want the method to return? The code you linked is actually only returning a single number (since the X of the returned Vector2 is always 0). Your intention seems to be that this number be the distance that _rectB would need to move straight up in order to escape the triangle.

Per your request, I'm going to write it so that the method returns the Vector2 the rectangle would need to move to escape the triangle, where interactions with the sloped edge are moved directly up (or down) enough to extract the midpoint of the bottom (or top) edge from the triangle without reference to the left or right edges. In effect the sloped edge treats the rectangle as though it is a vertical line segment. Note that this will give very strange behavior near the pointy corners of the triangle; to fix this you would want to make those corners interact with the rectangle as though it were actually the diamond formed by the midpoints of its edges. I'll leave that modification to you.

Also, you haven't described what the properties of your triangle object mean; Left, Right, Top, and Bottom are clear enough I suppose, but Slope and B aren't, and if they mean what I suspect, you have a lot of redundancy in the class which might be confusing you.

In your place I would define your Triangle blocks just like Rectangles, but with a couple of added flags to say which half of the Rectangle is real. Hereafter I'm going to write the section for when the bottom-right half of the rectangle is used. You should not have trouble mirroring the algorithm for other choices.

if (tri.UseBottom) {
// check for collision with the bottom
if (rect.Top > tri.Top && rect.Top < tri.Bottom &&
rect.Left < tri.Right && tri.Left < rect.Right) {
// rect top is inside triangle, shove it down
return new Vector2(0, tri.Bottom - rect.Top);
}
if (tri.UseRight) {
// check for collision with the sloped edge
float rectMid = (rect.Left + rect.Right) / 2;
if (rectMid > tri.Left && rectMid < tri.Right) {
// check bottom against sloped edge
float triHeightAtMid =
triTop + ((tri.Right - rectMid) / (tri.Right - tri.Left)) *
(tri.Bottom - tri.Top);
if (rect.Bottom > triHeightAtMid) {
// midpoint of bottom inside triangle, shove it up
return new Vector2(0, rectBottom - triHeightAtMid);
}
else {
// midpoint of bottom above triangle, no collision
return new Vector2(0, 0);
}
}
// rect midline not inside triangle, check for collision with the right
if (rect.Left > tri.Left && rect.Left < tri.Right &&
rect.Top < tri.Bottom && tri.Top < rect.Bottom) {
// rect left is inside triangle, shove it right
return new Vector2(tri.Right - rect.Left, 0);
}
// checked all 3 edges, no collision
return new Vector2(0, 0);
}
else {
// ...
}
}
else {
// ...
}


Sounds like you're trying to implement sloped terrain? I tackled the same thing not long ago, and it's a real pain. Try not to think of the triangle as a 'right triangle'. Think of it as a box with a line passing through it. Once you've established that it's a line, then you can ask yourself, 'what's the slope of the line?'. Presumably in this case, it's probably 1/1 (1 rise over 1 run, being as typically a right triangle has a 45-degree slope). Then, the part you're probably missing is simple slope-intercept form:

y = mx + b (or in other parts of the world y = mx + c).

More simply put, DesiredLocationOfBottomOfRectangle = Slope(rise/run)*GivenXValue(probably the center of the rectangle) + PointAtWhichLineIntersectsYAxis.

This will give you the location at which the corresponding y location would be with the provided x location. If specifically you are interested in knowing the depth of the intersection of your rectangle into the triangle, you could probably take the value returned from the equation, and subtract it from the current y coordinate of the intersecting edge of the rectangle.