# Trampoline and ball

Shows how to incorporate verlet into box2D physics, could be used for a game.

``````
--# Main
-- Trampoline

-- Use this function to perform your initial setup
function setup()
strings = {}
for i=1,1 do
strings[i] = Rope(vec2(0,100*-i+600),vec2(WIDTH-0,100*-i+600),50)
end
parameter.watch("1/DeltaTime")
ball = physics.body(CIRCLE,60)
ball.position = vec2(WIDTH/2,HEIGHT*0.8)
ball.restitution = 0.9
walls = physics.body(CHAIN,true,vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))
end

function angleOfPoint(pnt)
return math.atan2(pnt.y,pnt.x)
end
function touched(t)
ball.position = vec2(t.x,t.y)
if t.state == MOVING then
ball.linearVelocity = vec2(t.deltaX,t.deltaY)*20
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
for k,v in pairs(strings) do
v:draw()
end
end

--# Rope
Rope = class()

function Rope:init(pos1,pos2,segamnt)
-- you can accept and set parameters here
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()
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.01),0.01,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 d=1,4 do
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+grav-prevpos)
da = (maxl-va:len())/va:len()
ea = va:len()-maxl
vb = (pos+grav-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
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
if ball:testPoint(pos) then
local dir = pos-ball.position
end
self.prevnt = DeltaTime
segtbl[i].ang = angleOfPoint(pos-prevpos)+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
len = (p:dist(self.p2))
end
self.m:draw()
end
``````

Enjoy!

And a different one updated with friction for the balls:

``````
--# Main
-- Trampoline

-- Use this function to perform your initial setup
function setup()
strings = {}
for i=1,1 do
strings[i] = Rope(vec2(0,100*-i+600),vec2(WIDTH-0,100*-i+600),40)
end
parameter.watch("1/DeltaTime")
ball = {}
for i=1,5 do
ball[i] = physics.body(CIRCLE,math.random(30,30))
ball[i].position = vec2(30*i,HEIGHT*0.8)
ball[i].restitution = 0.25
ball[i].gravityScale = 0
end
walls = physics.body(CHAIN,true,vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))
tchs = {}
end

function angleOfPoint(pnt)
return math.atan2(pnt.y,pnt.x)
end
function touched(t)
if t.state == BEGAN then
table.insert(tchs,t)
end
for k,v in pairs(tchs) do
if v.id == t.id then
tchs[k] = t
if t.state == ENDED then
table.remove(tchs,k)
end
end
end
if #tchs == 1 then
strings[1].p1 = vec2(tchs[1].x,tchs[1].y)
end
if #tchs == 2 then
strings[1].p1 = vec2(tchs[1].x,tchs[1].y)
strings[1].p2 = vec2(tchs[2].x,tchs[2].y)
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
for i=1,#ball do
ball[i]:applyForce(vec2(Gravity.x,Gravity.y)*40)
ball[i]:applyForce(vec2(UserAcceleration.x,UserAcceleration.y)*-350)
end
-- Do your drawing here
for k,v in pairs(strings) do
v:draw()
end
end

--# Rope
Rope = class()

function Rope:init(pos1,pos2,segamnt)
-- you can accept and set parameters here
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()
local p,dpos,len,va,da,ea,vb,db,eb,grav,stiffness,dt,nt,np,delta
local vd,vdl,diff
grav,stiffness,nt = -vec2(Gravity.x,Gravity.y)*0.01,0.01,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 d=1,4 do
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
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
for j=1,#ball do
if ball[j]:testPoint(pos) then
local dir = pos-ball[j].position
ball[j].linearVelocity/60+(segi.prev-pos)*0.1,pos)
end
end
segi.prev = pos+grav
self.prevnt = DeltaTime
segtbl[i].ang = angleOfPoint(pos-prevpos)+math.pi/2
dpos = (prevpos+segi.pos)/2
len = (prevpos:dist(segi.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
len = (p:dist(self.p2))