## Rope Physics Help

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
pgimeno
Party member
Posts: 2132
Joined: Sun Oct 18, 2015 2:58 pm

### Rope Physics Help

I'm trying to model a rope, but so far I have been unsuccessful. It doesn't behave quite like a rope.

The rope is modelled by using multiple line segments. It's an isolated main.lua file so I can work out the details comfortably.

I'm pretty sure I'm calculating the forces wrong. Just in case, I'm calculating the centre of mass of all the segments starting from the last, because I felt it was important, but I couldn't do anything useful with it so I can remove it if it's not used.

I'm using Verlet integration because of its simplicity.

Can someone help me with the force calculation?

Code: Select all

local ropeNSegs = 15
local ropeSegLen = 30
local ropeSegMass = 1
local gravity = 100
local dragx, dragy = 0.001, 0.001

local rope = {}
local pts = {400, 50}

-- Uncomment for having a stable testcase for debugging
--love.math.setRandomSeed(8)

for i = 1, ropeNSegs do
local angle = love.math.random() * (math.pi - 0.2) + 0.1
local seg = {
x = math.cos(angle) * ropeSegLen,
y = math.sin(angle) * ropeSegLen,
oldx = 0,
oldy = 0
}
-- Initialize to zero velocity
seg.oldx = seg.x
seg.oldy = seg.y
rope[i] = seg
end
love.graphics.setLineJoin("none")
end

function love.update(dt)
local dt2 = dt * dt * 0.5

-- nsegs is the number of segments hanging from this pivot
-- 1 for rope[ropeNSegs], 2 for rope[ropeNSegs-1] etc.
-- Remember the segments are expressed as vectors.
local nsegs = 1
-- SumX/Y is the running sum of all the individual CoMs so far
local SumX = 0
local SumY = 0
-- Loop in reverse
for i = ropeNSegs, 1, -1 do
local seg = rope[i]
-- The minus 0.5 gives us a point in the centre of the segment
SumX = SumX + seg.x * (nsegs - 0.5)
SumY = SumY + seg.y * (nsegs - 0.5)

-- Centre of mass relative to this pivot point
local CoMX = SumX / nsegs
local CoMY = SumY / nsegs

-- Calculate the force on this pivot
local ForceX = 0
local ForceY = nsegs * ropeSegMass * gravity

-- Apply Verlet to this endpoint, with mass ropeSegMass * nsegs
local newsegx = seg.x +  (seg.x - seg.oldx) * (1 - dragx) + ForceX / (nsegs * ropeSegMass) * dt2
local newsegy = seg.y + ((seg.y - seg.oldy) * (1 - dragy) + ForceY / (nsegs * ropeSegMass) * dt2)

-- Constrain length
local seglen = math.sqrt(newsegx^2 + newsegy^2)
if seglen < 0.00001 then seglen = 1 end
newsegx = newsegx / seglen * ropeSegLen
newsegy = newsegy / seglen * ropeSegLen

-- "Rotate" the values: old <- current <- new
seg.oldx = seg.x
seg.oldy = seg.y
seg.x = newsegx
seg.y = newsegy

nsegs = nsegs + 1
end
end

function love.draw()
for i = 1, ropeNSegs do
pts[i + i + 1] = pts[i + i - 1] + rope[i].x
pts[i + i + 2] = pts[i + i - 0] + rope[i].y
end
love.graphics.line(pts)
end

function love.keypressed(k) if k == "escape" then love.event.quit() end end

