Collision detection between rectangles (no overlap) - libgdx
Asked Answered
C

2

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.

Centiare answered 23/6, 2015 at 16:46 Comment(13)
Can the rectangle that you're controlling rotate? Or are you just rotating its heading?Turku
Yes, you can control its rotation. Basically, when you move down, up, right or left, the object will rotate correspondingly.Centiare
But the Rectangle will always be Axis-Aligned right?Kameko
Yes always! The rectangles are all axis-aligned.Centiare
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 laterAppassionato
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-EPSILONConsummate
or, make everything integer.Consummate
Out of curiosity... Is there a reason you don't want to use the libgdx Rectangle#overlaps(Rectangle) method?Shishko
@Shishko I'm not using it because i'm using negative coordinates for the rectangles and that I've tried before and it's not workingCentiare
why are you not using intersect method of Rectangle class??Rodina
@Rodina 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.Centiare
@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. :)Rodina
I already am doing that in my code. Look at my moveRight() function and stopGoingRight() function.Centiare
C
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!!

Centiare answered 29/6, 2015 at 2:28 Comment(0)
T
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

Turbinal answered 26/6, 2015 at 2:52 Comment(0)
C
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!!

Centiare answered 29/6, 2015 at 2:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.