# physics joint-ROPE

Here’s an example of a physics ROPE joint that I have. Touch near the rope ends to move them. You’re not exactly moving the rope ends, you’re just altering their speed and direction. So depending on the tension of the rope, sometimes the end will move easily, sometimes it takes more force to move it where you want. Once you lift your finger, the rope end will stay at that position. It’s kind of interesting to loop the rope and watch it react.

``````
displayMode(FULLSCREEN)

function setup()
t1,t2=0,0   -- id for rope ends
tab={}  -- table of physics bodies
jnt={}  -- table of joints
j=200   -- number of joints
len=(WIDTH-20)/j    -- length between joints
for z=1,j do    -- create bodies
a = physics.body(CIRCLE,0)
a.x = 10+z*len
a.y = HEIGHT-100
if z==1 or z==j then
a.type=STATIC   -- lock end points of rope
end
table.insert(tab,a) -- add bodies to table
if z>1 then -- create joint information and put in table
table.insert(jnt,physics.joint(ROPE,tab[z-1],tab[z],tab[z-1].position,
tab[z].position,5))
end
end
end

function draw()
background(40, 40, 50)
fill(255)
text("Physics Joint (Rope)",WIDTH/2,HEIGHT-50)
text("Touch near a rope end to move it.",WIDTH/2,HEIGHT-80)
strokeWidth(2)
for z=2,#tab do
stroke(255)
if z%2==0 then  -- alternate white and red colors
stroke(255,0,0)
end
line(tab[z].x,tab[z].y,tab[z-1].x,tab[z-1].y)   -- draw line between joints
end
noStroke()
fill(255,0,0)
ellipse(tab[1].x,tab[1].y,10)   -- draw circles for rope end
fill(0,255,0)
ellipse(tab[j].x,tab[j].y,10)
end

function touched(t)
if t.state==BEGAN then
-- find which rope end is closest to the touch
v1=vec2(t.x,t.y)
d1=v1:dist(vec2(tab[1].x,tab[1].y)) -- distance to red end
d2=v1:dist(vec2(tab[j].x,tab[j].y)) -- distance to green end
if d2<d1 then
t2=t.id -- set to move green end
elseif t1==0 then
t1=t.id -- set to move red end
end
end
if t.state==MOVING then -- move red or green end
if t.id==t1 then  -- red end
tab[1].type=DYNAMIC -- make end movable
-- change linear velocity of red end
tab[1].linearVelocity=vec2(t.deltaX*200,t.deltaY*200)
end
if t.id==t2 then  -- green end
tab[j].type=DYNAMIC -- make end movable
-- change linear velocity of green end
tab[j].linearVelocity=vec2(t.deltaX*200,t.deltaY*200)
end
end
if t.state==ENDED then  -- lock ends to current positions
if t.id==t1 then
tab[1].type=STATIC  -- make end stop
t1=0
else
tab[j].type=STATIC  -- make end stop
t2=0
end
end
end

``````

Never thought of using more than one rope joint!
Here’s my rope class renderer method for rope joints using verlet:

``````Rope = class()

function Rope:init(joint,segamnt)
-- you can accept and set parameters here
local pos1,pos2 = joint.anchorA,joint.anchorB
self.id = level.ropes:amount() + 1
self.joint = joint
self.p1 = pos1
self.p2 = pos2
self.m = mesh()
self.r = {}
self.dst = pos1:dist(pos2)
self.segamnt = segamnt
self.prevnt = DeltaTime
self.seglen = (self.dst/segamnt)*0.7
self.segtbl = {}
for i=1,segamnt do
self.segtbl[i] = {}
self.segtbl[i].pos = pos1+(pos2-pos1):normalize()*self.seglen*i
self.segtbl[i].prev = self.segtbl[i].pos
self.segtbl[i].next = self.segtbl[i].pos +vec2(0,-5)
self.segtbl[i].ang = 0
end
self.i = 0
end

