0
\$\begingroup\$

I'm using simple AABBs in a tile based world, and for some reason the algorithm does not detect collisions when moving towards the left and then down. I actually upload a video to YouTube to demonstrate the problem because I can't figure out a good way to explain my problem. Here it is: AABB collision detection problem

As you can see, the little wireframe tile that moves around is the player, and when I move to the left, and then try to move down on the tiles, the player just slips right through. Detection works when moving to the right. Here's my algorithm to detect collisions:

public static boolean isColliding(AABB a, AABB b) {
    if (Math.abs(a.pos.getX() - b.pos.getX()) < a.size + b.size) {
        if (Math.abs(a.pos.getY() - b.pos.getY()) < a.size + b.size) {
            return true;
        }
    }
    return false;
}

The pos variable in the AABB class is the center of the AABB in question, and the size is half the size. Here's how I move the player:

if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
        move(0, 1, 0, MOVESPEED);
    }
    if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
        move(1, 0, MOVESPEED, 0);
    }
    if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
        move(-1, 0, -MOVESPEED, 0);
    }
    if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
        move(0, -1, 0, -MOVESPEED);
    }
    if (Keyboard.isKeyDown(Keyboard.KEY_SPACE) && onGround) {
        onGround = false;
    }

Which references this method:

private void move(float x, float y, float sx, float sy) {
    if (getX() / 32 + x >= 0 && getX() / 32 + x <= world.mx && getY() / 32 + y >= 0 && getY() / 32 + y <= world.my) {
        if (world.tiles[(int) ((int) getX() / 32 + x)][(int) ((int) getY() / 32 + y)] != null) {

            Tile t = world.tiles[(int) ((int) getX() / 32 + x)][(int) ((int) getY() / 32 + y)];
            Vector2f tempPos = new Vector2f((pos.getX() + (pos.getX() + 32)) / 2, (pos.getY() + (pos.getY() + 32)) / 2);
            box.update(new Vector2f(tempPos.getX() + sx, tempPos.getY() + sy), 16);
            t.color = true;

            if (!Collision.isColliding(box, t.getBox())) {
                setPos(getX() + sx, getY() + sy);
            }
        } else {
            setPos(getX() + sx, getY() + sy);
        }
    } else {
        setPos(getX() + sx, getY() + sy);
    }
    glPushMatrix();
    glTranslatef(getX(), getY(), 0);
    glPopMatrix();
}

32 is the tile size and the player size, just for reference. The 'tempPos' vector is just a vector that holds the center of the player's position. AABB is a class that stores a vector and a size variable, and the update method just updates those variables.

I guess my question is either, why is it only working on one axis, or how can I change my move method to be "better"? I've been trying to figure out why this isn't working, and I just can't come up with any ideas because it happens constantly, so it's not that my entities are moving too fast and the algorithm isn't detecting the collisions.

\$\endgroup\$
  • \$\begingroup\$ Looks like you are only checking collision with tiles that are to the left of your player. In your move function, you are truncating with your divisions which may be causing this issue. \$\endgroup\$ – congusbongus Dec 10 '13 at 4:18
  • \$\begingroup\$ So should I check if I'm moving to the left and then instead multiply to find my position? \$\endgroup\$ – opiop65 Dec 10 '13 at 10:51
  • \$\begingroup\$ But wait, no that makes no sense because I'm dividing to find my world coordinates. How does that make any sense? \$\endgroup\$ – opiop65 Dec 10 '13 at 11:15
1
\$\begingroup\$

Let's say you are at the position (336, 330), and you are moving the block downwards. According to this line in your code:

if (world.tiles[(int) ((int) getX() / 32 + x)][(int) ((int) getY() / 32 + y)] != null) {

You're going to be checking the point tile (10, 9), which is fine. But your tile is positioned half way between two tiles. That means you should also be checking the tile (11, 9) for a collision. Casting to an (int) rounds down. But you should also have a conditional where you are rounding up.

\$\endgroup\$
  • \$\begingroup\$ So if I understand correctly I should be checking for two tiles in every direction I move instead of one and see if I collide with either? For instance, when moving down I should check the two potential tiles under the player? Is this his its normally done? I was always told only to check the tiles directly touching the player. \$\endgroup\$ – opiop65 Dec 10 '13 at 13:20
  • \$\begingroup\$ Very basic collision detection would mean checking all the tiles the player is intersecting with, which would be four tiles in your case (each corner of the player will be in a different tile, except when aligned with the grid). But since you know the direction the player is moving in, you only need to check the tiles in that direction, meaning, yes, two tiles. Personally I'd just check all four tiles each time, regardless of movement direction, to keep things simple. \$\endgroup\$ – Fault Dec 10 '13 at 15:03
  • \$\begingroup\$ Ah, I see. I don't know why I didn't think of that. So, just to clarify I should check the eight tiles around the player (since the player is the size of tile), or should I just check the four tiles around the player? I think I should check all eight because like you said, I was stuck in between two tiles. \$\endgroup\$ – opiop65 Dec 10 '13 at 15:23
  • 1
    \$\begingroup\$ Four tiles is enough. If the player is aligned to the grid, such as at the position (32, 32), it won't (at that moment) be colliding with any tiles. If, on the other hand, it's at (16, 16), it'll be half way between tiles on the x and y axis. And as such, you'd need to check for collisions at the tiles: (0, 0), (0, 1), (1, 1), and (1, 0). 4 tiles in all. Think about it this way: how many tiles can the player occupy at once? \$\endgroup\$ – Fault Dec 10 '13 at 17:20
  • \$\begingroup\$ Right, but with my rounding will it not just do the same thing as it is now? Where it rounds off and picks the incorrect tile? That's why I think I need eight to account for when the player is in between tiles. \$\endgroup\$ – opiop65 Dec 10 '13 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.