9

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.

C.O.D.E
  • 885
  • 8
  • 19
  • Can the rectangle that you're controlling rotate? Or are you just rotating its heading? – Trent Small Jun 23 '15 at 17:09
  • Yes, you can control its rotation. Basically, when you move down, up, right or left, the object will rotate correspondingly. – C.O.D.E Jun 23 '15 at 17:12
  • But the `Rectangle` will always be Axis-Aligned right? – Robert P Jun 24 '15 at 07:43
  • Yes always! The rectangles are all axis-aligned. – C.O.D.E Jun 24 '15 at 12:50
  • for shapeRenderer.rect(0.9f, 12, 1.15f, 0 ... what parameters are you defining? seems strange to have coordinate-like input params and then rect.width and rect.height being used later – softwarenewbie7331 Jun 26 '15 at 03:07
  • 1
    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-EPSILON` – Adrian Shum Jun 26 '15 at 03:09
  • 1
    or, make everything integer. – Adrian Shum Jun 26 '15 at 03:10
  • Out of curiosity... Is there a reason you don't want to use the libgdx `Rectangle#overlaps(Rectangle)` method? – nEx.Software Jun 27 '15 at 03:44
  • @nEx.Software I'm not using it because i'm using negative coordinates for the rectangles and that I've tried before and it's not working – C.O.D.E Jun 27 '15 at 16:34
  • why are you not using intersect method of Rectangle class?? – dharam Jun 28 '15 at 02:54
  • @dharam Like i've answered before, the Intersector.overlaps function won't work with negative coordinates rectangles. I've used it before and it didn't work. – C.O.D.E Jun 28 '15 at 03:30
  • 1
    @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 Jun 28 '15 at 03:35
  • I already am doing that in my code. Look at my moveRight() function and stopGoingRight() function. – C.O.D.E Jun 28 '15 at 12:23

2 Answers2

5

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

Matthew Mark Miller
  • 3,128
  • 1
  • 16
  • 11
4

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!!

Community
  • 1
  • 1
C.O.D.E
  • 885
  • 8
  • 19