Advertisement Jump to content
Sign in to follow this  
????? ?????

2D Rects collision problems

This topic is 1851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I've written my own simple function to detect collisions of rectangles and it works not accurate and not always. So here is my code:

bool GameLogic::IsRectsCollide(float* rect1, float* rect2, float eps)
{
	float r1_left = rect1[0];
	float r1_top = rect1[1];
	float r1_right = rect1[2];
	float r1_bottom = rect1[3];
	float r2_left = rect2[0];
	float r2_top = rect2[1];
	float r2_right = rect2[2];
	float r2_bottom = rect2[3];
	if (r2_right - r2_left < r1_right - r1_left)
	{
		swap(r1_left, r2_left);
		swap(r1_top, r2_top);
		swap(r1_right, r2_right);
		swap(r1_bottom, r2_bottom);
	}

	if ( ( r1_left >= r2_left && r1_left <= r2_right && r1_top >= r2_bottom && r1_top <= r2_top ) ||
		( r1_right >= r2_left && r1_right <= r2_right && r1_top >= r2_bottom && r1_top <= r2_top ) ||
		( r1_right >= r2_left && r1_right <= r2_right && r1_bottom >= r2_bottom && r1_bottom <= r2_top ) ||
		( r1_left >= r2_left && r1_left <= r2_right && r1_bottom >= r2_bottom && r1_bottom <= r2_top ) )
	{
		return true;
	}

	return false;
}

Image shows typical fail... blink.png

Share this post


Link to post
Share on other sites
Advertisement

I would not design the code like that. It is much more complicated doing it your way and harder to maintain in the future and even unreadable. It does not need to be that way. 

 

Why not design a data structure called Rectangle with data members x and y and width and height? And have your ship bounded by a rectangle object? 

 

The swap operations and arrays make things more complicated.

 

psuedo code:

 

Rectangle rectangle = new Rectangle(x,y,width,height);

 

public boolean intersects(Rectangle other)

{

 

}

 

// collision algorithm

if(rectangle.intersects(asteroids.getRectangle())

{

 

}

Edited by warnexus

Share this post


Link to post
Share on other sites

Google "separating axis theorem".

 

For rectangles it's very simple.

// Assuming left right top and bottom are not flipped or invalid
if (r1_left < r2_right && r1_right > r2_left && r1_top < r2_bottom && r1_bottom > r2_top) 
    return true;  // Collision
return false;  // No collision

[edit] - I suppose if the edges are equal they would be touching but not necessarily colliding.

Edited by achild

Share this post


Link to post
Share on other sites

It's way less complicated for simple rectangle collision:

 

IF:
1st's top IS HIGHER THAN 2nd's bottom AND
1st's bottom IS LOWER THAN 2nd's top AND
1st's right IS MORE RIGHT THAN 2nd's left AND
1st's left IS LESS RIGHT THAN 2nd's right
THEN: WE HAVE COLLISION

Share this post


Link to post
Share on other sites

Google "separating axis theorem".

 

For rectangles it's very simple.

// Assuming left right top and bottom are not flipped or invalid
if (r1_left < r2_right && r1_right > r2_left && r1_top < r2_bottom && r1_bottom > r2_top) 
    return true;  // Collision
return false;  // No collision

[edit] - I suppose if the edges are equal they would be touching but not necessarily colliding.

It is correct, but there is performance problem and need to be optimized.
In your "if" statement you have 3 &&, which means that all comparisons must be done before return correct answer. In practical case "return false" state is more frequent than "return true" and if you will rewrite your code to determine "non collided" situations in earlier stage it will increase efficiency.
for example:
 
if( ( r1_left > r2_right ) || ( r1_right < r2_left ) || (r1_top > r2_bottom ) || ( r1_bottom > r2_top ) )
        return false;
return true;

in this case if first comparison( r1_left > r2_right ) is false it will immediately return false.
Edited by koiava

Share this post


Link to post
Share on other sites

Lazy evaluation of && does that already (bails out immediately if one of the operands is false).

 

EDIT: Likewise || immediately bails out with true if any operand is true. That's why in C you can do

 

if(ptr && ptr->dereference_it)

 

without causing a null pointer access violation.

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

no need a fancy code, here a simple solution:

bool point_in_rect(int x, int y, rect r)
{
if(x<r.left) return false;
if(x>r.right) return false;
if(y<r.top) return false;
if(y>r.down) return false;
return true;
}
bool rect_collision(rect r1, rect r2)
{
if(point_in_rect(r1.top, r1.left,r2)) return true;
if(point_in_rect(r1.down, r1.left,r2)) return true;
if(point_in_rect(r1.top, r1.right,r2)) return true;
if(point_in_rect(r1.down, r1.right,r2)) return true;
if(point_in_rect(r2.top, r2.left,r1)) return true;
if(point_in_rect(r2.down, r2.left,r1)) return true;
if(point_in_rect(r2.top, r2.right,r1)) return true;
if(point_in_rect(r2.down, r2.right,r1)) return true;
return false;
}
Edited by ngoaho91

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!