main.lua 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. --[[ Wrecking ball suspended from rope. Cyrus-free.
  2. Making realtime rope simulation is finicky on any physics engine. At certain weight the force becomes
  3. too much to be successfully distributed among rope elements.
  4. Some steps that can help solve the issue:
  5. 1) lower the mass of suspended weight or lower the gravity constant
  6. 2) increase mass of each rope element, preferably having more mass at top of rope and less mass at bottom
  7. 3) decrease number of rope elements
  8. 4) decrease the simulation time step
  9. 5) modify engine code to use direct solver instead of iterative solver (step() instead of quickStep())
  10. --]]
  11. local world
  12. function lovr.load()
  13. world = lovr.physics.newWorld(0, -3, 0, false)
  14. -- ground plane
  15. local box = world:newBoxCollider(vec3(0, -0.05, 0), vec3(20, 0.1, 20))
  16. box:setKinematic(true)
  17. -- hanger
  18. local hangerPosition = vec3(0, 2, -1)
  19. local hanger = world:newBoxCollider(hangerPosition, vec3(0.3, 0.1, 0.3))
  20. hanger:setKinematic(true)
  21. -- ball
  22. local ballPosition = vec3(-1, 1, -1)
  23. local ball = world:newSphereCollider(ballPosition, 0.2)
  24. -- rope
  25. local firstEnd, lastEnd = makeRope(
  26. hangerPosition + vec3(0, -0.1, 0),
  27. ballPosition + vec3(0, 0.3, 0),
  28. 0.02, 10)
  29. lovr.physics.newDistanceJoint(hanger, firstEnd, hangerPosition, vec3(firstEnd:getPosition()))
  30. lovr.physics.newDistanceJoint(ball, lastEnd, ballPosition, vec3(lastEnd:getPosition()))
  31. -- brick wall
  32. local x = 0.3
  33. local even = true
  34. for y = 1, 0.1, -0.1 do
  35. for z = -0.5, -1.5, -0.2 do
  36. world:newBoxCollider(x, y, even and z or z - 0.1, 0.08, 0.1, 0.2)
  37. end
  38. even = not even
  39. end
  40. lovr.graphics.setBackgroundColor(0.1, 0.1, 0.1)
  41. end
  42. function lovr.update(dt)
  43. world:update(dt)
  44. end
  45. function lovr.draw(pass)
  46. for i, collider in ipairs(world:getColliders()) do
  47. local shade = (i - 10) / #world:getColliders()
  48. pass:setColor(shade, shade, shade)
  49. local shape = collider:getShapes()[1]
  50. local shapeType = shape:getType()
  51. local x,y,z, angle, ax,ay,az = collider:getPose()
  52. if shapeType == 'box' then
  53. local sx, sy, sz = shape:getDimensions()
  54. pass:box(x,y,z, sx,sy,sz, angle, ax,ay,az)
  55. elseif shapeType == 'sphere' then
  56. pass:setColor(0.4, 0, 0)
  57. pass:sphere(x,y,z, shape:getRadius())
  58. end
  59. end
  60. end
  61. function makeRope(origin, destination, thickness, elements)
  62. local length = (destination - origin):length()
  63. thickness = thickness or length / 100
  64. elements = elements or 30
  65. elementSize = length / elements
  66. local orientation = vec3(destination - origin):normalize()
  67. local first, last, prev
  68. for i = 1, elements do
  69. local position = vec3(origin):lerp(destination, (i - 0.5) / elements)
  70. local anchor = vec3(origin):lerp(destination, (i - 1.0) / elements)
  71. element = world:newBoxCollider(position, vec3(thickness, thickness, elementSize * 0.95))
  72. element:setRestitution(0.1)
  73. element:setGravityIgnored(true)
  74. element:setOrientation(quat(orientation))
  75. element:setLinearDamping(0.01)
  76. element:setAngularDamping(0.01)
  77. element:setMass(0.001)
  78. if prev then
  79. local joint = lovr.physics.newBallJoint(prev, element, anchor)
  80. joint:setResponseTime(10)
  81. joint:setTightness(1)
  82. else
  83. first = element
  84. end
  85. prev = element
  86. end
  87. last = prev
  88. return first, last
  89. end