0
\$\begingroup\$

I am trying to implement collision response in my libgdx game. I'm using Rectangle objects as my bounbing boxes. This makes collision detection very easy, however I can't quite get the response working correctly. At the moment I have this:

float overlapX = getOverlap1D(dynamicBounds.x, dynamicBounds.x + dynamicBounds.width, blockBounds.x, blockBounds.x + blockBounds.width);
float overlapY = getOverlap1D(dynamicBounds.y, dynamicBounds.y + dynamicBounds.height, blockBounds.y, blockBounds.y + blockBounds.height);

if (overlapX < overlapY)
{
      if (dynamic.getVelocity().x < 0)
      {
            dynamic.getPos().add(overlapX, 0);
      }
      else
      {
            dynamic.getPos().sub(overlapX, 0);
      }
      dynamic.setVelocityX(0);
}
else
{
      if (dynamic.getVelocity().y < 0)
      {
            dynamic.getPos().add(0, overlapY);
      }
      else
      {
            dynamic.getPos().sub(0, overlapY);
      }
      dynamic.setVelocityY(0);
}

private float getOverlap1D(float min1, float max1, float min2, float max2)
{
    return Math.max(0, Math.min(max1, max2) - Math.max(min1, min2));
}

Using this, corners are handled in a very unpleasant way, resulting in less than extraoridnary results like this. Where am I going wrong that allows this to happen?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

It's a rather old question, so the OP probably solved it already, but for those who might stumble here, there are my 2 cents.

I didn't made a thorough check of all the code, but the first obvious mistake I have spotted in the OP's code, is that he is using the overlap to compute the collision response. It might or might not be the culprit, but it's wrong IMHO. The value to compute should be the compenetration, which is similar to the overlap, but not the same in some edge cases (e.g. when high speed or a low framerate prevents a correct collision response and the object is now "inside" the one it's colliding with. Not this case, but still...).

Second, from the video I have also noticed that the "player" is sort of "sucked" in the object he's colliding with (maybe a signs problem of sorts? Are you sure the bodies in the the ifs are not inverted?). A word to the wise: wire some graphic debugging in your game: a couple of vectors with the values of speed and acceleration, coupled with a way to slow the simulation 10x or 20x will do wonders for your understanding of what's going on.

Even better: write all values to a file and do some post-game analysis with gnuplot/excel/whatever is an invaluable tool.

Hope this helps

\$\endgroup\$
0
\$\begingroup\$

Why don't you just use the rectangle class for this?

if (tileRectangle.overLaps(playerRec))
{
    //Overlapping, do not move in the direction you currently want.
}

Since you are using a tilemap you do not have to check each and every rectangle. Just the ones around the player. You setup a y loop with a inner x loop and set the start and end coordinates in it. This way you just have to check 9 tiles each loop or maybe 12 since you sprite is a bit bigger.

Once you have a overlap with other rectangles you can check check more precisely what is happening. You only ever have to check 2 direction because if the sprite is moving down and right the collision could never have been taking place above or at the left of the object.

So let's assume the player moves right and due to gravity (simulating or not) was pressed down as well and collided with something. So we have to check the bottom of the character and the right of the rectangle/character.

Vector2 bottomLeft = new Vector2(playerRec.x, playerRec.y);
Vector2 bottomRight = new Vector2(playerRec.x + playerRec.width, playerRec.y);
Vector2 topRight = new Vector2(playerRec.x + playerRec.width, playerRec.y + playerRec.height);

Now we check the bottom and right points independently so if we just detect a collision at the bottom we keep moving to the right

for (Rectangles r : rectanglesYouJustColidedWith)
{
    if(r.contains(bottomLeft) || r.contains(bottomRight)
    {
        //bottom collision you should not increase the y of the player.
        //You could however set is to the height of the rectangle + player height offset
    }
//If we use the same vector as the above for checking the right we would always hit true when we just have a bottomRight collision. 
//So we need a offset, this could also function as a step height the player can climb.
//You should offset this step offset by the amount your point went into the colliding rectangle, otherwise the point could still be inside the bottom rectangle.
//Rectangle
     if(r.contains(topRight) || r.contains(new Vector2(bottomRigth.x, bottomRight.y + stepheight)
    {
        //side collision you should not alter x of the player.
    }
}

Perhaps you can go with only 4 points if you do not have tiny gaps in your level. For bottom you only have to check the bottom middle and for right only the right center.

It all comes down to fine tuning this to your own liking. But these are the basics. You have to do the same for the top and the left, just wrap them in a statement like if (player moves left) checkThe corresponding collision.

\$\endgroup\$
2
  • \$\begingroup\$ My question is about collision response, not detection. I'm already detecting a collision in the way you've posted. \$\endgroup\$
    – Panda
    Jul 26, 2015 at 17:53
  • \$\begingroup\$ Sorry was on my phone and probably to bussy with other things to read correctly ;). I extended my post. \$\endgroup\$
    – Madmenyo
    Jul 26, 2015 at 18:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .