Tuesday, August 6, 2019

How do I detect the direction of 2D rectangular object collisions?


After this question, I need some more help.


How can I find out which side of a rectangle a collision came from and react accordingly?


rectangles being collided with from all sides


The blue arrows are the paths that some circular objects would follow if before and after colliding with the box.


How can I calculate this?



Answer




Since this is based on your other question I'll give a solution for when the rectangle is axis-aligned.


First, you build up you current object's rectangle with the following values:


int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;

Next, you must have the old object's position (which you can store on each object or simply pass to a function) to create the old object's rectangle (when it was not colliding):


int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;

int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;

Now, to know where the collision was from, you must find the side where the old position was not in the collision area and where its new position is. Because, when you think of it, this is what happens when you collide: a side that was not colliding enters an other rectangle.


Here is how you could do so (these functions assume that there is a collision. They should not be called if there is no collision):


 bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}


Rince and repeat.


bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}

bool collidedFromTop(Object otherObj)
{

return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}

bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}


Now, for the actual use with the collision response from the other question:


if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;

Again, this may not be the best solution but that's the way I usually go for collision detection.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...