Hi! I've been playing around with the Verlet integration API and I have hit a snag.
Based off of the Fantastic Verlet example from this thread, I have setup a rope and ball with cup simulator.
Based on the positions of the first and last nodes, I have set up Love to create a body and a shape corresponding to the cup and ball, accordingly. My understanding is that this talks to the Love2D API and should automatically handle collision, like in the physics tutorial https://love2d.org/wiki/Tutorial:Physics
However, I haven't been able to make it so this registers collisions. I am very certain I am just missing just one little detail. What am I missing?
[Verlet Integration] Cannot add collision in Rope and Ball situation.
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
[Verlet Integration] Cannot add collision in Rope and Ball situation.
- Attachments
-
verlet.love
- (2.83 KiB) Downloaded 179 times
Re: [Verlet Integration] Cannot add collision in Rope and Ball situation.
There are several issues here.
First, love.physics.newPolygonShape has a limit of 8 points, and the polygons must be convex. Yours has more points and isn't convex. You can solve that by using four rectangles and four fixtures for the cup's body.
Second, you made a typo: you used self.objects.ball.body:setY when you should be using self.objects.cup.body:setY (i.e. you used ball instead of cup for the Y coordinate of the cup).
Third, you don't use anything from the love.physics world. You add some objects and move them but never query where they are or anything. You could as well not create the physical world and nothing would change.
Fourth, even if all that were fixed, you can't expect love.physics to react to the collisions if you don't let it move things according to physics. If you want proper collision reaction, you need to let the love.physics world do the movement.
In the thread you've linked, I wanted to avoid love.physics, but since that doesn't seem to be your case, note that you can make a rubber string (or a rigid-ish string) with love.physics.
I can't write an example right now and I'll be busy for about 24 hours, but I'll try to write a PoC as soon as I can.
First, love.physics.newPolygonShape has a limit of 8 points, and the polygons must be convex. Yours has more points and isn't convex. You can solve that by using four rectangles and four fixtures for the cup's body.
Second, you made a typo: you used self.objects.ball.body:setY when you should be using self.objects.cup.body:setY (i.e. you used ball instead of cup for the Y coordinate of the cup).
Third, you don't use anything from the love.physics world. You add some objects and move them but never query where they are or anything. You could as well not create the physical world and nothing would change.
Fourth, even if all that were fixed, you can't expect love.physics to react to the collisions if you don't let it move things according to physics. If you want proper collision reaction, you need to let the love.physics world do the movement.
In the thread you've linked, I wanted to avoid love.physics, but since that doesn't seem to be your case, note that you can make a rubber string (or a rigid-ish string) with love.physics.
I can't write an example right now and I'll be busy for about 24 hours, but I'll try to write a PoC as soon as I can.
Re: [Verlet Integration] Cannot add collision in Rope and Ball situation.
And here it is:
Code: Select all
local metre = 64
local lp = love.physics
local lg = love.graphics
local nSegments = 20
local initialCupX = 400
local initialCupY = 0
local initialBallX = initialCupX
local initialBallY = 500
local function lerp(a, b, t)
return t < 0.5 and a + (b - a) * t or b + (a - b) * (1 - t)
end
local objs = {}
lp.setMeter(metre)
local world = lp.newWorld(0, 9.81*metre, true)
objs.cup = {}
objs.cup.body = lp.newBody(world, initialCupX, initialCupY, "dynamic")
objs.cup.body:setFixedRotation(true) -- don't rotate the cup
-- The position of the rectangle is the centre, not the top left, so we add
-- half the width/height to the top left of each rectangle to get the centre
objs.cup.shapes = {}
objs.cup.shapes[1] = lp.newRectangleShape(-60+20/2, -60+40/2, 20, 40)
objs.cup.shapes[2] = lp.newRectangleShape( 40+20/2, -60+40/2, 20, 40)
objs.cup.shapes[3] = lp.newRectangleShape(-60+120/2, -20+20/2, 120, 20)
objs.cup.shapes[4] = lp.newRectangleShape(-10+20/2, 0+60/2, 20, 60)
objs.cup.fixtures = {}
for i = 1, #objs.cup.shapes do
objs.cup.fixtures[i] = lp.newFixture(objs.cup.body, objs.cup.shapes[i])
-- Don't bounce too much.
objs.cup.fixtures[i]:setRestitution(0.5)
end
-- Add a mouse joint for the cup.
objs.cup.joint = lp.newMouseJoint(objs.cup.body, objs.cup.body:getPosition())
objs.ball = {}
objs.ball.body = lp.newBody(world, initialBallX, initialBallY, "dynamic")
objs.ball.shape = lp.newCircleShape(25)
objs.ball.fixture = lp.newFixture(objs.ball.body, objs.ball.shape)
objs.string = {}
-- Make the string from the bottom of the cup to the ball
local prevX, prevY = initialCupX, initialCupY+60
for i = 1, nSegments-1 do
local segment = {}
local x, y = lerp(initialCupX, initialBallX, i/nSegments),
lerp(initialCupY+60, initialBallY, i/nSegments)
segment.body = lp.newBody(world, x, y, "dynamic")
-- A distance joint has some spring effect already; you can play with
-- DistanceJoint:setFrequency to make it more elastic.
segment.joint = lp.newDistanceJoint(
i == 1 and objs.cup.body or objs.string[i-1].body, segment.body,
prevX, prevY, x, y
)
-- This causes issues, not sure why.
-- segment.shape = lp.newRectangleShape(1, 1)
-- segment.fixture = lp.newFixture(segment.body, segment.shape)
objs.string[i] = segment
prevX, prevY = x, y
end
do
-- Final segment goes from the last body to the ball
local x, y = objs.ball.body:getPosition()
objs.ball.joint = lp.newDistanceJoint(
objs.string[nSegments-1].body, objs.ball.body, prevX, prevY, x, y
)
end
function love.keypressed(k) return k == "escape" and love.event.quit() end
-- Avoid jerks before the mouse is moved for the first time
-- (at the cost of stealing the mouse once)
love.mouse.setPosition(0, 0)
love.event.pump()
love.mouse.setPosition(400, 300)
objs.cup.body:setPosition(400.5, 300.5)
function love.update(dt)
objs.cup.joint:setTarget(love.mouse.getPosition())
world:update(dt)
end
function love.draw()
for i = 1, #objs.cup.shapes do
lg.polygon("line", objs.cup.body:getWorldPoints(objs.cup.shapes[i]:getPoints()))
end
lg.circle("line", objs.ball.body:getX(), objs.ball.body:getY(), objs.ball.shape:getRadius())
for i = 0, nSegments - 1 do
local x1, y1, x2, y2
if i == 0 then
x1, y1 = objs.cup.body:getPosition()
y1 = y1 + 60
else
x1, y1 = objs.string[i].body:getPosition()
end
if i == nSegments - 1 then
x2, y2 = objs.ball.body:getPosition()
else
x2, y2 = objs.string[i+1].body:getPosition()
end
lg.line(x1, y1, x2, y2)
end
end
- Attachments
-
cup_and_ball.love
- (1.57 KiB) Downloaded 200 times
Re: [Verlet Integration] Cannot add collision in Rope and Ball situation.
This is fantastic by the way. I would had liked to use the exact same physics I got from the verlet integration but this approach works, will just tinker some of the parameters to get the right kind of "feel" to it and finish building my game.
Thank you so much, your advice is truly appreciated! You rule.
Thank you so much, your advice is truly appreciated! You rule.
Who is online
Users browsing this forum: Ahrefs [Bot], Google [Bot] and 76 guests