Skip to content

Instantly share code, notes, and snippets.

@JesterXL
Created June 15, 2013 13:34
Show Gist options
  • Save JesterXL/5788150 to your computer and use it in GitHub Desktop.
Save JesterXL/5788150 to your computer and use it in GitHub Desktop.
Corona SDK Verlet Ropes
-- Verlet class at bottom, save to separate file called "Verlet.lua"
require "physics"
local Verlet = require "Verlet"
display.setStatusBar( display.HiddenStatusBar )
--physics.setDrawMode("hybrid")
physics.start()
physics.setGravity(0, 9.8)
physics.setPositionIterations( 10 )
function getGrapplePoint()
local point = display.newRect(0, 0, 10, 10)
physics.addBody(point,"static", {density = 1, friction = .5, bounce = .1})
return point
end
function getMetalSphere(r)
local sphere = display.newCircle(0, 0, r)
physics.addBody(sphere, "dynamic", {density=3, radius=r, bounce=0.0, friction=0.7})
return sphere
end
local function testingRope2()
local point1 = getGrapplePoint()
point1.x = 100
point1.y = 100
local point2 = getGrapplePoint()
point2.x = 300
point2.y = 200
local sphere = getMetalSphere(20)
sphere.x = 0
sphere.y = 200
local mappedX, mappedY = sphere:contentToLocal(sphere.x + 2, sphere.y - sphere.height / 2)
local rope1 = physics.newJoint("rope", sphere, point1, mappedX, mappedY)
-- now watch the bounce (elsaticity more accurate) of a distance joint
local sphere2 = getMetalSphere(20)
sphere2.x = 200
sphere2.y = 300
local distance = physics.newJoint("distance", sphere2, point2, sphere2.x, sphere2.y, point2.x, point2.y)
distance.length = 200
distance.frequency = 0.7
distance.dampingRatio = 0
local visualRope1 = Verlet:new(point1, sphere)
local visualRope2 = Verlet:new(point2, sphere2)
-- finally, MOVE 'EM UP!
local t = {}
t.speed = 5
function t:timer()
if rope1.maxLength > 20 then
rope1.maxLength = rope1.maxLength - self.speed
end
if distance.length > 20 then
distance.length = distance.length - self.speed
end
end
-- t.id = timer.performWithDelay(10, t, 0)
local function startDrag( event )
local t = event.target
local phase = event.phase
if "began" == phase then
display.getCurrentStage():setFocus( t )
t.isFocus = true
-- Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
-- Make body type temporarily "kinematic" (to avoid gravitional forces)
event.target.bodyType = "kinematic"
-- Stop current motion, if any
event.target:setLinearVelocity( 0, 0 )
event.target.angularVelocity = 0
elseif t.isFocus then
if "moved" == phase then
t.x = event.x - t.x0
t.y = event.y - t.y0
elseif "ended" == phase or "cancelled" == phase then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
t.bodyType = "dynamic"
end
end
-- Stop further propagation of touch event!
return true
end
sphere:addEventListener("touch", startDrag)
sphere2:addEventListener("touch", startDrag)
end
testingRope2()
-- if you want more bounce/slack, play with the stick's contract method, like changing the .5 to higher, or lower
-- or making the x and y values different.
-- Also, in the enterframe, you can change the 4 to different #'s to get a more slack wire
local Verlet = {}
function Verlet:new(startPoint, endPoint)
local verlet = display.newGroup()
verlet.startPoint = startPoint
verlet.endPoint = endPoint
function verlet:init()
local TOTAL = 10
local points = {}
local sticks = {}
self.points = points
self.sticks = sticks
local w = TOTAL * 10
local startPoint = self.startPoint
local i = 1
while i < TOTAL do
local vpoint = self:getVPoint(startPoint.x, startPoint.y)
table.insert(points, vpoint)
if i > 1 then
local stick = self:getVStick(points[i - 1], points[i])
table.insert(sticks, stick)
end
i = i + 1
end
Runtime:addEventListener("enterFrame", self)
end
function verlet:clearLines()
local len = self.numChildren
while len > 0 do
local line = self[len]
line:removeSelf()
len = len - 1
end
end
function verlet:getVPoint(x, y)
local point = {}
point.classType = "VPoint"
function point:setPos(x, y)
-- assert(x == x)
-- assert(y == y)
self.x = x
self.y = y
self.oldX = x
self.oldY = y
--print("initial:, x:", self.x, ", y:", self.y)
-- assert(self.x == self.x)
-- assert(self.y == self.y)
-- assert(self.oldX == self.oldX)
-- assert(self.oldY == self.oldY)
end
function point:refresh()
local tempX = self.x
local tempY = self.y
local oldOldX = self.oldX
local oldOrigX = self.x
local diffX = self.x - self.oldX
self.x = self.x + (self.x - self.oldX)
self.y = self.y + (self.y - self.oldY)
self.oldX = tempX
self.oldY = tempY
-- assert(self.x == self.x, "Failed, oldOldX: " .. oldOldX .. ", vs oldOrigX: " .. oldOrigX .. ", diffX: " .. diffX)
-- assert(self.y == self.y)
-- assert(self.oldX == self.oldX)
-- assert(self.oldY == self.oldY)
end
point:setPos(x, y)
return point
end
function verlet:getVStick(pointA, pointB)
local stick = {}
stick.pointA = pointA
stick.pointB = pointB
local dx = pointA.x - pointB.x;
local dy = pointA.y - pointB.y;
stick.hyp = math.sqrt(dx * dx + dy * dy);
function stick:contract()
local dx = self.pointB.x - self.pointA.x
local dy = self.pointB.y - self.pointA.y
local h = math.sqrt(dx * dx + dy * dy)
local diff = self.hyp - h
local offx = (diff * dx / h) * .5
local offy = (diff * dy / h) * .5
--print("dx:", dx, ", dy:", dy)
--print("h:", h, ", diff:", diff)
--print("offx:", offx, ", offy:", offy)
self.pointA.x = self.pointA.x - offx
self.pointA.y = self.pointA.y - offy
self.pointB.x = self.pointB.x + offx
self.pointB.y = self.pointB.y + offy
--Runtime:dispatchEvent({name="VPoint_changed", target=self})
end
return stick
end
function verlet:enterFrame()
local points = self.points
local sticks = self.sticks
local startPoint = self.startPoint
local endPoint = self.endPoint
local startX = startPoint.x
local startY = startPoint.y
local endX = endPoint.x
local endY = endPoint.y
local t = #points
local i = 1
points[1]:setPos(endX, endY)
points[#points]:setPos(startX, startY)
while points[i] do
local point = points[i]
point.y = point.y + 4
point:refresh()
i = i + 1
end
t = #sticks
i = 1
while sticks[i] do
local stick = sticks[i]
stick:contract()
i = i + 1
end
self:clearLines()
i = 1
while i < t do
local stick = sticks[i]
local line = display.newLine(self, stick.pointA.x, stick.pointA.y, stick.pointB.x, stick.pointB.y)
line.width = 3
line:setColor(255, 0, 0)
--print("pos:", stick.pointA.x, stick.pointA.y, stick.pointB.x, stick.pointB.y)
i = i + 1
end
return true
end
verlet:init()
return verlet
end
return Verlet
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment