My 2D physics aabb testing seems a little flooey

@dave1707 can you provide an example? When I try to make precise movements with linear velocity I always mess it up.

Here’s your code modified a little to use appleForce instead of linearVelocity. I changed the gravity so the square falls. I also made the lower square static so it doesn’t fall. To move the upper square, with your finger below mid screen, slide your finger near the left side to move it left and right side to move it right. To move it up, slide your finger anywhere above mid screen.

It looks like all that’s happening is the black background is just the max size of the square as it rotates.

viewer.mode=FULLSCREEN

function boundsOf(body)
    local ll, ur = body.position, body.position
    if body.shapeType == CIRCLE then 
        ll = body.position - vec2(body.radius, body.radius)
        ur = body.position + vec2(body.radius, body.radius)
    else
        for _, thisPoint in ipairs(body.points) do
            local worldPoint = body:getWorldPoint(thisPoint)
            if worldPoint.x <= ll.x then ll.x = worldPoint.x end
            if worldPoint.y <= ll.y then ll.y = worldPoint.y end
            if worldPoint.x >= ur.x then ur.x = worldPoint.x end
            if worldPoint.y >= ur.y then ur.y = worldPoint.y end
        end 
    end  
    return ll, ur
end

function tableHas(targetTable, candidate)
    if not targetTable or not candidate then return end
    for key, element in pairs(targetTable) do
        if element == candidate then return key end
    end
end

function setup()
    
    rectMode(CENTER)
    stroke(74)
    strokeWidth(2)
    physics.gravity(vec2(0,-5))
    
    s1=physics.body(CIRCLE,60)
    s1.x=WIDTH/2
    s1.y=HEIGHT/2+200
    s1.type=STATIC
    
    r1=physics.body(POLYGON,vec2(-40,40),vec2(-40,-40),vec2(40,-40),vec2(40,40))
    r1.x=WIDTH/2
    r1.y=300
    r1.type=STATIC
    
    tx,ty=WIDTH/2-300,HEIGHT-300
    
    r2=physics.body(POLYGON,vec2(-40,40),vec2(-40,-40),vec2(40,-40),vec2(40,40))
    r2.x=tx
    r2.y=ty
    
end

function drawAABB()
    local all = physics.queryAABB(vec2(0,0),vec2(WIDTH, HEIGHT))
    for _, body in ipairs(all) do 
        local ll, ur = boundsOf(body)
        if ll and ur then
            local foundUpper, foundLower, foundRight, foundLeft, foundBounds
            while not foundBounds do
                local yUp, yDown, xLeft, xRight = 0, 0, 0, 0
                --find left edge
                while not foundLeft do
                    local bodiesToLeft = physics.queryAABB(vec2(0,0), vec2(ll.x - xLeft, HEIGHT))
                    if tableHas(bodiesToLeft, body) then
                        xLeft = xLeft + 1
                    else
                        xLeft = xLeft - 1
                        foundLeft = true
                    end
                end
                --find right edge
                while not foundRight do
                    local bodiesToRight = physics.queryAABB(vec2(ur.x + xRight, 0), vec2(WIDTH, HEIGHT))
                    if tableHas(bodiesToRight, body) then
                        xRight = xRight + 1
                    else
                        xRight = xRight - 1
                        foundRight = true
                    end
                end
                --find top
                while not foundUpper do
                    local bodiesAbove = physics.queryAABB(vec2(0, ur.y + yUp), vec2(WIDTH, HEIGHT))
                    if tableHas(bodiesAbove, body) then
                        yUp = yUp + 1
                    else
                        yUp = yUp - 1
                        foundUpper = true
                    end
                end
                --find bottom
                while not foundLower do
                    local bodiesBelow = physics.queryAABB(vec2(0, 0), vec2(WIDTH, ll.y - yDown))
                    if tableHas(bodiesBelow, body) then
                        yDown = yDown + 1
                    else
                        yDown = yDown - 1
                        foundLower = true
                    end
                end
                
                ur.x = ur.x + xRight
                ur.y = ur.y + yUp
                
                ll.x = ll.x - xLeft
                ll.y = ll.y - yDown
                
                foundBounds = true
            end
            pushStyle()
            rectMode(CORNER)
            fill(0)
            rect(ll.x, ll.y, ur.x - ll.x, ur.y - ll.y)
            popStyle()
        end
    end
end

function draw()
    background(233, 218, 80)
    
    drawAABB()
    
    q=physics.queryAABB(vec2(tx-40,ty-40),vec2(tx+40,ty+40))
    if #q > 1 then
        fill(0,255,0)
    end
    
    bodiesDraw({r1, r2, s1})
end