Edit: To clarify, what I'm after is a rope that meets these criteria:
1. fast to calculate
2. constrained in length, at least visibly (i.e. doesn't look like a rubber band)
3. somewhat realistic-looking
4. without love.physics
I got 1, 2 and 4, but failed 3.
Last edited by pgimeno on Fri Mar 09, 2018 11:39 am, edited 1 time in total.

lachlaan
Prole
Posts: 30
Joined: Sun Jun 30, 2013 7:23 pm

### Re: Rope Physics Help

It behaves pretty rope like considering it's still line segments in the end. Consider a rope is made up of infinitesimaly small segments and there's rotation/bend tension between every single small segment you could pick. That could be a thing your rope is lacking, segments being too long and acting as tiny pendulums while not looking as curvy, as well as a lack of rotational/bend friction or resistance that'd make it smooth out sooner.

Having stared at it a bit it seems fairly okay. About as accurate as you can get a bunch of segments. Make it so it falls down from a position closer to the side so you see it swing. If you think of letting a rope uncoil all of a sudden it'd do mostly what your segments are doing and accordeon as they distribute the wave along the length. The one force to look out would be that, the rotational tension/friction. You have some sort of x and y component of drag but i'm not sure it's what you're looking for, it just slows it all down.

pgimeno
Party member
Posts: 2132
Joined: Sun Oct 18, 2015 2:58 pm

### Re: Rope Physics Help

Thanks for your input. I know it's possible to do better using segments. https://gamedev.stackexchange.com/quest ... reate-rope

Of course my segments will be shortened in the final version; this is a sort of debug version. Adding more segments and making them shorter doesn't help; it's nothing like the animated gif in the link above. Multiplying the vertical force by nsegs seems to help a bit, but not enough. It still doesn't feel realistic.

I feel it fails the "pendulum law" where the period of the segments that are higher up should be roughly longer than the ones lower down. In other words, the lower end should wiggle more than the top.

lachlaan
Prole
Posts: 30
Joined: Sun Jun 30, 2013 7:23 pm

### Re: Rope Physics Help

That guy mentions he handles it like a spring, so perhaps you're omitting the tension of each segment on the segments below them, pulling back upward, rather than the segments themselves just being constrained to dangle from the above joint without being affected by it much?

Basically he said it pulls up on each joint provided there's an opposing force, otherwise it dangles loosely.

Edit: Also sorry for the lazy replies, it's a fascinating thing to think about but i'm too lazy atm to remember how2physics xD

Ostego160
Prole
Posts: 14
Joined: Tue Oct 17, 2017 7:18 pm

### Re: Rope Physics Help

Hi,

Attached is a rope simulator that I threw together using verlet integration. Its very imperfect and not time stepped but the effect is decent.
verlet.love
Hope this helps!

pgimeno
Party member
Posts: 2132
Joined: Sun Oct 18, 2015 2:58 pm

### Re: Rope Physics Help

Thank you. That rope looks more natural, but it looks too much like a rubber band with a weight or something like that. I've updated the OP with the criteria I am aiming for.

Your rope meets 1, 3 and 4 but fails 2. A search in the forums revealed this thread, which looks great: viewtopic.php?f=5&t=12330 but a look at the code shows that it meets 2, 3 and 4 but it fails 1 because it applies 40 iterations to every node every frame.

I've also found several attempts using physics, which fail 4.

@lachlaan I'm pretty sure it's that, but I don't see how to apply that force there. Perhaps my model of having a chain of relative vectors instead of absolute positions is not a good idea.

Edit: I've tried with love.physics and it's quite straightforward. I guess people having trouble with this are using the wrong approach regarding bodies/joints, as I've seen them use of DistanceJoint or RopeJoint. Making the body a thin rectangle for the segment (with some damping to avoid too much wiggle), and the joint be a simple revolute joint, the effect is satisfactory; unfortunately, that doesn't help me because I need to do it without physics.

Code: Select all

--local drawWorld = require 'debugWorldDraw_mod'
local world

local ropeNSegs = 15
local ropeSegLen = 30
local ropeSegMass = 1
local gravity = 10
local dragx, dragy = 0.001, 0.001
local k = 200

local rope = {}

world = love.physics.newWorld(0, 1000)
local posx = 400
local posy = 50
rope[0] = {}
rope[0].body = love.physics.newBody(world, posx, posy, "static")
for i = 1, ropeNSegs do
local angle = love.math.random() * (math.pi - 0.2) + 0.1
local seg = {}
local newposx = posx + math.cos(angle) * ropeSegLen
local newposy = posy + math.sin(angle) * ropeSegLen
seg.body = love.physics.newBody(world, newposx, newposy, "dynamic")
seg.shape = love.physics.newPolygonShape(0, -0.1, 0, 0.1, -ropeSegLen, 0.1, -ropeSegLen, -0.1)
seg.body:setAngle(angle)
seg.fix = love.physics.newFixture(seg.body, seg.shape, 1)
seg.joint = love.physics.newRevoluteJoint(seg.body, rope[i-1].body, posx, posy)
seg.body:setLinearDamping(0.1)
seg.body:setAngularDamping(10)
rope[i] = seg
posx = newposx
posy = newposy
end
end

function love.update(dt)
world:update(dt)
end

function love.draw()
--  love.graphics.clear(255,255,255)
--  drawWorld(world, 0, 0, 800, 600)
local line = love.graphics.line
for i = 1, ropeNSegs do
local body = rope[i].body
local angle = body:getAngle()
local posx, posy = body:getPosition()
local prevposx = posx - math.cos(angle) * ropeSegLen
local prevposy = posy - math.sin(angle) * ropeSegLen
line(posx, posy, prevposx, prevposy)
end
end


NotARaptor
Citizen
Posts: 59
Joined: Thu Feb 22, 2018 3:15 pm

### Re: Rope Physics Help

I just threw this together quickly - looks to be pretty rope-ish to me, doesn't rely on love.physics.
screenshot.png (28.04 KiB) Viewed 2886 times
It doesn't do collisions or anything, but that could be added easily enough.

I added two ropes - one has zero drag, the other does have drag, so you can see the difference.

The first point of both ropes is static, the last point can be free or static (hold the spacebar to fix them, release to free them)
rope-test.love
Hope this helps!

UPDATED : Fixed case issue.
Attachments
rope-test.love
Last edited by NotARaptor on Tue Mar 13, 2018 4:30 pm, edited 1 time in total.

pgimeno
Party member
Posts: 2132
Joined: Sun Oct 18, 2015 2:58 pm

### Re: Rope Physics Help

Thanks. That uses the same technique as in the thread I linked. It makes 20 passes. I was aiming for something faster. Reducing the count to 1 pass keeps it fairly realistic but too elastic. Even with the 20 passes the length oscillates a little bit, though not visibly.

I've tried several variations. Switching off vsync makes the damping much more noticeable, which suggests that it needs to be compensated for by using dt. Fixing the lengths after they are altered results in disaster, which makes me think that Verlet is a bad approach for correcting the lengths because it misrepresents the speed in the next timestep. I will try switching to a different integrator.

NotARaptor
Citizen
Posts: 59
Joined: Thu Feb 22, 2018 3:15 pm

### Re: Rope Physics Help

You can adjust the number of passes to suit. Decreasing it a lot will give the rope a more springy feel. But with 50 segments and 50 passes, I could still simulate 100 ropes at 60fps, so it's not slow, and the maths could be optimised, but as a beginner in LUA I'm not sure how best to do it - in C I'd replace the square root with an approximation, for example.

Jasoco
Inner party member
Posts: 3650
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

### Re: Rope Physics Help

NotARaptor wrote:
Fri Mar 09, 2018 2:03 pm
I just threw this together quickly - looks to be pretty rope-ish to me, doesn't rely on love.physics.

screenshot.png

It doesn't do collisions or anything, but that could be added easily enough.

I added two ropes - one has zero drag, the other does have drag, so you can see the difference.

The first point of both ropes is static, the last point can be free or static (hold the spacebar to fix them, release to free them)

rope-test.love

Hope this helps!
ZIP files are case sensitive. You told it to require "Rope". But the file is named "rope". Heads up to anyone downloading this to unzip it and change that code to make it run.

### Who is online

Users browsing this forum: No registered users and 25 guests