function Rope:draw()
self.p1 = self.joint.anchorA
self.p2 = self.joint.anchorB
local p,dpos,len,va,da,ea,vb,db,eb,grav,stiffness,dt,nt,np,delta
local vd,vdl,diff
grav,stiffness,nt = vec2(0,0.1),5,DeltaTime
local segamnt = self.segamnt
local segtbl = self.segtbl
local maxl = self.seglen
local prevpos = vec2()
local nextpos = vec2()
local pos = vec2()
local segi = nil
for i=1,segamnt do
segi = segtbl[i]
pos = segi.pos
if i==1 then
prevpos = self.p1
nextpos = segtbl[i+1].pos
elseif i==segamnt then
prevpos = segtbl[i-1].pos
nextpos = self.p2
else
prevpos = segtbl[i-1].pos
nextpos = segtbl[i+1].pos
end
if not pos or not prevpos or not nextpos then level.ropes:removeRope(self.id) return end
va = (pos-prevpos)
da = (maxl-va:len())/va:len()
ea = va:len()-maxl
vb = (pos-nextpos)
db = (maxl-vb:len())/vb:len()
eb = vb:len()-maxl
dt = (va*stiffness*da+vb*stiffness*db)
if dt:len() > 0 then
np = (pos-segtbl[i].prev) *(nt/self.prevnt) +(dt)*nt*nt
segi.pos = segi.pos + np
end
if i == segamnt then
vd = self.p2-segi.pos
vdl = vd:len()
diff = vdl-maxl
vd = vd:normalize()
if vd:len()>0 then
segtbl[i].pos = segtbl[i].pos + vd*diff*0.5
end
end
if i > 1 then
vd = segtbl[i].pos-segtbl[i-1].pos
vdl = vd:len()
diff = vdl-maxl
vd = vd:normalize()
if vd:len()>0 then
segi.pos = segi.pos - vd*diff*0.5
segtbl[i-1].pos = segtbl[i-1].pos + vd*diff*0.5
end
elseif i==1 then
vd = segi.pos-self.p1
vdl = vd:len()
diff = vdl-maxl
vd = vd:normalize()
if vd:len()>0 then
segi.pos = segi.pos - vd*diff*0.5
end
end

segi.prev = pos+grav
pos = segi.pos
self.prevnt = DeltaTime
segtbl[i].ang = angleOfPoint(pos-prevpos)/mp+math.pi/2
dpos = (prevpos+pos)/2
len = (prevpos:dist(pos))
self.m:setRect(self.r[i],dpos.x,dpos.y,5,len,segtbl[i].ang)
end
self.segtbl = segtbl
p = segtbl[segamnt].pos
dpos = (p+self.p2)/2
len = (p:dist(self.p2))
self.m:setRect(self.r[segamnt+1],dpos.x,dpos.y,5,len,angleOfPoint(p-self.p2)/mp+math.pi/2)
self.m:draw()
end
``````

Gets to be quite slow with about 10 ropes though… Easy to implement just put the rope joint and segment amount in. I haven’t accounted for the change of maxLength because of the bugs

Here’s a rope class based on my above code. The parameters are: the x,y position of where the rope starts, the x,y position where it ends, the number of segments, and the length of each segment. This example draws 6 ropes. They don’t do much except hang around.

``````
displayMode(FULLSCREEN)

function setup()
rp={}
for r=1,6 do
table.insert(rp,rope(math.random(WIDTH/2),math.random(HEIGHT/2,HEIGHT),
math.random(WIDTH/2,WIDTH),math.random(HEIGHT/2,HEIGHT),100,10))
end
end

function draw()
background(40, 40, 50)
for a,b in pairs(rp) do
b:draw()
end
end

rope=class()

function rope:init(sx,sy,ex,ey,nbr,len)
self.tab={} -- table of objects
self.jnt={} -- table of joints
self.sx=sx  -- start x,y
self.sy=sy
self.ex=ex  -- end x,y
self.ey=ey
self.nbr=nbr    -- number of segments
self.len=len    -- length of segments
self.dx=(self.ex-self.sx)/self.nbr
self.dy=(self.ey-self.sy)/self.nbr
for z=1,self.nbr do    -- create bodies
a = physics.body(CIRCLE,0)
a.x = self.sx+z*self.dx
a.y = self.sy+z*self.dy
if z==1 or z==self.nbr then
a.type=STATIC   -- lock end points of rope
end
table.insert(self.tab,a) -- add bodies to table
if z>1 then -- create joint information and put in table
table.insert(self.jnt,physics.joint(ROPE,self.tab[z-1],self.tab[z],
self.tab[z-1].position,self.tab[z].position,self.len))
end
end
end

function rope:draw()
strokeWidth(2)
for z=2,#self.tab do
stroke(255)
if z%2==0 then  -- alternate white and red colors
stroke(255,0,0)
end
-- draw line between joints
line(self.tab[z].x,self.tab[z].y,self.tab[z-1].x,self.tab[z-1].y)
end
-- draw rope end points
noStroke()
fill(255,0,0)
ellipse(self.tab[1].x,self.tab[1].y,10)   -- draw circles for rope end
fill(0,255,0)
ellipse(self.tab[self.nbr].x,self.tab[self.nbr].y,10)
end

``````