My 2D physics aabb testing seems a little flooey

Attached is a project I made on top of PhysicsLab to better understand raycasting and aabb queries.

It’s pretty simple and self-explanatory, but if you play with it for any length of time, you’ll probably notice the bug: the purple square seems to be detecting the blue line when they aren’t touching at all.

In the attached screenshot you can see this happening: the purple text reports that the query has detected the line, but they’re not touching—I’ve racked my brain on this one, can anybody help?

@UberGoober The problem with trying to figure out what’s wrong is first trying to figure out what code is actually being run. Then trying to jump around from tab to tab to see what to look for. You’re adding code to an existing project that in my opinion is hard to follow to begin with since there’s 7 different examples all reusing some different code here and there. Whenever I have a problem with something not working, I’ll create another project with as little code as possible and work with that until I figure out what’s wrong. Since you added code, take what you added and create another project with that and see how raycast and aabb works, or in your case, doesn’t.

+1 on small test code.

@UberGoober Slide your finger to move the left square to the circle or the other square. The moving square is the aabb area. Below are some things you’ll see.

1.) rect to rect. They don’t have to touch to cause a hit.
2.) rect to circle. They don’t have to touch and the hit area around the circle appears to be a square the size of the circle.

viewer.mode=FULLSCREEN

function setup()
    rectMode(CENTER)
    stroke(255)
    strokeWidth(2)
    
    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
end

function draw()
    background()

    noFill()
    rect(r1.x,r1.y,80,80)
    ellipse(s1.x,s1.y,120)
    
    q=physics.queryAABB(vec2(tx-40,ty-40),vec2(tx+40,ty+40))
    if #q~=0 then
        fill(0,255,0)
    end
    
    rect(tx,ty,80,80)
end

function touched(t)
    if t.state==BEGAN or t.state==CHANGED then
        tx=t.x
        ty=t.y+150
    end
end

@dave1707 what a great little demo you whipped up—I was here deleting all the extraneous tabs in my existing project and arguing with myself about which lines of code should stay or not.

So yeah it looks like you done zeroed in on a bug—the 2D physics engine’s aabb routines seem to be yielding the wrong results.

@Simeon, did we find something new here?

@UberGoober I wouldn’t say they’re the wrong results, just not as exact as they could be. As far as I know, that might be the way it’s written, close enough to get the job done. If you’re running a game at full speed that’s using aabb to check something, you might not even notice the difference.

@dave1707 ennnnnnnnnnnh I think if a piece of software is going to tell me it made me a circle, that thing should act like a circle.

@UberGoober Its possible they were trying to keep the code for aabb small. Try writing some code that will indicate when any part of a rectangle of any size touches any part of a circle of any size.

@dave1707 I have had a lifetime’s worth of experience being wrong about things, so I’m sure this could be yet another one, but I find it hard to believe that a codebase that can accurately calculate a ball rolling down a slope doesn’t already have all the code it needs to accurately detect a circle overlapping a square.

I’ll be flabbergasted if it’s not a bug.

@UberGoober You may be right, but I’m sure that codes been around for a long time. I’d be surprised if no one found it in all that time.

PS. I checked up on aabb and it’s bounding volumes. It’s not meant to be exact, but a quick check to see if two objects might be overlapping. If they pass the aabb check then if a more exact check needs to be done, it can be. If they don’t pass the simple aabb check, then there’s no need to do the more intensive calculation.

So it’s not a bug, but just a simple check. I didn’t know that, so thanks.

Huh, I guess that’s another log on the “things I was wrong about” fire!

I am, as the kids on my playground used to say, moded.

From my own brief googling it seems like there’s kind of a grid underlying everything in the physics 2D system—it’s not that simple, I gather, but for the sake of illustration, we could say that aabb querying isn’t telling you exactly where a shape is, it’s telling you if any part of the shape is in the same square of the grid.

@dave1707 I think it’s even more complex than that—according to this:

https://stackoverflow.com/questions/18689451/what-is-aabb-explanation-required

…aabb bounding boxes can also include a body’s recent motions!

…man, I wonder if there’s some way to actually render all aabb boxes for any given moment on screen.

@UberGoober Here’s another example showing that the bounding area is a square around the triangle. Move the triangle around the square and make contact. I’ll have to try another example to see if the motion is also included.

viewer.mode=STANDARD

