123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- --[[ Wrecking ball suspended from rope. Cyrus-free.
- Making realtime rope simulation is finicky on any physics engine. At certain weight the force becomes
- too much to be successfully distributed among rope elements.
- Some steps that can help solve the issue:
- 1) lower the mass of suspended weight or lower the gravity constant
- 2) increase mass of each rope element, preferably having more mass at top of rope and less mass at bottom
- 3) decrease number of rope elements
- 4) decrease the simulation time step
- 5) modify engine code to use direct solver instead of iterative solver (step() instead of quickStep())
- --]]
- local world
- function lovr.load()
- world = lovr.physics.newWorld(0, -3, 0, false)
- -- ground plane
- local box = world:newBoxCollider(vec3(0, -0.05, 0), vec3(20, 0.1, 20))
- box:setKinematic(true)
- -- hanger
- local hangerPosition = vec3(0, 2, -1)
- local hanger = world:newBoxCollider(hangerPosition, vec3(0.3, 0.1, 0.3))
- hanger:setKinematic(true)
- -- ball
- local ballPosition = vec3(-1, 1, -1)
- local ball = world:newSphereCollider(ballPosition, 0.2)
- -- rope
- local firstEnd, lastEnd = makeRope(
- hangerPosition + vec3(0, -0.1, 0),
- ballPosition + vec3(0, 0.3, 0),
- 0.02, 10)
- lovr.physics.newDistanceJoint(hanger, firstEnd, hangerPosition, vec3(firstEnd:getPosition()))
- lovr.physics.newDistanceJoint(ball, lastEnd, ballPosition, vec3(lastEnd:getPosition()))
- -- brick wall
- local x = 0.3
- local even = true
- for y = 1, 0.1, -0.1 do
- for z = -0.5, -1.5, -0.2 do
- world:newBoxCollider(x, y, even and z or z - 0.1, 0.08, 0.1, 0.2)
- end
- even = not even
- end
- lovr.graphics.setBackgroundColor(0.1, 0.1, 0.1)
- end
- function lovr.update(dt)
- world:update(dt)
- end
- function lovr.draw(pass)
- for i, collider in ipairs(world:getColliders()) do
- local shade = (i - 10) / #world:getColliders()
- pass:setColor(shade, shade, shade)
- local shape = collider:getShapes()[1]
- local shapeType = shape:getType()
- local x,y,z, angle, ax,ay,az = collider:getPose()
- if shapeType == 'box' then
- local sx, sy, sz = shape:getDimensions()
- pass:box(x,y,z, sx,sy,sz, angle, ax,ay,az)
- elseif shapeType == 'sphere' then
- pass:setColor(0.4, 0, 0)
- pass:sphere(x,y,z, shape:getRadius())
- end
- end
- end
- function makeRope(origin, destination, thickness, elements)
- local length = (destination - origin):length()
- thickness = thickness or length / 100
- elements = elements or 30
- elementSize = length / elements
- local orientation = vec3(destination - origin):normalize()
- local first, last, prev
- for i = 1, elements do
- local position = vec3(origin):lerp(destination, (i - 0.5) / elements)
- local anchor = vec3(origin):lerp(destination, (i - 1.0) / elements)
- element = world:newBoxCollider(position, vec3(thickness, thickness, elementSize * 0.95))
- element:setRestitution(0.1)
- element:setGravityIgnored(true)
- element:setOrientation(quat(orientation))
- element:setLinearDamping(0.01)
- element:setAngularDamping(0.01)
- element:setMass(0.001)
- if prev then
- local joint = lovr.physics.newBallJoint(prev, element, anchor)
- joint:setResponseTime(10)
- joint:setTightness(1)
- else
- first = element
- end
- prev = element
- end
- last = prev
- return first, last
- end
|