Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collision detection between rectangles (no overlap) - libgdx

I've been at this for 2-3 weeks now and I still can't manage to have a proper collision detection. I have created a maze using rectangles. I want my object (which is in a Rectangle) to stop whenever my object collides with any wall and be able to move anywhere (or slide down a wall). My walls (the rectangles) have negative coordinates like the following:

shapeRenderer.rect(0.9f, 12, 1.15f, 0, Color.RED, Color.RED, Color.RED, Color.RED); //NORTH
shapeRenderer.rect(1, 12, 0, -1.05f, Color.RED, Color.RED, Color.RED, Color.RED); // WEST
shapeRenderer.rect(2, 12, 0, -1.05f, Color.RED, Color.RED, Color.RED, Color.RED); // EAST
shapeRenderer.rect(0.9f, 11, 1.15f, 0, Color.RED, Color.RED, Color.RED, Color.RED); // SOUTH

I'm currently using an overlaps method that I've found in SO. Here's the method that's in my CollisionManager class:

private boolean overlaps (Rectangle collision, Rectangle wall) {
    return Math.min(collision.x, collision.x + collision.width) 
        < Math.max(wall.x, wall.x + wall.width) 
    && Math.max(collision.x, collision.x + collision.width) 
        > Math.min(wall.x, wall.x + wall.width) 
    && Math.min(collision.y, collision.y + collision.height) 
        < Math.max(wall.y, wall.y + wall.height) 
    && Math.max(collision.y, collision.y + collision.height) 
        > Math.min(wall.y, wall.y + wall.height);
}

I have a function which saves all position moves made by the object. Thus, when a collision occurs, the object restores to the previous move before the last move (since the last move is when the collision occured) (example below):

private void overlapsTop(Entity object, Rectangle wall){

    Rectangle r = new Rectangle();
    if(spritePositions.size() != 0){
        r = spritePositions.get(spritePositions.size()-1);
    }
    object.update(r.x, r.y, r.width, r.height);
    object.getObject().setBounds(r.x, r.y, r.width, r.height);
    spritePositions.clear();
}

Additional information: I'm moving my object like this:

public void moveRight(){
    position.x += 1f;
    update();
}

public void update(){

      boundingRectangle.set(position.x, position.y, object.getWidth(), object.getHeight());
}

Where I'm stuck is my overlaps function (the one I've found in SO). It works most cases; yet, for example, if the object moves near a wall on the right and touches it, the function returns true and everything gets executed. But let's say if I slide along the wall and move directly down and that there are no walls, the object stops at one point because it detects a collision between the bottom of the object and the top of a wall (when there's none) and a collision between the right of the object and the left of a wall.

I'm trying to find another solution for this. I just want my object to stop at any wall and be able to move (or slide down a wall) without suspecting that there might be a collision where there are no walls nearby. I feel that I'm very close to a solution, but I would need a little bit of extra help.

UPDATE

I've updated the moveRight function and the update function. @Adrian Shum and @Matthew Mark Miller I've made everything now with an integer (meaning instead of 0.01f, I use 1f).

Thus the following code that I use to move the object is like this:

if(Gdx.input.isKeyPressed(Keys.RIGHT)){

                 if(collisionManager.canSpriteNotMoveRight(object)){
                     object.stopGoingRight();
                 }else{
                     object.moveRight();
                 }
             }

In my collisionManager class, the function stopGoingRight is the following:

public void stopGoingRight(){
    position.x -= 1f;
    update();
}

So far, so good. When the object collides with the wall, the object stops and bounces back. That's good. But I have another problem (which is irritating) that I'll try to describe the best I can. If, for example, I keep moving the object up to a wall, the object will bounce back many times from that wall; if I stop pressing the up key, the object will sometimes stay stuck within the wall. Thus what happen is when I press the down key, it'll go up instead of going down (or if I press left, the object will go right instead of going left) because the overlaps function gets executed (since both object and the wall intersect).

Is there a way for me to solve this? It seems as though Libgdx isn't perfectly well-suited to handle this kind of collision detection, but I'm just far into deep in building my game right now.

like image 674
C.O.D.E Avatar asked Jun 23 '15 16:06

C.O.D.E


1 Answers

Your collision algorithm seems wordy but correct (Wordy because the min of x, x+ width is always just x as width must be >= 0, and the inverse is true for max).

Have you considered the possibility that it's a floating point precision issue? E.g if you add 1 to an fp number, then later remove 1 from the result, you aren't guaranteed to be back at the original value. You may be a little more or less as the intermediate result may not be representable as a float.

My favorite example: .1f + .2f > .3f

like image 133
Matthew Mark Miller Avatar answered Oct 04 '22 23:10

Matthew Mark Miller