Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm having difficulties getting a moveable rectangle to collide with more than one rectangle.

I'm using SFML and it has a handy function called intersects which takes 2 rectangles and returns the intersections. I have a vector full of rectangles which I want my moveable rectangle to collide with. I'm looping through this using the following code (p is the moveble rectangle).

IsCollidingWith returns a bool but also uses SFML's intersects to work out the intersections.

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

and the actual Collide() code:

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

and the IsCollidingWith() code is:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

This works fine when there's only 1 Rect in the scene. However, when there's more than one Rect it causes an issue when working out 2 collisions at once.

Any idea how to deal with this correctly? I have uploaded a video to youtube to show my problem. The console on the far-right shows the width and height of the intersections. You can see on the console that it's trying to calculate 2 collisions at once, I think this is where the problem is being caused.

Finally, the image below seems to illustrate my problem nicely:

rectangle colliding with multiple other rectangles

share|improve this question
    
The video link is broken. –  XiaoChuan Yu Mar 25 '12 at 22:47
    
Updated the video link, thanks XiaoChuan Yu. –  dotty Mar 25 '12 at 23:03
    
Are the collider objects returned by this->getCollider() updated by this->move() ?? –  XiaoChuan Yu Mar 25 '12 at 23:34
    
Could you add some more information please? What exactly is the problem? The YouTube video seems to show predictable behavior, and there's only one other rectangle in the scene. –  Wackidev Jun 2 '12 at 22:12
add comment

4 Answers 4

Your image illustrates one of the many problems with trying to use convex shapes - particularly rectangles - to simulate a flat surface like a floor. The algorithm leads to characters getting stuck on inner edges of the shapes making up the floor.

A simple fix for that is to check for vertical collision only, correct that, then check again for horizontal collision. Unless you're falling and trying to slide down a wall, in which case you want to check for horizontal collisions first. How do you know when to check which first? You could do it based on which component of your velocity is larger (if horizontal movement is greater, check vertical collisions first, otherwise check horizontal collisions).

What can be even simpler - and more performant - is to instead generate a list of edges for your world. That is, for your boxes making up the floor, set a flag indicating that only their top edge is actually collidable, and then ignore collisions with the other edges. You will not be able to use SFML's collision routine for that, but honestly simply box collisions is possibly the easiest bit of code you'll ever write in a game. This technique works particularly well if your world is aligned to a grid. I would check out the excellent Metanet tutorials (http://www.metanetsoftware.com/technique.html/) for that technique.

You're going to run into many others problems trying to build a simple 2D platformer game like you are. By far, the best resource I've seen latel for that is the following one, which you should read, and then read again:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

share|improve this answer
add comment

Maybe a simple solution would be to check for collisions with every rectangle and move back, in the opposite direction of movement, until no collisions are detected. If that solves the problem, the implementation should be quite simple too.

share|improve this answer
    
+1, I actually wrote about it here: gamedev.stackexchange.com/questions/38252/… –  Markus von Broady Oct 11 '12 at 8:44
add comment

I don't think having 2 collisions calculated is a problem, only a performance issue. In order for the collision to be handled correctly it may have to be tested twice. Using your diagram think if A is tested against B first, then it will need to be tested against the other boxes as well, and may well collide with another.

Hope that is helpful?

share|improve this answer
add comment

This isn’t really an optimal method, you should be trying to determine there earliest time when or the first point along the moving objects path where collisions occur and move the objects to that position (or the position at the calculated time), attempting to correct based on the penetrating positions after movement is very problematic, but you can use your current process with a small change. Just keep checking for collisions until there are none.

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

Note that there are situations where this will lead to an Infinite Loop (think of a situation where moving the box out of a collision results in another collection, and moving the box out of that collision moves it back into the same colliding position as before)

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.