23

I'm writing a top down 2d XNA game. Since its my first I'm trying to write the physics and collision stuff myself to learn it.

Whenever my player sprite character attempts to move into a position where its bounds intersect with the edge of a wall, I figure out a bounce angle (angle of incidence = angle of reflection) and I make the player bounce off the wall and avoid the collision.

I'm having trouble figuring out how to deal with the situation of my sprite intersecting with two wall edges simultaneously though e.g. it hits a corner.

corner collision

My code currently tells me that two wall edges have been intersected but not which edge it would have hit first and therefore which edge to bounce off.

What is the mathematical test to pick which edge to bounce off? It's plain to see when looking at it but I'm struggling to figure out the math test for it.

TerryB
  • 1,273
  • 2
  • 13
  • 18
  • 2
    http://gamedev.stackexchange.com/questions/10911/a-ball-hits-the-corner-where-will-it-deflect – Tetrad Sep 21 '11 at 01:29
  • Thanks Tetrad. I saw that one but it looked like the ball would behave differently to my rectangular problem. In the case illustrated above the rectangular sprite would have hit the bottom edge of the wall and bounced off it. The side edge of the wall would never have come into the equation. I just don't know how to express that in code and make that decision. – TerryB Sep 21 '11 at 02:04

4 Answers4

17

Minimum displacement does not always give the right answer for which edge was hit first. Consider this case:

case that breaks shortest-displacement algorithm

This happens when the velocity is high enough that the block moves rather far during one frame. To correctly detect which edge was hit first, you'll need to set up a linear equation to solve for the time of collision with each edge. In this case described in the OP's diagram, the relevant equations are:

timeXCollision = (player.left - wall.right) / -player.velocity.x
timeYCollision = (wall.bottom - player.top) / player.velocity.y

(This is assuming an X-right, Y-up coordinate system.) In general, you'd have to use the signs of player.velocity's X and Y components to determine which pair of edges need to be tested. Anyway, once you have the collision times computed, the earlier of the two is the collision you need to handle.

Nathan Reed
  • 33,657
  • 3
  • 90
  • 114
10

If you calculate how far into the Wall the Player Sprite has moved, you can probably base it on the delta of the x and y coordinates of the corners that are intersecting. I hope that makes sense, I can't think of a better way to word it.

So, for example, if you look at your diagram. Take the x value of the top left corner of the Player Sprite (after the move), and subtract the x value of the bottom right corner of the Wall. Do the same thing for the y values and then see which one is larger. The key is that if one is larger than the other, the Player Sprite probably intersected on that side.

Here's an image example (this is a subsection of your image with my own lines added):

intersection example

Now, you see here that the blue line is larger than the green line. In this case the blue line is also on the side that the Player Sprite would be expected to bounce off of.

If the two values are equal, they hit right on the corner.

