Rope joint keeps getting pulled beyond its maximum length

Hi there,

I’m working on a mobile game using the physics engine in Corona.

I have multiple rope joints arranged in a chain.

The chain is affected by upwards gravity.

When I pull down on the chain, ideally, the chain should move together, as it is restricted by set rope joint distances.

Yet when I pull it down, the closest link to the chain is the only one that follows, and there is a huge gap between it and the second closest.

Here’s a picture of what I’m describing in my game:

http://puu.sh/iycTT/a2db9c6498.jpg

I’ve had to have tried every single iteration of this. I can’t figure this out. What’s up with rope joints? Anyone have any experience with this willing to help out?

Thank you

Hi @exclaimteam,

Can you please post your code where you set up these objects and joints? I’ll need to see that to assist you. Please remember to surround the code with “lua” tags for clarity:

[lua] -- [/lua]

Thanks,

Brent Sorrentino

Sorry, I was apprehensive to posting my code because it’s a mess. Here, I’ll try cleaning it up it isolate the specific problem I’m having.

Here I create the balloon and chain:

[lua]local function make_balloon( x, y, lw, lh, c )

    --table to keep track of the chain links

    local prevs = {}

    --image of the balloon

    balloon = display.newImage(“red_balloon_small.png”)

    physics.addBody(balloon, “dynamic”, {density=100, bounce=0, friction = 1})

    balloon.x, balloon.y = x, y

    balloon.dampingRatio = 1

    balloon.isSensor = true

    balloon.gravityScale = 0

    --“top of the balloon” effected by gravity. Pivot jointed to the top of the balloon image.

    local balloonTop = display.newRect( x, y - balloon.contentHeight/2, lw, lh )

    physics.addBody(balloonTop, “dynamic”, {density=100, bounce=0, friction = 1})

    balloonTop:setFillColor(0,0,0)

    local linker = physics.newJoint(“pivot”, balloonTop, balloon, balloon.x, balloon.y - balloon.contentHeight/2)

    balloonTop.gravityScale = 100

    balloonTop.alpha = 0

    --“bottom of the balloon” not effected by gravity. Pivot jointed to the base of the balloon image.

    local balloonBottom = display.newRect( x, y + balloon.contentHeight/2, lw, lh )

    physics.addBody(balloonBottom, “dynamic”, {density=100, bounce=0, friction = 1})

    balloonBottom:setFillColor(0,0,0)

    local linker = physics.newJoint(“pivot”, balloonBottom, balloon, balloon.x, balloon.y + balloon.contentHeight/2)

    balloonBottom.gravityScale = 0

    --the handle at the base of the chain. Can be touched and dragged

    handle = display.newCircle(0,0,25)

    handle:setFillColor(1,0.2,0.4)

    physics.addBody(handle,“static”, {isSensor = true})

    handle.x,handle.y = x, y + ((i)*lh) + 15

    handle:addEventListener( “touch”, handleDrag )

    --the chain starts at the base of the balloon

    prevs[0] = balloonBottom

    --creates “links” of the chain

    for i = 1, c do 

            local link = display.newRect( x, y+(i*(lh)), lw, lh )

            link:setFillColor(0,0,0)

            link.alpha = 0

            link.isSensor = true

            physics.addBody( link, “dynamic”,{ density=100.0} )  

            link.dampingRatio = 1

            --a series of rope joints. the current link connects to the previous one

            local linker = physics.newJoint(“rope”, link, prevs[i-1], 0, 0, 0, 0)

            linker.maxLength = link.y - prevs[i-1].y

            prevs[i] = link

    end

    --connects the last link to top of the handle

    local linker = physics.newJoint(“rope”, handle, prevs[c], 0, -handle.contentHeight/2, 0, 0)

    linker.maxLength = handle.y - prevs[c].y

    --links handle to balloon. Even this rope joint overstretches.

    local linkerB = physics.newJoint(“rope”, handle, balloonBottom, 0, -handle.contentHeight/2, 0, 0)

    linkerB.maxLength = handle.y - balloon.y + 2*c

end 

make_balloon(w/2, h/4, 5, 5, 30)

[/lua]

The balloon is affected by upwards gravity. When I pull the handle down, not all of the chain links follow. Specifically it’s the closest rope joint. This happens consistently. I’ve switched the drag-object to other links, and it’s always the closest rope joint that seems to overstretch. Here is the code for the drag-function:

[lua]