function setup()
    rectMode(CENTER)
    stroke(255)
    strokeWidth(2)    
    physics.gravity(0,0)
    r1=physics.body(POLYGON,vec2(0,0),vec2(100,0),vec2(100,100))
    r1.x=WIDTH/2
    r1.y=100
    r1.type=DYNAMIC    
end

function draw()
    background(0)
    noFill()
    line(r1.x,r1.y,r1.x+100,r1.y)
    line(r1.x+100,r1.y,r1.x+100,r1.y+100)
    line(r1.x,r1.y,r1.x+100,r1.y+100)
    q=physics.queryAABB(vec2(WIDTH//2-50,HEIGHT//2-50),vec2(WIDTH//2+50,HEIGHT//2+50))
    if #q~=0 then
        fill(0,255,0)        
    end
    rect(WIDTH/2,HEIGHT/2,100,100)    
end

function touched(t)
    if t.state==BEGAN or t.state==CHANGED then
        r1.x=t.x-50
        r1.y=t.y+150
    end
end

@UberGoober Here’s an example showing the trailing bounding area. There’s a fix circle shown and another circle off screen that’s falling. You have to wait about 8 seconds for the falling circle to hit the fixed circle. After the collision, move the aabb square above the circles and move it down. The aabb area will turn green well above the top circle. I’m not sure how the size of the trailing area is calculated. It has something to do with the speed of the moving object. If you remove the *10 so it doesn’t fall as far, the trailing area isn’t as much.

viewer.mode=FULLSCREEN

function setup()
    rectMode(CENTER)
    stroke(255)
    strokeWidth(2)

    s1=physics.body(CIRCLE,60)
    s1.x=WIDTH/2
    s1.y=HEIGHT*10
    s1.type=DYNAMIC
    
    s2=physics.body(CIRCLE,60)
    s2.x=WIDTH/2
    s2.y=100
    s2.type=STATIC
    
    tx,ty=WIDTH/2-300,HEIGHT-300
end

function draw()
    background()    
    noFill()
    ellipse(s1.x,s1.y,120)
    ellipse(s2.x,s2.y,120)
    q=physics.queryAABB(vec2(tx-40,ty-40),vec2(tx+40,ty+40))
    if #q~=0 then
        fill(0,255,0)
    end    
    rect(tx,ty,80,80)
end

function touched(t)
    if t.state==BEGAN or t.state==CHANGED then
        tx=t.x
        ty=t.y-150
    end
end

Nice demonstration!

I’ve been trying to figure out if there’s a way to detect a body’s actual aabb value at any moment in time.

In box2d (2.4.1 at least) bodies have a command “GetFixtureList”, and whatever a ‘fixture’ is, it has a “GetAABB” command that returns the actual AABB being tracked by the physics simulation.

It looks like ‘fixtures’ are a component of Box2D that’s intentionally obscured by Codea–I think fixtures allow a body to contain sub-bodies, and I am assuming @John decided that was an unnecessary layer of complexity for Codea, and in my opinion I think that’s the right call in general.

The fourth answer on this page : https://stackoverflow.com/questions/2620377/lua-reflection-get-list-of-functions-fields-on-an-object#comment2638663_2620398

…contains code that claims to output a pretty comprehensive survey of functions available at the global level, I think.

It’s written in lua, for a version of lua running on C#, though, and I can’t get it to do anything.

@UberGoober I don’t see any reason to know the aabb area. The whole purpose of aabb is just a quick check to see if two objects might be collideing. If aabb is true, then a more complex calculation can be don’t if the objects aren’t simple rectangles and you want to know exact collisions. In simple games, the aabb check might be enough, but in the physics code, you already have a collision function.

There are many reasons I’d like to know it — frankly, it’s honestly surprising to me that you don’t — but the simplest is that not knowing it created this whole post.

Isn’t that enough?

@UberGoober I guess I know more about aabb now then I did before, so in that respect it’s good. But as for using it, that doesn’t change much other than writing a few examples that uses it.

Right now, or should I say over the last few weeks, I’ve been trying to make a better demo of aabb and raycasting than the one in the current PhysicsLab–from which, currently, none of this is obvious or even, really, possible to guess.

I think being able to show people what’s happening by visually representing the actual aabb boundaries would be fantastic.

And I think it would save other people a huge amount of frustration if right from the start they knew not to use aabb testing if you want results that are precise or–for goodness’ sakes–current.