Now, there is a slight problem with doing it this way. If the Player Sprite is traveling very fast or the collision is very close to the corner, it's possible that the Player Sprite may go further into the Wall in the wrong direction. In that case you'll probably have to check the velocity of the moving object. (See Nathan Reed's answer.)

Note: I think I'm essentially trying to describe the SAT collision detection that @Blau mentioned, but I've spent a long time writing this so I'm going to post it anyways. Hopefully it'll help you some.

  • Thanks Drackir! And I guess if my wall is rotated relative to the sprite its a bit trickier but same principle applies. Look for the minimum length displacement vector that would mean the sprite would not collide with the wall. Then use the wall that is normal to that vector as my one to bounce off. – TerryB Sep 21 '11 at 03:26
  • @TerryB - Rotation adds a bit more complexity to it. You may want to read up on axis-aligned bounding boxes (AABB). Basically, you still use the same principle as above by testing the smallest box that the rotated object will fit into, but whose axes are aligned to the cartesian axes. Imagine if you had a square and you rotated it 45 degrees to make it a diamond. Calculating the collision on that would be difficult and costly, so first check to see if the object is even near it by using the AABB which would be a square where each point of the diamond touches each side in the middle. – Richard Marskell - Drackir Sep 21 '11 at 04:06
  • Then, when you know it's near it, you can do the more costly calculations to see if they intersect on angles (which should probably be another question altogether :) ). – Richard Marskell - Drackir Sep 21 '11 at 04:10
  • 1
    -1 since minimum displacement does not always give the correct answer to "which edge collided first"; see my answer. – Nathan Reed Jan 19 '12 at 17:53
  • @NathanReed - Which is why I mentioned checking the velocity in my "Now, there is a slight problem with doing it this way" paragraph. – Richard Marskell - Drackir Jan 19 '12 at 19:42
  • @Drackir Yes, but you didn't actually solve the problem, which is actually easy to solve in this case. – Nathan Reed Jan 19 '12 at 19:53
2

You need SAT Collision Detection

Basically you need to look for the minimum displacement vector that substracted to one of the objects let them to no intersect.

In your image the minimum displacement is the orange segment.

enter image description here

Blau
  • 3,386
  • 16
  • 19
  • 4
    -1 since minimum displacement does not always give the correct answer to "which edge collided first"; see my answer. – Nathan Reed Jan 19 '12 at 17:52
  • who are asking that? – Blau Jan 19 '12 at 23:13
  • The question is asking that. "My code currently tells me that two wall edges have been intersected but not which edge it would have hit first and therefore which edge to bounce off." – Nathan Reed Jan 20 '12 at 00:02
  • first? the problem is not what is the first, it collides with the two edges at the same time,... the matter is which edge to bounce off, you have choose one method that is good to you, I have choosed a method that is good to me, both are valid – Blau Jan 20 '12 at 12:25
  • No, they're not both valid. Look at the diagram in my answer; if the player is moving up, clearly it should bounce off of the bottom edge of the wall, not the side edge, which your method would have it do. – Nathan Reed Jan 20 '12 at 16:43
  • First, to clarify what does each solution, see this. Second, as you can see in this video, it works very well. Is my design decission, I can choose what solution is better, but both are solutions, and you're too self-centered thinking that your solution is the only right in the world. (English is not native to me, and I use a translator, I don't want to be offensive, only defend my opinion that is as good as yours). – Blau Jan 21 '12 at 08:53
  • 1
    If you want to make a design decision to let objects slip past each other like that, as if they were rounded or beveled on the corners, that's your decision, and may well be the right thing for your gameplay. But I don't think the question is asking about a design decision; it is asking mathematically how to bounce axis-aligned rectangles off each other. This is not a matter of interpretation; this math problem has a clear and correct answer to which edge to bounce off. – Nathan Reed Jan 21 '12 at 19:29
  • I think that the question was "How to deal with corner collisions in 2D?", and this reply is a good answer to that question, because describe a method to deal with corners in 2D... I think is easy to understand... ;) – Blau Jan 21 '12 at 22:16
  • SAT works flawless here and this is indeed a conceptual question, as the OP has no initial understanding how to implement a corner solution. SAT works out if object A boundary hits corner of object B OR if object B boundary hits corner of OR if truly two corners collide. I have implemented this code for my game and it is mathematically precise. However, the answer is not right. You check the min (negative) displacement BEFORE the collision takes place, i.e. collide objects, restore previous sate a frame ago, calculate (if displacement_x OR displacement_y OR no displacement), apply collision. – Majte Oct 13 '15 at 23:35
  • Also note a true corner vs corner collision is very rare and does not happen a lot (in my game at least) as one pixel is almost surely off on one axis. In case of true corner vs corner I revolve back to circle vs circle collision with circle size from center mass to corner. – Majte Oct 13 '15 at 23:37
0

Answered a similar question here

You may want to consider checking previous positions-

For example : if your left side was previously to the right of their right side and you're colliding, then a right hand collision has happened.

If you do this, just resolve y axis collisions, check if you're colliding with anything, then resolve x axis collisions.

ultifinitus
  • 1,912
  • 1
  • 16
  • 19