9
votes

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.

2
Can the rectangle that you're controlling rotate? Or are you just rotating its heading?Trent Small
Yes, you can control its rotation. Basically, when you move down, up, right or left, the object will rotate correspondingly.C.O.D.E
just a thought that may help: as mentioned by other, that may be caused by precision issue of floating point number. If you know that your maze/movement etc are going be, let's say, dealing with minimal of 0.01, then try to do an epsilon adjustment (using 0.005 maybe) in your overlaps, so that instead of writing a < b, write a < b-EPSILONAdrian Shum
or, make everything integer.Adrian Shum
@CODE. If negative coordinates is the only problem, then you could have applied translation to both the rectangles in vertical or horizontal or both directions before checking for intersection and then use translation back in the reverse direction. :)dharam

2 Answers

5
votes

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

4
votes

I've finally found a good solution all thanks to the following link: On overlap, player gets stuck libgdx Rectangle.

Basically I have to create a "fake" move to see if the object will collide with the wall. If there's a collision, i just stop the object and don't execute the new move.

Thanks for everyone's help :)!! It's greatly appreciated!!