1
\$\begingroup\$

Detecting a 2d collision is easy, but after that, I'm having trouble fixing the AABB position to where it should be. I think it would be something like e.x=obj.x-aabb.x1. but this obviously won't work for sliding on the ground, as the position will put to the front of the object. You could subtract the prev pos, but that is garbage in a lot of ways.

How can I make sure that the AABBs line up normally, and allow sliding on both axes?

for y=0; y<rows;
    for x=0; x<row;
        info = map[y][x]
        if(info.solid && p.aabb.offset(p.x,p.y).intersects(x,y,x+1,y+1)
            ???
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Collision detection in games comprises of the following phases:

  1. Broad phase (which we will not go into here) culling.
  2. Narrow phase (which you have implemented) detection.
  3. Collision feature identification.
  4. Collision response.

Collision response, in your case, is correcting the position of intersecting AABBs, based on some metric, which is computed within step 3, which you are missing.

The features of a collision you are interested in, is the collision normal, and penetration depth.

But to compute these, you will need to redo your collision code again, but in more detail, but first, let me explain a few points.

An AABB is comprised of 4 edges, each of which has a normal vector:

(0,1), (1,0), (-1,0) & (0,-1) As shown below:

enter image description here

Now that we know this, we can use that information to measure the axis of minimum penetration :

function findMinAxis(in: pointsA, in: pointsB, out: min_penetration, out: normal) begin

    float maxA = min_possible_value
    float maxB = min_possible_value
    float minA = max_possible_value
    float minB = max_possible_value

    min_penetration = max_possible_value
    for each axis in axes loop
        for each point in pointsA loop
            if maxA < dot_product( point, axis)
                maxA = dot_product( point, axis)
            end if
            if minA > dot_product( point, axis)
                minA = dot_product( point, axis)
            end if
        end loop

        for each point in pointsB loop
            if maxA < dot_product( point, axis)
                maxA = dot_product( point, axis)
            end if
            if minA > dot_product( point, axis)
                minA = dot_product( point, axis)
            end if
        end loop
        
        float penetration = maxA - minB

        if penetration < min_penetration AND penetration > 0
            min_penetration = penetration
            normal = axis
        end if
    end loop
end function

Ok, that was a lot of pseudocode, so let's summarise it:

What this code does, is iterate through each axis, and project each of the corners of the box onto that axis (via the dot product). This allows us to know how far along the axis each point in, and thus, we can measure the overlap.

We can then compare this overlap to the previous value, and if it is both positive, and smaller, then it is our current best feature. Once the loops complete, then we have our minimum, and the axis that minimum resides upon.

Now that we have identified the axis of minimum penetration, we can now respond to it(see stage 4).

We can do this by moving one or more of the boxes so they don't overlap any more, or do something cooler, like use physics. It's entirely up to you.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .