@UberGoober I think you’re missing the point of aabb. It’s not supposed to be used for precise or current collision results. It’s a quick and easy way (code wise) to check if 2 objects are colliding. If the 2 bounding areas don’t overlap, then the 2 objects in those areas aren’t colliding. If the bounding areas do overlap, then you can either say that’s close enough, or do a more intense (code wise) calculation to determine if they collide. It’s very simple code to determine if 2 rectangles overlap, so that would be very fast when checking a lot.
@dave1707 I think you’re missing the point of me missing the point.
If I understand you correctly, you think I want aabb testing to be something it’s not, and that’s what I may have failed to make clear: I’m just trying to make an accurate demo.
I’m looking for a way to easily and accurately and visually demonstrate it to others, because the current PhysicsLab doesn’t.
Also I apologize @dave1707 for being a jerko earlier about circles being circles and stuff. You’d think I’d eaten enough humble pie in my life to not act that way anymore, and I try not to, but clearly I fail now and then. Sorry.
@UberGoober No need to apologize about anything. Most of the time I don’t understand what is being asked and I go off in the wrong direction.
Glad to hear it, @dave1707, thanks for letting me know.
For what it’s worth, in actual Box2D, you can query a body directly for its precise current aabb boundary, so wanting and using that information is at least common enough that they built it right into the API.
If you want to take a second to try to think of a way to clearly and visually demonstrate this unusual aspect of aabb querying without actually showing the boundaries themselves, I’d love to know what occurs to you.
@UberGoober I don’t think there’s an option in Codea to show it. If the aabb area is stationary, then it just the defined rectangle around it. If it’s a moving aabb, then it’s harder to pinpoint the area.
PS. Haven’t found a way to highlight the aabb area of a moving object.
@dave1707 maybe play around with this:
viewer.mode=OVERLAY
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)
noStroke()
physics.gravity(vec2(0,0))
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
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
while not foundUpper do
local bodiesAbove = physics.queryAABB(vec2(ll.x, ur.y + yUp), vec2(ur.x, ur.y + yUp + 1))
local indexOfBody = tableHas(bodiesAbove, body)
if bodiesAbove[indexOfBody] then
yUp = yUp + 1
else
foundUpper = true
end
end
while not foundLower do
local bodiesBelow = physics.queryAABB(vec2(ll.x, ll.y - (yDown + 1)), vec2(ur.x, ll.y - yDown))
local indexOfBody = tableHas(bodiesBelow, body)
if bodiesBelow[indexOfBody] then
yDown = yDown + 1
else
foundLower = true
end
end
while not foundRight do
local bodiesRight = physics.queryAABB(vec2(ur.x + xRight, ll.y), vec2(ur.x + xRight + 1, ur.y))
local indexOfBody = tableHas(bodiesRight, body)
if bodiesRight[indexOfBody] then
xRight = xRight + 1
else
foundRight = true
end
end
while not foundLeft do
local bodiesLeft = physics.queryAABB(vec2(ll.x - (xLeft + 1), ll.y), vec2(ll.x - xLeft, ur.y))
local indexOfBody = tableHas(bodiesLeft, body)
if bodiesLeft[indexOfBody] then
xLeft = xLeft + 1
else
foundLeft = 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()
fill(233, 218, 80)
rect(r1.x,r1.y,80,80)
ellipse(s1.x,s1.y,120)
rect(r2.x,r2.y,80,80)
q=physics.queryAABB(vec2(tx-40,ty-40),vec2(tx+40,ty+40))
if #q > 1 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
r2.position = vec2(tx, ty)
end
end
…I think it draws the actual aabb, though it’s all brute-force. There might be a better way to do it.
The bodies are drawn in yellow and the aabbs are drawn as black boxes behind them.
I’m not sure if any single body’s aabb can be a shape other than a rectangle, if so this is imprecise because it only draws rectangles.
…and my original intersection lab project with accurate aabbs drawn (attached)
@UberGoober I don’t think this is working. There’s no reason the aabb area should increase in size just because I touch one of the other objects with the other.
@dave1707 it might not be working, but according to what I’ve read, there’s totally a reason the aabb would increase in size because of a touch.
Again, my code could be wrong, but as I understand it, aabb shows where an object could be, because it’s intended to return extremely best-guess results, leaving it up to other querying techniques to get more precise if needed.
So my code may not accurately reflect the aabb areas involved, but the concept that a given contact between two bodies results in a range of possibilities, therefore creating a larger black square, makes sense to me.
Also, if you run the intersection lab, the same code seems to give very accurate aabb results…
Also you’ll note that the faster you move the square into the circle’s space the larger the black box becomes.
That seems consistent.
@UberGoober I don’t think so. I’m barely moving the square into the circle and the black area increases in size as I move the square. Also, it only sometimes does it after I run the square into the other square and then into the circle. It should do it consistently if that’s how it works. I can agree that the faster you move the object, the more the aabb area will be behind the object. I would say that’s caused by the lag in calculating the aabb area and the position of the object. The aabb area is calculated where the object used to be. The only problem with trying to verify that, is the object is moving too fast to do anything to check it. The aabb area is calculated with the lower left and upper right x,y values. Those remain the same relative to the moving object, so I can’t see how the bounding area is going to change for the object.
@dave1707 I’m not sure if you’re getting, or if you’re getting and rejecting, the concept that aabb incorporates movement.
It’s not lag, it’s intentional, that’s how it’s supposed to work, at least as far as that SO article I linked to.
@UberGoober From what I’ve found so far, aabb will alter it size ( recalculate it’s area in the direction it’s moving ) to account for fast moving objects. It will also alter its position after a collision to reposition the object so fast moving objects aren’t overlapping each other at collision. So the increased bounding area will be in front or behind the moving object depending on what’s happening. I haven’t found any info about the bounding area increasing in size to each side. In your example, I was barely moving the square into the circle and the black area was increasing in size all around the square. That’s what I don’t think should be happening.
@dave1707 that makes sense
Have any idea why the objects only sometimes collide??
@dave1707 i just realized, one thing that could account for a larger box from even a small touch is the potential for rotation. If aabb queries take into account potential rotation as well as potential motion then even a small contact could create a larger box.
@dave1707 I think that hunch turned out to be at least partially correct.
I added a proper physics body drawer from PhysicsLab, so we can see what’s actually going on, and while it doesn’t fully explain the size of the boxes, it seems clear that box size expansion is linked to body rotation.
viewer.mode=OVERLAY
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,0))
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
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
tx=t.x
ty=t.y+150
r2.position = vec2(tx, ty)
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
I think my aabb drawing technique seems to be working—also please check out how it looks on all the default PhysicsLab projects included with IntersectionLab—and that any results that look odd are not the code being wrong, they’re us not understanding the reason for the results.
@UberGoober That looks nice, but I haven’t looked at why the collision isn’t happening all the time. Maybe while I’m watch football this afternoon, I’ll look thru your code.
I think the problem with the collisions is because you’re overriding the physics engine by moving the square with the touch function. Need to move it using applyForce so the physics code is doing everything.