Circle V Rectangle Collision Response
Posted: Tue Oct 20, 2020 6:43 pm
Hi, I'm trying to make basic physics simulations. I implemented Coding Math's Verlet Integration Tutorial to my project and I wanted to add a rectangle to interact with. Problem is, I don't know how to handle circle V rectangle collision.
First I tried to make a solid rectangle. It went decently good and made circle couldn't pass through it. Though I don't know if its the right way. (collision detection script implemented from here):
Then I wanted to make circle bounce whenever it intersect with rectangle and that went pretty bad...
My whole Lua code looks like this (both intersection codes included):
I also had some understanding issues with Verlet Integration. It looks like oldx and oldy variables are used like velocity properties. Couldn't we just use velocity values? Thank you for your interest.
First I tried to make a solid rectangle. It went decently good and made circle couldn't pass through it. Though I don't know if its the right way. (collision detection script implemented from here):
Code: Select all
function collision()
local testX = circle.x
local testY = circle.y
if circle.x < rect.x then
testX = rect.x
elseif circle.x > rect.x + rect.w then
testX = rect.x + rect.w
end
if circle.y < rect.y then
testY = rect.y
elseif circle.y > rect.y + rect.h then
testY = rect.y + rect.h
end
local distX = circle.x - testX
local distY = circle.y - testY
local distance = math.sqrt(distX ^ 2 + distY ^ 2)
if distance <= circle.rad then
--COLLISION RESPONSE-----
local unitX, unitY = distX / distance, distY / distance
circle.x = testX + circle.rad * unitX
circle.y = testY + circle.rad * unitY
end
end
Code: Select all
function collision()
local testX = circle.x
local testY = circle.y
if circle.x < rect.x then
testX = rect.x
elseif circle.x > rect.x + rect.w then
testX = rect.x + rect.w
end
if circle.y < rect.y then
testY = rect.y
elseif circle.y > rect.y + rect.h then
testY = rect.y + rect.h
end
local distX = circle.x - testX
local distY = circle.y - testY
local distance = math.sqrt(distX ^ 2 + distY ^ 2)
if distance <= circle.rad then
--COLLISION RESPONSE-----
local unitX, unitY = distX / distance, distY / distance
circle.x = testX + circle.rad * unitX
circle.y = testY + circle.rad * unitY
if circle.x < rect.x then
circle.oldx = circle.x + vx * bounce
elseif circle.x > rect.x + rect.w then
circle.oldx = circle.x + vx * bounce
end
if circle.y < rect.y then
circle.oldy = circle.y + vy * bounce
elseif circle.y > rect.y + rect.h then
circle.oldy = circle.y + vy * bounce
end
-------------------------
return true
else
return false
end
end
Code: Select all
mouse = love.mouse
graphics = love.graphics
keyboard = love.keyboard
local rect = {
x = 300,
y = 200,
w = 200,
h = 100,
}
local circle = {
x = 10,
y = 10,
oldx = 5,
oldy = 5,
rad = 30,
speed = 30,
}
local bounce = 0.9
local gravity = 0.5
local friction = 0.999
function collision()
local testX = circle.x
local testY = circle.y
if circle.x < rect.x then
testX = rect.x
elseif circle.x > rect.x + rect.w then
testX = rect.x + rect.w
end
if circle.y < rect.y then
testY = rect.y
elseif circle.y > rect.y + rect.h then
testY = rect.y + rect.h
end
local distX = circle.x - testX
local distY = circle.y - testY
local distance = math.sqrt(distX ^ 2 + distY ^ 2)
if distance <= circle.rad then
--COLLISION RESPONSE-----
local unitX, unitY = distX / distance, distY / distance
circle.x = testX + circle.rad * unitX
circle.y = testY + circle.rad * unitY
if circle.x < rect.x then
circle.oldx = circle.x + vx * bounce
elseif circle.x > rect.x + rect.w then
circle.oldx = circle.x + vx * bounce
end
if circle.y < rect.y then
circle.oldy = circle.y + vy * bounce
elseif circle.y > rect.y + rect.h then
circle.oldy = circle.y + vy * bounce
end
-------------------------
return true
else
return false
end
end
function love.update(dt)
--circle.x, circle.y = mouse.getPosition()
vx, vy = (circle.x - circle.oldx) * friction, (circle.y - circle.oldy) * friction
circle.oldx, circle.oldy = circle.x, circle.y
circle.x, circle.y = circle.x + vx, circle.y + vy + gravity
if circle.x + circle.rad > graphics.getWidth() then
circle.x = graphics.getWidth() - circle.rad
circle.oldx = circle.x + vx * bounce
elseif circle.x < 0 then
circle.x = 0
circle.oldx = circle.x + vx * bounce
end
if circle.y + circle.rad > graphics.getHeight() then
circle.y = graphics.getHeight() - circle.rad
circle.oldy = circle.y + vy * bounce
elseif circle.y < 0 then
circle.y = 0
circle.oldy = circle.y + vy * bounce
end
if keyboard.isDown("left") then
circle.x = circle.x - circle.speed * dt
elseif keyboard.isDown("right") then
circle.x = circle.x + circle.speed * dt
end
end
function love.keypressed(key)
if key == "escape" then
love.event.quit()
end
if key == "space" then
circle.y = circle.y - 10
end
end
function love.draw()
graphics.setColor(255, 255, 255)
graphics.rectangle("fill", rect.x, rect.y, rect.w, rect.h)
graphics.print("Circle X: " .. circle.x .. "\nCircle Y: " .. circle.y, 10, 10)
if collision() then
graphics.setColor(255, 40, 40)
else
graphics.setColor(0, 255, 255)
end
graphics.circle("fill", circle.x, circle.y, circle.rad)
end