Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I don't know how to react to collisions between two axis aligned rectangles that have x, y, width and height values (x and y are from the centre of the box) to make them simply not overlap.

I figured I'd just make them move away from each other depending on how far they intersect in the opposite direction (left, right, up or down) of where they collided. If I check for collisions only on the x axis or only on the y axis it works fine, but when checking for both collisions crazy stuff happens.

This code executes when the first box collides with the second. It's in lua but feel free to answer in anything that isn't to too counter-intuitive.

if box1.x < box2.x then
    box1.x = box2.x - (box1.width / 2) - (box2.width / 2)
end

if box1.x > box2.x then
    box1.x = box1.x - (box1.x - box2.x - (box1.width / 2) - (box2.width / 2))
end

if box1.y < box2.y then
    box1.y = box2.y - (box1.height / 2) - (box2.height / 2)
end

if box1.y > box2.y then
    box1.y = box1.y - (box1.y - box2.y - (box1.height / 2) - (box2.height / 2))
end
share|improve this question

1 Answer 1

The thing is that the boxes only actually overlap if they overlap on both axes. You can therefore compute the overlap on both axes, then decide whether to move the boxes.

First compute how far apart the box centres are:

local dx = box2.x - box1.x
local dy = box2.y - box1.y

Then compute how far apart they should be at least (in absolute value):

local dw = (box2.width + box1.width) / 2
local dh = (box2.height + box1.height) / 2

Now a bit of maths tells us the excess in both directions:

local movex = math.max(dw - math.max(dx, 0), 0) - math.max(dw + math.min(dx, 0), 0)
local movey = math.max(dh - math.max(dy, 0), 0) - math.max(dh + math.min(dy, 0), 0)

And you can finally move the boxes away from each other if needed, either in the X or in the Y direction. If both movex and movey are zero then the boxes don't move:

if math.abs(movex) <= math.abs(movey) then
    box1.x -= movex / 2
    box2.x += movex - movex / 2
else
    box1.y -= movey / 2
    box2.y += movey - movey / 2
end
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.