Two rectangles colliding

Started by
13 comments, last by Stroppy Katamari 11 years, 4 months ago
There is a tutorial here that explain how to check if two 2D-rectangles collide. It works excellent in most cases in my game.
There is an other case where I need to check if the unit is colliding from the right, left, up or down. I am having trouble getting this function to work.

Anyone have or know a piece of code that works(C/C++/Java/C#)?
Advertisement
I use to solve this by having a "direction" of the objects. If you have for example an enemy object then you can use
if(x1.intersects(x2)){

if(enemy.dx == 1)
- do something
if(enemy.dx == -1)
- do something
if(enemy.dy == 1)
- do something
if(enemy.dy == -1)
- do something

Maybe that's a bad method, but I use it :)
You can use Dot Product for this purpose.

Consider PlayerDir as a vector pointing in direction the player looks and EnemyDir is the direction in which an enemy moves.

Using following calculation :

(PlayerDir.x * EnemyDir.x + PlayerDir.y * EnemyDir.y);



you get the value of cosine between their directions. Importantly, make sure that PlayerDir and EnemyDir are normalized! Otherwise you have to divide your result by length of both vectors!

If result was positive it means, that player and enemy moved in the same direction, so the player was hit in the back. If negative than, they moved in opposite directions. If you get value really close to 0, it means the player was hit from the side.
I've implemented a simple collision detection/response method for a 2d platform game project. At the moment, the only response I've coded is between player and platform collisions.

Collision util functions are defined here:
https://github.com/larsbutler/gamedemo/blob/master/src/com/larsbutler/gamedemo/math/Collision.java

And everything is used here:
https://github.com/larsbutler/gamedemo/blob/master/src/com/larsbutler/gamedemo/core/GameState.java#L95

This method would need to be optimized for lots of collisions, but for a low number it works well; it's reliable and stable.

I hope that helps.
We have rectangles R1 and R2. R1 has middle point (x1,y1), height h1, width w1, and is moving at velocity (vx1, vy1). Same stuff for R2.

Now let's assume we know there's a sideways collision between rectangles R1 and R2. It's really easy to determine which side the collision is on: you just look at their relative velocities. If vx2-vx1>0, R2 hit R1 from the left, otherwise it hit R1 from the right. If we know we have a vertical collision, same thing, we check vy2-vy1>0.

Looking at the middle points, x2-x1>0, would also work if the rectangles move slowly relative to their size. If they move so fast that one rectangle is already more than halfway inside the other when the collision check happens, this will produce a collision from the wrong side whereas velocities would produce the right result. Of course, if the rectangles move even faster, they will get past each other entirely before the collision check happens. To prevent that you'd have use a different strategy to check for collisions in the first place.

So that was trivial. The more interesting part is determining whether your collision is sideways or vertical. This is how I'd go about checking it:
1) For a collision to have happened, the rectangles must now be overlapping in both x and y directions.
2) We assume this is the first frame when the collision happens.
3) Therefore, on the last frame, the collision was not happening, and that means either the rectangles were overlapping in x direction, overlapping in y direction, or neither.
4) The last direction of those two directions which came to overlap is the collision direction.
(how to check presence of overlap between two rectangles in x-direction: abs(x1-x2) < (w1+w2)/2)
5) We check overlap between oldR1 and oldR2.
(we can get the old coordinates from new coordinates and velocity; oldx1 = x1-vx1, oldy1 = y1-vy1 and so on).
6) If there was x overlap between oldR1 and oldR2, the collision is vertical, because it's impossible for two rectangles overlapping in x direction to move in a straight line and collide horizontally. If there was y overlap between oldR1 and oldR2, the collision is horizontal.
7) In the special case that there was no x-overlap and no y-overlap, both overlaps occurred between last frame and this frame. Now it is slightly harder to figure out which of those overlaps occurred first and which occurred last. We'll call the moment of time when x overlap happened as timex and its counterpart as timey. With the exact same logic as before, if timex < timey is true, the collision is vertical, otherwise it is horizontal.
8) How to get timex and timey? It's elementary physics; distance divided by velocity equals time. In this case, the distance is the gap between the rectangles, and the velocity is the rectangles' relative velocity.
(timex = gapx / vx = (abs(oldx2-oldx1)-(w1+w2)/2) / abs(vx2-vx1))
Thanks for the help.
I have resolved this problem.

I appreciate the great help, looking forward to stay here :)

I have resolved this problem.
It would be considerate to tell how you resolved your problem, both for the benefit of those who have the same problem later, and for the benefit of those who tried to give you advice.
Funny you should mention this, I just finished posting a two part tutorial on bounding box collisions.

Part One -- covers the concept of an AABB in the first place, as well as having the code to check for a rectangle on rectangle collision.
Part Two -- which I literally posted 15 minutes ago, covers resizing the bounding box as your sprite rotates.

Both samples have a running example in the browser ( JavaScript using Easel ), but break out the math specific parts into their own section and have a complete explanation how everything works. Although the samples are in JavaScript, the code is basically 90% compatible with C#/C++/Java, so you only need to change a few key words to get it to compile in your language of choice ( which is why I went with JavaScript for examples... that and obviously it runs in the browser ).
My solution is irrelevant because uses variables that are exclusive to my game(and not to an actual rectangle) to calculate this.
Well my so called "solution" was limited to work with one single situation and the code is not reusable.
I want a global method to check this, so I have looked a bit closer at Stroppy Katamaris post.
With all due respect, your text is cryptic. Why is velocity needed? Old R2? timex/timey?
Could you please clarify your post?

This topic is closed to new replies.

Advertisement