Guest User

love2d rope physics

a guest
Feb 2nd, 2025
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.66 KB | Gaming | 0 0
  1. Rope = {}
  2. Rope.__index = Rope
  3.  
  4. --[[
  5. Basic Usage:
  6.     local Rope = require 'rope'
  7.  
  8.     .load()
  9.         Rope:load()
  10.         Rope:createRope()
  11.         Rope:attachToObject(body_to_attach{body, shape, fixture)
  12.  
  13.     .update()
  14.         Rope:update()
  15.  
  16.     .draw()
  17.         Rope:draw()
  18.  
  19.     Uses key q and e to handle rope length
  20. --]]
  21.  
  22. function Rope:load()
  23.     rope = {
  24.         x = 300,
  25.         y = 100,
  26.         segmentLength = 5,
  27.         maxLength = 5, -- length between joints
  28.         segmentCount = 20,
  29.         minLength = 4,
  30.         attachedObject = nil
  31.     }
  32.     setmetatable(rope, Rope)
  33.     return rope
  34. end
  35.  
  36. local delay = 0.09 -- rope extension delay
  37. local timer = 0
  38. function Rope:update(dt)
  39.     Rope:fixRopePosition()
  40.     timer = timer + dt
  41.  
  42.     -- Add a segment
  43.     if love.keyboard.isDown("e") and timer > delay then
  44.         timer = 0
  45.         print("Current rope length:" , #ropeSegments)
  46.         rope.segmentCount = rope.segmentCount + 1
  47.  
  48.         -- Remove the first joint
  49.         if not rope.mainJoint:isDestroyed() then
  50.             rope.mainJoint:destroy()
  51.         end
  52.  
  53.         -- Create new segment then attach to the object
  54.         local newY = ropeSegments[1].body:getY() + 10
  55.         local newX = ropeSegments[1].body:getX()
  56.         newSegment = Rope:createRopeSegment(newX, newY)
  57.         local joint = Rope:connectRopeSegment(ropeSegments[1].body, newSegment.body)
  58.         table.insert(ropeSegments, 1, newSegment)
  59.         table.insert(ropeJoints, 1, joint)
  60.  
  61.         if rope.attachedObject then
  62.             rope.mainJoint = Rope:attachToObject(rope.attachedObject)
  63.         end
  64.  
  65.     -- Remove a segment
  66.     elseif love.keyboard.isDown("q") and timer > delay then
  67.         timer = 0
  68.         print("Current rope length:", #ropeSegments)
  69.         rope.segmentCount = rope.segmentCount - 1
  70.  
  71.         if #ropeJoints == rope.minLength then return end
  72.  
  73.         -- Remove the first joint and segment then attach to the object
  74.         joint_to_delete = table.remove(ropeJoints, 1)
  75.         joint_to_delete:destroy()
  76.         first = ropeSegments[1]
  77.         first.body:destroy()
  78.  
  79.         table.remove(ropeSegments, 1)
  80.  
  81.         if rope.attachedObject then
  82.             rope.mainJoint = Rope:attachToObject(rope.attachedObject)
  83.         end
  84.  
  85.     end
  86. end
  87.  
  88. function Rope:removeSegment()
  89.     if ropeSegments > 1 then
  90.         local joint_to_delete = table.remove(ropeJoints, #ropeJoints)
  91.         joint_to_delete:destroy()
  92.  
  93.         local segment_to_delete = table.remove(ropeSegments, #ropeSegments)
  94.         segment_to_delete.body:destroy()
  95.     end
  96. end
  97.  
  98. function Rope:unDockHookObject()
  99.    if hook.dockJoint and hook.docking then
  100.        hook.dockJoint:destroy()
  101.        hook.docking = false
  102.        hook.dockJoint = nil
  103.    end
  104. end
  105.  
  106. function Rope:dockHookObject()
  107.     if hook.readyToDock then
  108.         hook.dockJoint = love.physics.newRevoluteJoint(
  109.             hook.body,
  110.             hook.contactBody,
  111.             hook.body:getX(),
  112.             hook.body:getY(), false
  113.         )
  114.         hook.readyToDock = false
  115.         hook.docking = true
  116.     end
  117. end
  118.  
  119. function Rope:mousepressed(key)
  120.     if key == 1 then -- left click
  121.         Rope:toggleHook()
  122.     end
  123. end
  124.  
  125. function Rope:toggleHook()
  126.     if hook.docking then
  127.        print("Undocking..")
  128.        Rope:unDockHookObject()
  129.     elseif hook.readyToDock then
  130.        print("Docking Object to Rope Hook")
  131.        Rope:dockHookObject()
  132.     end
  133. end
  134.  
  135. function Rope:createRopeSegment(x, y)
  136.     newSegment = {}
  137.     newSegment.body = love.physics.newBody(world, x, y, "dynamic")
  138.     newSegment.shape = love.physics.newCircleShape(5)
  139.     newSegment.fixture = love.physics.newFixture(newSegment.body, newSegment.shape, 0.2)
  140.     newSegment.body:setLinearDamping(2)
  141.     return newSegment
  142. end
  143.  
  144. function Rope:connectRopeSegment(segmentA, segmentB)
  145.     local joint = love.physics.newRopeJoint(
  146.         segmentA,        segmentB,
  147.         segmentA:getX(), segmentA:getY(),
  148.         segmentB:getX(), segmentB:getY(),
  149.         rope.maxLength,
  150.         false
  151.     )
  152.     return joint
  153. end
  154.  
  155. function Rope:attachToObject(object)
  156.     firstSegment = ropeSegments[1]
  157.     newJoint = love.physics.newRopeJoint(
  158.         firstSegment.body, object.body,
  159.         firstSegment.body:getX(), firstSegment.body:getY(),
  160.         object.body:getX(), object.body:getY()+10,
  161.         10
  162.     )
  163.     rope.attachedObject = object
  164.     return newJoint
  165. end
  166.  
  167. function Rope:createRope()
  168.     ropeSegments = {}
  169.     ropeJoints = {}
  170.  
  171.     -- create all the segments
  172.     for segment = 1, rope.segmentCount do
  173.         newSegment = Rope:createRopeSegment(rope.x, rope.y + (segment - 1) * rope.segmentLength)
  174.         table.insert(ropeSegments, {
  175.             body = newSegment.body,
  176.             shape = newSegment.shape,
  177.             fixture = newSegment.fixture
  178.         })
  179.     end
  180.  
  181.     -- connect all segments
  182.     for segment = 1, #ropeSegments - 1 do
  183.         local bodyA = ropeSegments[segment].body
  184.         local bodyB = ropeSegments[segment + 1].body
  185.         newJoint = Rope:connectRopeSegment(bodyA, bodyB)
  186.         table.insert(ropeJoints, newJoint)
  187.     end
  188.  
  189.     -- hook configuration
  190.     hook = ropeSegments[#ropeSegments]
  191.     hook.fixture:setUserData("hook")
  192.     hook.docking = false -- is holding an object?
  193.     hook.dockJoint = nil -- the joint
  194.     hook.contactBody = nil -- the body that is holding or contacting
  195. end
  196.  
  197. function Rope:fixRopePosition()
  198.     for i = 1, #ropeSegments - 1 do
  199.         local segmentA = ropeSegments[i]
  200.         local segmentB = ropeSegments[i + 1]
  201.  
  202.         local dx = segmentB.body:getX() - segmentA.body:getX()
  203.         local dy = segmentB.body:getY() - segmentA.body:getY()
  204.         local distance = math.sqrt(dx * dx + dy * dy)
  205.  
  206.         local desiredDistance = 10
  207.         local correctionFactor = 0.5
  208.  
  209.         if distance > desiredDistance then
  210.             local offsetX = (dx / distance) * (distance - desiredDistance) * correctionFactor
  211.             local offsetY = (dy / distance) * (distance - desiredDistance) * correctionFactor
  212.             segmentB.body:setPosition(
  213.                 segmentB.body:getX() - offsetX,
  214.                 segmentB.body:getY() - offsetY
  215.             )
  216.         end
  217.     end
  218. end
  219.  
  220. function Rope:draw()
  221.     drawSegments = true
  222.  
  223.     love.graphics.push()
  224.     if drawSegments then
  225.         for _, segment in ipairs(ropeSegments) do
  226.             line = love.graphics.line(
  227.             segment.body:getX(),
  228.             segment.body:getX(),
  229.             segment.body:getX(),
  230.             segment.body:getX())
  231.             love.graphics.setLineWidth(6)
  232.             love.graphics.setLineStyle("smooth")
  233.         end
  234.     end
  235.     love.graphics.pop()
  236.  
  237.     for _, joint in ipairs(ropeJoints) do
  238.         love.graphics.line(joint:getAnchors())
  239.     end
  240. end
  241.  
  242. return Rope
  243.  
  244.  
Tags: love2d
Advertisement
Add Comment
Please, Sign In to add comment