local function handleDrag( 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 = “static”

        end

    end

    – Stop further propagation of touch event!

    return true

end

[/lua]

The code I’ve presented here results in this effect:

If I don’t drag anything (balloon chain seems normal) - http://puu.sh/izflu/cd8dbb5195.jpg

Once I drag on the handle (balloon chain overstretches) - http://puu.sh/izfpN/2add7b0170.jpg

Obviously, that overstretching is not the intention. I’d like the rope joints to follow their max lengths (which I’ve defined to be no greater than the initial distance between the two objects it’s connecting), so that I have a chain that behaves like a balloon-string.

Thank you for taking the time to look at this.

If I understand correctly, looking at the screenshots, is “balloonBottom” the “handle” that should be dragged? If so, are you connecting the “balloonBottom” to the balloon? I would think that you shouldn’t… the handle should not be joined to the balloon directly in any way.

I would also not change the “handle” to kinematic on touch. If you want it to be immune to gravity, just set its “.gravityScale” to 0. I’ve seen some cases where kinematic bodies don’t play nicely with joints.

Brent

I’ve tried changing the “kinematic on touch” for the handle before, it did not change anything.

“balloonBottom” is not the “handle” that’s to be dragged. “balloonBottom” is a box on the bottom of the balloon object, pivot-jointed to the balloon object. This facilitates the rest of the “chain links” to be connected to the bottom of the balloon. 

The “handle” is the large circle at the end of the balloon string, as seen in the pictures above.

So to respond, the handle is not directly jointed to the balloon. It’s joined to the links, which join to the “balloonBottom” which is then joined to the balloon image.

I see that “handle” is static. Try changing it to dynamic as well…

Alright, I just gave that a shot. When the handle is dynamic, the balloon’s gravitational force pulls the entire thing. While its only being pulled by gravity, the string’s rope joints work fine and do not seem to be over-elastic. When I try dragging on the handle however, the stretching persists. So changing the handle to dynamic did not seem to impact the over-stretching.

My friend created a function a while back for making the balloon. It used a single rope joint between the balloon and handle, and did attempt to create any kind of chain. In this case, the rope joint held sturdy and did not overstretch.

[lua]

local function make_balloon()

        local joints = {}

        local handle2 = display.newCircle(0,0,25)

        handle2:setFillColor(1,0.2,0.4)

        physics.addBody(handle2,“dynamic”, {isSensor = true})

        handle2.x,handle2.y = math.random(0, w), 2*h

        local balloon2 = display.newImage(“red_balloon_small.png”)

        physics.addBody(balloon2, “dyanmic”, {density=100, bounce=0, friction = 1})

        balloon2.x, balloon2.y = handle2.x, handle2.y - 150

        --attach string to balloon

        joints[#joints+1] = physics.newJoint(“rope”, handle2, balloon2, 0, -handle2.contentHeight/2, 0, balloon2.contentHeight/2)

        joints.springDampingRatio = 1

        joints.maxLength = 100

end

[/lua]

The only real takeaway from this code is that the rope joint is joined from the touch-drag object (the handle) directly to the gravitationally-pulled object (the balloon). In this scenario, the handle pulls the balloon without any rope-stretching.

From my testing around it seems that corona has a problem with a series of rope joints connected down a line when they are affected by both gravitational force and the pull of my finger-dragging.

Using this, I directly connected my handle to the gravity-affected object (the balloon) and the rope works fine. However, in the case of multiple joints connected with each other, the problem persists. Any ideas on how I can have multiple rope joint-links connecting a gravity-affected object and a touch/drag-affected object without stretching out?

Here’s a picture of what I mean:

http://puu.sh/iAB0I/410c3e4049.jpg

On the left is the balloon of my friend’s code, which has a singular rope joint, but does not stretch out even when the handle is dragged.

On the right is the balloon with a chain. I’ve made the rope joint connecting the handle to the balloon work similarly to the left, so that joint no longer over-stretches. But as you can see with the chain, it continues to overstretch. Particularly the joint next to the handle.

Hi @exclaimteam,

Just curious, is there a reason why you couldn’t assemble your “chain” using pivot joints instead of rope joints? I’m almost certain that implementation has been proven to work. Also, it tends to create a more believeable chain, since you can limit the angle of rotation of each joint, thus preventing the segments from twisting around each other.

Brent

Hi @exclaimteam,

Just curious, is there a reason why you couldn’t assemble your “chain” using pivot joints instead of rope joints? I’m almost certain that implementation has been proven to work. Also, it tends to create a more believeable chain, since you can limit the angle of rotation of each joint, thus preventing the segments from twisting around each other.

Brent

Ah, well, I actually tried using pivot joints originally, but it didn’t seem to work for me. I just gave it another try. It still breaks. Basically, when I start dragging the handle, the joints break and get pulled away by the force of gravity on the balloon.

Here’s some pictures of it happening:

Before drag (it’s behaving really elastically, but the connections are stable) - http://puu.sh/iEn6O/6c6a28a56d.jpg

After drag (it pulls apart completely) - http://puu.sh/iEn7L/17732ae663.jpg

What might I be doing wrong?

Attached is the code for creating the balloon & chain using pivot joints:

[lua]

    local function make_balloon( x, y, lw, lh, c )

        local prevs = {}

        balloon = display.newImage(“red_balloon_small.png”)

        physics.addBody(balloon, “dynamic”, {density=100, bounce=0, friction = 1})

        balloon.x, balloon.y = x, y

        balloon.dampingRatio = 1

        balloon.isSensor = true

        balloon.gravityScale = 0

        local balloonTop = display.newRect( x, y - balloon.contentHeight/2, lw, lh )

        physics.addBody(balloonTop, “dynamic”, {density=100, bounce=0, friction = 1})

        balloonTop:setFillColor(0,0,0)

        local linker = physics.newJoint(“pivot”, balloonTop, balloon, balloon.x, balloon.y - balloon.contentHeight/2)

        balloonTop.gravityScale = 100

        balloonTop.alpha = 0

        --balloonTop.isSensor = true

        local balloonBottom = display.newRect( x, y + balloon.contentHeight/2, lw, lh )

        physics.addBody(balloonBottom, “dynamic”, {density=100, bounce=0, friction = 1})

        balloonBottom:setFillColor(0,0,0)

        local linker = physics.newJoint(“pivot”, balloonBottom, balloon, balloon.x, balloon.y + balloon.contentHeight/2)

        balloonBottom.isSensor = true

        balloonBottom.alpha = 0

        --balloonBottom.gravityScale = 100

        handle = display.newCircle(0,0,25)

        handle:setFillColor(1,0.2,0.4)

        physics.addBody(handle,“static”, {isSensor = true})

        handle.gravityScale = 0

        handle:addEventListener( “touch”, handleDrag )

        prevs[0] = balloon

        for i = 1, c do 

                local link = display.newRect( x, balloon.y + balloon.contentHeight/2+(i*(lh) + 2), lw, lh )

                link:setFillColor(0,0,0)

                link.alpha = 0

                link.isSensor = true

                physics.addBody( link, “dynamic”,{ density=100.0} )  

                link.dampingRatio = 1

                link.gravityScale = 0

                if i == 1 then

                    local linker = physics.newJoint(“pivot”, link, prevs[i-1], prevs[i-1].x, prevs[i-1].y + (link.y - prevs[i-1].y)/2 + balloon.contentHeight/2)

                    linker.dampingRatio = 0

                    linker.isLimitEnabled = true

                    linker:setRotationLimits( -45, 45 )

                else

                    local linker = physics.newJoint(“pivot”, link, prevs[i-1], prevs[i-1].x, prevs[i-1].y + (link.y - prevs[i-1].y)/2)

                    linker.dampingRatio = 0

                    linker.isLimitEnabled = true

                    linker:setRotationLimits( -45, 45 )

                end

                prevs[i] = link

        end

        handle.x,handle.y = x, prevs[c].y + lh + handle.contentHeight/2

        local linker = physics.newJoint(“pivot”, handle, prevs[c], x, prevs[c].y + (prevs[c].y - handle.y)/2)

        linker.dampingRatio = 0

        linker.isLimitEnabled = true

        linker:setRotationLimits( -45, 45 )

    end 

    make_balloon(w/2, h/4, 5, 5, 30)

[/lua]

Hi @exclaimteam,

I did a little testing on my side, and basically, if you “pull” a joined series of objects fast enough… whether they be joined by “pivot”, “distance”, or “rope” joints… that chain will “break apart” momentarily and then, eventually, it will come back together as a joined chain again. The speed at which this happens is generally pretty fast, but basically, Box2D can’t compensate for a super-fast pull of one end of the chain and instantly transfer that force throughout all segments in the chain.

Is this what is happening for you? In my tests, the chain only “disassembled” temporarily when the handle was pulled very fast… but easily at a speed which the user could perform via a touch.

Now, if your chain is disassembling even on slower pulls of the handle, then there’s something else wrong with your setup. My chain retained its structure on slower pulls.

Brent

Well, my chain certainly “disassembles,” when I drag it. However, the “reassembling” part does not happen at a very fast pace.

I mean, in my code I have gravity pulling upwards constantly (and I drag downwards), so that likely slows the reassembling process?

At a certain threshold I’ve noticed, if the pull is strong enough, either from my drag, or from gravity, the chain will irreparably “disassemble” stretch out seemingly infinitely (and constantly bouncing around).

Here’s an example of it using rope joints in my current code: http://puu.sh/iJZD4/9226c05d31.jpg

When I use pivot joints the joints are not simply stretched out, but jittering around the screen.

Hi @exclaimteam,

I’m not sure if you’ll be able to solve this in your current setup. In my experience going way back, Box2D joints simply are prone to “falling apart” if too much stress is put upon them. This is especially true when assembling a chain of joints, where forces from one part are step-transferred up through a series of joints. In your most extreme case, where the rope absolutely disassembles beyond repair, that is where Box2D has really broken down (and that joint will not repair itself).

One final idea would be to create a chain of objects joined by pivot joints, as you’re doing. Then, in addition, join every other segment together using a distance joint with a slight amount of stretch. So, if you had 9 segments in the chain, you could join all of them together as normal: 1 to 2, 2 to 3, 3 to 4, etc. But then in addition, you could add distance joints from 1 to 3, 3 to 5, 5 to 7, etc. That may alleviate some of the stress on the overall chain, providing some pull on the next segment beyond, but with a little bit of elastic behavior, it wouldn’t pull as directly as the pivot joints.

Brent

Hi @exclaimteam,

Can you please post your code where you set up these objects and joints? I’ll need to see that to assist you. Please remember to surround the code with “lua” tags for clarity:

[lua] -- [/lua]

Thanks,

Brent Sorrentino

Sorry, I was apprehensive to posting my code because it’s a mess. Here, I’ll try cleaning it up it isolate the specific problem I’m having.

Here I create the balloon and chain:

[lua]local function make_balloon( x, y, lw, lh, c )

    --table to keep track of the chain links

    local prevs = {}

    --image of the balloon

    balloon = display.newImage(“red_balloon_small.png”)

    physics.addBody(balloon, “dynamic”, {density=100, bounce=0, friction = 1})

    balloon.x, balloon.y = x, y

    balloon.dampingRatio = 1

    balloon.isSensor = true

    balloon.gravityScale = 0

    --“top of the balloon” effected by gravity. Pivot jointed to the top of the balloon image.

    local balloonTop = display.newRect( x, y - balloon.contentHeight/2, lw, lh )

    physics.addBody(balloonTop, “dynamic”, {density=100, bounce=0, friction = 1})

    balloonTop:setFillColor(0,0,0)

    local linker = physics.newJoint(“pivot”, balloonTop, balloon, balloon.x, balloon.y - balloon.contentHeight/2)

    balloonTop.gravityScale = 100

    balloonTop.alpha = 0

    --“bottom of the balloon” not effected by gravity. Pivot jointed to the base of the balloon image.

    local balloonBottom = display.newRect( x, y + balloon.contentHeight/2, lw, lh )

    physics.addBody(balloonBottom, “dynamic”, {density=100, bounce=0, friction = 1})

    balloonBottom:setFillColor(0,0,0)

    local linker = physics.newJoint(“pivot”, balloonBottom, balloon, balloon.x, balloon.y + balloon.contentHeight/2)

    balloonBottom.gravityScale = 0

    --the handle at the base of the chain. Can be touched and dragged

    handle = display.newCircle(0,0,25)

    handle:setFillColor(1,0.2,0.4)

    physics.addBody(handle,“static”, {isSensor = true})

    handle.x,handle.y = x, y + ((i)*lh) + 15

    handle:addEventListener( “touch”, handleDrag )

    --the chain starts at the base of the balloon

    prevs[0] = balloonBottom

    --creates “links” of the chain

    for i = 1, c do 

            local link = display.newRect( x, y+(i*(lh)), lw, lh )

            link:setFillColor(0,0,0)

            link.alpha = 0

            link.isSensor = true

            physics.addBody( link, “dynamic”,{ density=100.0} )  

            link.dampingRatio = 1

            --a series of rope joints. the current link connects to the previous one

            local linker = physics.newJoint(“rope”, link, prevs[i-1], 0, 0, 0, 0)

            linker.maxLength = link.y - prevs[i-1].y

            prevs[i] = link

    end

    --connects the last link to top of the handle

    local linker = physics.newJoint(“rope”, handle, prevs[c], 0, -handle.contentHeight/2, 0, 0)

    linker.maxLength = handle.y - prevs[c].y

    --links handle to balloon. Even this rope joint overstretches.

    local linkerB = physics.newJoint(“rope”, handle, balloonBottom, 0, -handle.contentHeight/2, 0, 0)

    linkerB.maxLength = handle.y - balloon.y + 2*c

end 

make_balloon(w/2, h/4, 5, 5, 30)

[/lua]

The balloon is affected by upwards gravity. When I pull the handle down, not all of the chain links follow. Specifically it’s the closest rope joint. This happens consistently. I’ve switched the drag-object to other links, and it’s always the closest rope joint that seems to overstretch. Here is the code for the drag-function:

[lua]

local function handleDrag( 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 = “static”

        end

    end

    – Stop further propagation of touch event!

    return true

end

[/lua]

The code I’ve presented here results in this effect:

If I don’t drag anything (balloon chain seems normal) - http://puu.sh/izflu/cd8dbb5195.jpg

Once I drag on the handle (balloon chain overstretches) - http://puu.sh/izfpN/2add7b0170.jpg

Obviously, that overstretching is not the intention. I’d like the rope joints to follow their max lengths (which I’ve defined to be no greater than the initial distance between the two objects it’s connecting), so that I have a chain that behaves like a balloon-string.

Thank you for taking the time to look at this.

If I understand correctly, looking at the screenshots, is “balloonBottom” the “handle” that should be dragged? If so, are you connecting the “balloonBottom” to the balloon? I would think that you shouldn’t… the handle should not be joined to the balloon directly in any way.

I would also not change the “handle” to kinematic on touch. If you want it to be immune to gravity, just set its “.gravityScale” to 0. I’ve seen some cases where kinematic bodies don’t play nicely with joints.

Brent

I’ve tried changing the “kinematic on touch” for the handle before, it did not change anything.

“balloonBottom” is not the “handle” that’s to be dragged. “balloonBottom” is a box on the bottom of the balloon object, pivot-jointed to the balloon object. This facilitates the rest of the “chain links” to be connected to the bottom of the balloon. 

The “handle” is the large circle at the end of the balloon string, as seen in the pictures above.

So to respond, the handle is not directly jointed to the balloon. It’s joined to the links, which join to the “balloonBottom” which is then joined to the balloon image.

I see that “handle” is static. Try changing it to dynamic as well…

Alright, I just gave that a shot. When the handle is dynamic, the balloon’s gravitational force pulls the entire thing. While its only being pulled by gravity, the string’s rope joints work fine and do not seem to be over-elastic. When I try dragging on the handle however, the stretching persists. So changing the handle to dynamic did not seem to impact the over-stretching.

My friend created a function a while back for making the balloon. It used a single rope joint between the balloon and handle, and did attempt to create any kind of chain. In this case, the rope joint held sturdy and did not overstretch.

[lua]

local function make_balloon()

        local joints = {}

        local handle2 = display.newCircle(0,0,25)

        handle2:setFillColor(1,0.2,0.4)

        physics.addBody(handle2,“dynamic”, {isSensor = true})

        handle2.x,handle2.y = math.random(0, w), 2*h

        local balloon2 = display.newImage(“red_balloon_small.png”)

        physics.addBody(balloon2, “dyanmic”, {density=100, bounce=0, friction = 1})

        balloon2.x, balloon2.y = handle2.x, handle2.y - 150

        --attach string to balloon

        joints[#joints+1] = physics.newJoint(“rope”, handle2, balloon2, 0, -handle2.contentHeight/2, 0, balloon2.contentHeight/2)

        joints.springDampingRatio = 1

        joints.maxLength = 100

end

[/lua]

The only real takeaway from this code is that the rope joint is joined from the touch-drag object (the handle) directly to the gravitationally-pulled object (the balloon). In this scenario, the handle pulls the balloon without any rope-stretching.

From my testing around it seems that corona has a problem with a series of rope joints connected down a line when they are affected by both gravitational force and the pull of my finger-dragging.

Using this, I directly connected my handle to the gravity-affected object (the balloon) and the rope works fine. However, in the case of multiple joints connected with each other, the problem persists. Any ideas on how I can have multiple rope joint-links connecting a gravity-affected object and a touch/drag-affected object without stretching out?

Here’s a picture of what I mean:

http://puu.sh/iAB0I/410c3e4049.jpg

On the left is the balloon of my friend’s code, which has a singular rope joint, but does not stretch out even when the handle is dragged.

On the right is the balloon with a chain. I’ve made the rope joint connecting the handle to the balloon work similarly to the left, so that joint no longer over-stretches. But as you can see with the chain, it continues to overstretch. Particularly the joint next to the handle.

Hi @exclaimteam,

Just curious, is there a reason why you couldn’t assemble your “chain” using pivot joints instead of rope joints? I’m almost certain that implementation has been proven to work. Also, it tends to create a more believeable chain, since you can limit the angle of rotation of each joint, thus preventing the segments from twisting around each other.

Brent