AABB collision not working

Started by Andrew_3ds, February 11, 2015, 02:29:36

Previous topic - Next topic

Andrew_3ds

I'm trying to do AABB between two cubes, and I have tried several different tutorials online and I can't really find one I understand. I tried making one, but it doesn't work, and collision has been an annoying problem for a long time and I just can't get it to work.

Here is the current code I'm using
public class AABB {
    Vector3f pos;
    float front,back,right,left,top,bottom;
    float x1,x2,y1,y2,z1,z2;
    
    public AABB(float x, float z, float front, float back, float right, float left, float top, float bottom) {
        this.pos = new Vector3f(x,0,z);
        this.front = front;
        this.back = back;
        this.right = right;
        this.left = left;
        this.top = top;
        this.bottom = bottom;
    }
    
    public void update(Vector3f newPos) {
        this.pos = newPos;
        this.x1 = pos.x + right;
        this.x2 = pos.x + left;
        this.y1 = pos.y + top;
        this.y2 = pos.y + bottom;
        this.z1 = pos.z + front;
        this.z2 = pos.z + back;
    }
    
    public boolean intersects(AABB other) {
        if(this.x1 > other.x1||
           this.x2 < other.x2||
           this.y1 > other.y1||
           this.y2 < other.y2||
           this.z1 > other.z1||
           this.z2 < other.z2) {
//        --------------------------
                return true;
        }
        
        return false;
    }
}

Kai

Just do it in one dimension (X) first and expand what you'll find in Y and Z afterwards.
It's actually pretty easy. Get yourself a piece of paper and a pencil and draw rows of patterns of two line segments meeting each other.
Those lines should represent the projection of your AABB in a single dimension.

For example (I will use code blocks here just for monospace fonts):

First pattern (no intersection):
x1---------x2
                 x1Ã,´-------------x2Ã,´

Second pattern (intersection):
x1---------x2
      x1Ã,´-------------x2Ã,´

Third pattern (intersection):
      x1--------------x2
x1Ã,´-------------------------x2Ã,´

Fourth pattern (intersection):
x1---------------------------x2
      x1Ã,´-------------x2Ã,´

Fifth pattern (intersection):
       x1-----------------x2
x1Ã,´-------------x2Ã,´

Sixth pattern (no intersection):
                    x1-----------------x2
x1Ã,´-------------x2Ã,´


These are all patterns how two line segments can meet each other. Now, see which conditions the x'es need to have in order for the line segments to intersect.
Once you have that, you can simply copy/paste it and AND it together for the other two missing dimensions.

Hope, that helped!

Cheers,
Kai

SHC

There are a lot of representations for a AABB, where there is { v: min, v: max } approach, that stores the minimum and maximum vertices of the cube. Another famous representation is { v: center, float: width, height, thickness } approach. Personally I do prefer the second one as it was recommended in the Real-Time Collision Detection book.

public class AABB
{
    public Vector3 position;
    public float width, height, thickness;
}


In this representation, the position is the center point of the cube. To test the collision, I use this following piece of code.

public boolean intersects(AABB o)
{
    if (Math.abs(position.x - o.position.x) > (width/2 + b.width/2)) return false;
    if (Math.abs(position.y - o.position.y) > (height/2 + b.height/2)) return false;
    if (Math.abs(position.z - o.position.z) > (thickness/2 + b.thickness/2)) return false;

    return true;
}


Our condition is simple here, we cannot have been colliding in a direction if the distance between the centers in that axis is greater than the half of the size in that dimension. We are testing the same in all the three axes, and we quit early when we know that we aren't colliding.

Andrew_3ds

Wow, thanks guys! I got it working.
Here is the code I used (This is a dungeon-crawler like game; They Y will always be 0 so I don't need to check it)
public boolean intersects(AABB other) {
        if(this.pos.x + width/2 - other.pos.x > (other.pos.x-(other.width/2)) && this.pos.x - width/2 - other.pos.x < (other.pos.x+(other.width/2))) {
            if(this.pos.z + thickness/2 - other.pos.z > (other.pos.z-(other.thickness/2)) && this.pos.z - thickness/2 - other.pos.z < (other.pos.z+(other.thickness/2))) {
                return true;
            }
        }
        
        return false;
    }


I have one more problem though. When I collide with a block, I can no longer go through it, but now I can't move anymore, in any direction.
Movement code:
if(Display.isKeyDown(GLFW_KEY_W)) {
            boolean collided = false;
            float lastX = super.getX();
            float lastZ = super.getZ();
            float xTo = (float) (super.getX() + (Math.sin(Math.toRadians(ry)) * (speed*delta)));
            float zTo = (float) (super.getZ() - (Math.cos(Math.toRadians(ry)) * (speed*delta)));
            super.setZ(zTo);
            super.setX(xTo);
            for(Block b : OpenGL.lvl1.blocks) {
                if(this.aabb.intersects(b.aabb)) {
                    collided = true;
                }
            }
            for(Entity e : OpenGL.lvl1.entities) {
                if(this.aabb.intersects(e.aabb)) {
                    collided = true;
                }
            }
            if(collided) {
                super.setX(lastX);
                super.setZ(lastZ);
            } else {
                walking = true;
            }
        }

Kai

First a warning with good-will: You most likely do not want to build a physics engine yourself. :)
There are engines out there that you can make use of: JBullet, Dyn4j, jinngine.
Also maybe while your graphics is 3D your gameplay probably is 2D and does not require a full 3D engine, but you could get away with a 2D engine. In that case I would suggest having a look at JBox2D.

Having said that, now to your problem: You need a proper collision-response algorithm.

The problem is, when you detect a collision, then, due to the discretized nature of your physics simulation, your collided objects will always be a bit "inside" each other. You now have to figure out a position along the moving direction of the collided objects where they began to collide.
This can be done by holding onto the positions of the objects for two consecutive simulation frames, "current" and "last".
When in "current" you recognized a collision you know that in "last" there was none, and you can begin to "search" for a position of the objects along their moved direction where they first began to collide.
This is all very fiddly and error-prone, also due to floating-point arithmetic inaccuracies.
Therefore I would suggest having a look at existing frameworks first. If you do it for excercise then you can still investigate how existing engines do things and then use that knowledge.

Good luck,
and all the best, :)
Kai

david37370

What kai said is true, but for simplicity i suggest to make the response like this:
if one object is stationary, then calculate where the moving one collided it. explanation - in one dimension, line 1 (x1,length1) moves right and intersects line 2 (x2,length2), which is stationary. line 1 will be moved to x2-length1. basically the reverse of the collision detection.
if both object are movable, then calculate the middle point, and move each object so that it will touch it. our example with line 1 and line 2: here we calculate the middle point p = (x1+length + x2)/2, line 1 is moved to p-length and line 2 is moved to p.
this is what i use, and it works :)