function touched(t)
    if t.state==BEGAN or t.state==CHANGED then
        if t.y<HEIGHT/2 then
            if t.x>r2.position.x then
                r2:applyForce(vec2(10,0))
            elseif t.x<r2.position.x then
                r2:applyForce(vec2(-10,0))
            end
        else
            if t.y>r2.position.y then
                r2:applyForce(vec2(0,10))
            end
        end
    end
end

function bodiesDraw(bodies)
    for i,body in ipairs(bodies) do
        pushMatrix()
        translate(body.x, body.y)
        rotate(body.angle)
        
        if body.type == STATIC then
            stroke(255,255,255,255)
        elseif body.type == DYNAMIC then
            stroke(150,255,150,255)
        elseif body.type == KINEMATIC then
            stroke(150,150,255,255)
        end
        
        if body.shapeType == POLYGON then
            strokeWidth(3.0)
            local points = body.points
            for j = 1,#points do
                a = points[j]
                b = points[(j % #points)+1]
                line(a.x, a.y, b.x, b.y)
            end
        elseif body.shapeType == CHAIN or body.shapeType == EDGE then
            strokeWidth(3.0)
            local points = body.points
            for j = 1,#points-1 do
                a = points[j]
                b = points[j+1]
                line(a.x, a.y, b.x, b.y)
            end      
        elseif body.shapeType == CIRCLE then
            strokeWidth(3.0)
            line(0,0,body.radius-3,0)            
            ellipse(0,0,body.radius*2)
        end
        
        popMatrix()
    end 
end

This version has the AABB drawing routine applied to all the physics lab tests.

Usually if you run the “sensors” test, and sometimes when you run the “filtering” test, once everything is still you can see an aabb region that isn’t a product of rotation and that exceeds the regular rectangular boundary of the shape (screenshot included).

I’m still not clear if you’re doubting that aabb sometimes incorporates momentum.

@UberGoober When an object is falling, I can see the bounding area increase in size above and below the object. I also see as the object rotates that the bounding area increases or decreases to keep a rotating object enclosed in it. I agree with you that it increases depending on its speed and direction. It’s just that in your one example it was increasing in size by a lot on all 4 sides even though it was barely moving. So I don’t have a problem with it.

If the aabb function is used just to determine collisions, I’ll just let the collide function determine the collision. It takes care of the collisions with any shaped object.

In the sensor example you can see the aabb area stretch out behind the box as it falls, and then once it hits the ground the aabb box (usually) stays extended beyond the boundaries of the physics body even though the physics body has stopped moving.

Honestly I don’t know what aabb boundaries are for, but they do seem to be working the way they’re supposed to, and most importantly the way they work is a lot different from the way the documentation says they work.

@UberGoober They had me confused too. I didn’t know that the bounding area stretched in front and behind a moving object. I guess that’s the fun part of Codea, trying to figure out what’s really happening and creating examples to show it.

@dave1707 clearly we have vastly different ideas of fun :wink:

Kudos to Codea for being a good tool for both of us.

@dave1707 I want to see what happens to aabb boundaries around a circle that’s rapidly moving in an elliptical orbit.

I am no good at all the sine and cosine stuff to make that kind of motion happen—but you’re a pro at that right? Would you be willing to share some basic code for describing a circular orbit?

viewer.mode=FULLSCREEN

function setup()  
    fill(255)  
    physics.gravity(vec2(0,0))
    
    s1=physics.body(CIRCLE,50)
    s1.x=0
    s1.y=0
    
    ang=0
    speed=1
    radius=math.min(WIDTH/2,HEIGHT/2)-50
end

function draw()
    background(0)
    ang=ang+1    
    s1.x=math.cos(math.rad(ang))*radius+WIDTH/2
    s1.y=math.sin(math.rad(ang))*radius+HEIGHT/2
    ellipse(s1.x,s1.y,100)   
    ang=ang+speed   
end

@dave1707 further somewhat-interesting results.

I applied your code to a physics body, and at the same time I made a circle that uses a REVOLUTE joint and angular velocity to achieve elliptical motion—in other words, a body that achieves circular motion just using the physics engine.

Of note:

  • the aabb rect of the manually-positioned circle actually lags behind the circle as it travels, meaning the circle is often outside its own aabb rect… which is odd…
  • the aabb rect of the manually-positioned circle never changes size—it’s always the size of the minimum rect needed to enclose the circle, no matter how fast it goes
  • the aabb rect of the circle moved by the physics engine never lags behind—even at the same or greater speeds than the manually-positioned one, it always fully encloses the circle
  • the aabb rect of the circle moved by the physics engine does change size as the circle moves, and the faster it moves the larger it gets.