Pivot Joints and apparent elasticity

_ Editor’s Note: See the following comment for a resolution to this issue:_
http://developer.anscamobile.com/forum/2010/10/30/pivot-joints-and-apparent-elasticity?page=2#comment-110810

I’m trying to create a rope physical object out of a series of rectangles. No problem. I’ve taken 10 rectangles and attached them end to end with pivot joints.

Then I’ve taken one end of this rope and attached it to a static object near the top of the screen.

Finally I’ve taken the other end of the top and attached it to something reasonably heavy (lets just say its a bowling ball for these purposes).

Then I am propelling the bowling ball away from the static object by colliding it with another static object which I am manually tweening in its direction (let’s say it’s just a bullet as a static physics body).

What I see is that the ball moves away as it should and it stays attached to the rope, but before the ball starts to swing back to a point of rest thanks to gravity, it seems to *stretch* the rope, and the constituent rectangles that compose the rope seem to rip apart visibly…

That is bad. Why does this happen? What can do I do to make sure the rope does not have this elastic quality?

Distance joint *seems* right but it says that it shouldn’t be used for attaching objects directly to one another? Maybe that’s just bad wording… is that what I want? [import]uid: 7473 topic_id: 3208 reply_id: 303208[/import]

I’m facing the same problem than you. I’m trying to create a rope by linking many links (like in chains sample code) and would like to control it with the touch but there is elasticity when there is movement. As you said, pivot shouldn’t allow elasticity. But i cannot make it work with distance joint. Sounds weird.

Matthieu [import]uid: 10991 topic_id: 3208 reply_id: 10844[/import]

I’m having this same problem. This is also a big problem with creating ragdolls. Can we get an answer on either a way to fix this or whether this is a bug that needs to be fixed? [import]uid: 7531 topic_id: 3208 reply_id: 19490[/import]

I agree. It seems the box2d physics engine is not being used like it is supposed to be. In flash or cocos2d using the box2d engine you do not have these problems. It makes it almost completely impossible to build ragdolls or anything with joints that is going to interact with other physics bodies.
I’ve tried increasing the iterations but that doesn’t help either.

The box2d physics engine is great and really appealed to me when they said it was used in corona, but it just seems to be horribly implemented or we are all just doing something wrong. I wish we could get an answer from Ansca. [import]uid: 10243 topic_id: 3208 reply_id: 19508[/import]

So… rag dolls difficult in Corona?

I was hoping to start building those next.

m [import]uid: 8271 topic_id: 3208 reply_id: 19522[/import]

Its not difficult to build, its actually very straight forward. Its just difficult to get them to interact with other physics bodies without them coming apart. The joints don’t break they just stretch and it looks very unrealistic. For example an arm might get stuck while the rest of the body continues to move. [import]uid: 10243 topic_id: 3208 reply_id: 19536[/import]

A user posted a good ragdoll example on the forum

http://developer.anscamobile.com/forum/2010/10/29/new-corona-any-radgoll-examples

Tim [import]uid: 8196 topic_id: 3208 reply_id: 20016[/import]

Tim that’s great example of ragdolls working in Corona but that is not what this thread is about. Can you please tell us what the plan is to fix the elasticity with joints? This is major problem with trying to build physics based games and our current app.

Thanks [import]uid: 7531 topic_id: 3208 reply_id: 20017[/import]

Can someone post a reproducible test case demonstrating the problem? [import]uid: 8196 topic_id: 3208 reply_id: 20018[/import]

This requires the link.png from the chains example.

[lua]–> Setup Display
display.setStatusBar (display.HiddenStatusBar)

system.activate (“multitouch”)

–> Start Physics
local physics = require (“physics”)
–local config = require(“config”)
physics.start ()
physics.setGravity (0, 10)

–physics.setDrawMode (“hybrid”)

–> Create Walls
local leftWall = display.newRect (0, 0, 1, display.contentHeight)
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight)
local ceiling = display.newRect (0, 0, display.contentWidth, 1)
local floor = display.newRect (0, display.contentHeight, display.contentWidth, 1)

physics.addBody (leftWall, “static”, {bounce = 0.0, friction = 10})
physics.addBody (rightWall, “static”, {bounce = 0.0, friction = 10})
physics.addBody (ceiling, “static”, {bounce = 0.0, friction = 10})
physics.addBody (floor, “static”, {bounce = 0.0, friction = 10})

– A basic function for dragging physics objects
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

myText:setTextColor(0, 0, 255)
–dragTimer = event.time
local myText4 = display.newText( dragTimer, 0, 60, “Helvetica”, 16 )
myText:setTextColor(0, 0, 255)

elseif t.isFocus then
if “moved” == phase then
t.x = event.x - t.x0
t.y = event.y - t.y0
dragTimer = event.time

elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
local myText = display.newText( event.time, 0, 0, “Helvetica”, 16 )
myText:setTextColor(0, 0, 255)
local myText2 = display.newText( dragTimer, 0, 40, “Helvetica”, 16 )
myText:setTextColor(0, 0, 255)
– Switch body type back to “dynamic”, unless we’ve marked this sprite as a platform
if ( not event.target.isPlatform ) then
event.target.bodyType = “dynamic”

end
end
end

– Stop further propagation of touch event!
return true
end

—> Objects

local beam3 = display.newRect( 0, 0, 120, 20 )
beam3.x = 280; beam3.y = 50
physics.addBody( beam3, “kinematic”, { friction=0.7 } )
beam3.isPlatform = true – custom flag, used in drag function above
–> Create Chain

local myJoints = {}
i = 1
local link = {}
for j = 1,17 do
link[j] = display.newImage( “link.png” )
link[j].x = 221 + (i*34)
link[j].y = 55 + (j*17)
physics.addBody( link[j], { density=2.0, friction=0, bounce=0 } )

– Create joints between links
if (j > 1) then
prevLink = link[j-1] – each link is joined with the one above it
else
prevLink = beam3 – top link is joined to overhanging beam
end
–link[j].linearDamping = 1
myJoints[#myJoints + 1] = physics.newJoint( “pivot”, prevLink, link[j], 221 + (i*34), 46 + (j*17) )
if j == 17 then
local chainball = display.newCircle( 0, 0, 35)
chainball.x = 221 + (i*34); chainball.y = 46 + (j*17)
physics.addBody( chainball, { density=1.0, friction=0.4, bounce=0.2, radius = 35 } )
chainball:setFillColor (255, 255, 255, 255)
local chainballjoint = physics.newJoint( “pivot”, chainball, link[j], 221 + (i*34), 46 + (j*17) )
end
end

beam3:addEventListener ( “touch”, startDrag )
[import]uid: 7531 topic_id: 3208 reply_id: 20057[/import]

Thanks for the test case, I definitely see the problem. I will discuss with the engineering team further to see what’s going on.

But I’m wondering why the rag doll sample posted previously doesn’t exhibit the same joint elasticity with the pivot joints. You can drag the head, arms, etc. and everything stays together. Perhaps it’s not a perfect comparison…just thinking out loud.

Tim [import]uid: 8196 topic_id: 3208 reply_id: 20167[/import]

After experimenting with Montage’s sample code. I have found the Box2D version in Corona is lacking in joint functionality and or implemented incorrectly. How it should work : download “testbed” from Box2d

http://code.google.com/p/box2d/downloads/detail?name=Testbed_v2.1.3.zip&can=2&q=

Under “Tests” drop down menu select Chain. The Chain works perfectly. We know cocos2d has this working I would like to see the Corona team step up and solve the problem for I am too working on a physics game.
[import]uid: 7177 topic_id: 3208 reply_id: 20170[/import]

The ragdoll example also uses a touch joint so it is elastic and doesn’t pull apart the ragdoll. Try using just a normal drag function on the head and it will have major problems as it updates its position.

The elasticity problem does happen with the ragdoll example if you add in obstacles. The head, arms or body will get stuck and pulled apart from the main radgoll when interacting with objects. Even when using the Touch joint and dragging the ragdoll around you can get it hung up on objects and tear body parts away from the main body.

[import]uid: 7531 topic_id: 3208 reply_id: 20203[/import]

Another thing. I tried to make the joints “weld” instead of “Pivot” and they still pull apart just as bad. That was unexpected.

Weld joints don’t act like they should in any way. At least from trying that experiment. [import]uid: 7531 topic_id: 3208 reply_id: 20208[/import]

I’m so glad this is getting attention. I knew I wasn’t crazy when I originally posted this. :slight_smile: [import]uid: 7473 topic_id: 3208 reply_id: 20212[/import]

I am having a problem with the piston joint, which is different, but still related to the Box2d implementation problems. A piston/prismatic joint is supposed to restrict movement to one axis. It does this when tested in other programs using Box2d, but doesn’t seem to work in Corona.

Here is an example. The piston joint is attached to the medium box. At first it appears it stays on the y axis and just moves on the x axis, which is how it is supposed to work, but if you drag the medium box it will pull right off the y axis. You can also drag the big box and push the medium box of the axis too. I just can’t seem to get it to restrict to one axis using the piston joint like it is supposed too.

[code]
local physics = require(“physics”)
physics.start()
physics.setDrawMode(“debug”)

display.setStatusBar( display.HiddenStatusBar )

local function startDrag( event )
local t = event.target

local phase = event.phase
if “began” == phase then
display.getCurrentStage():setFocus( t )
t.isFocus = true

t.x0 = event.x - t.x
t.y0 = event.y - t.y

event.target.bodyType = “kinematic”

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
event.target.bodyType = “dynamic”

end
end

return true
end

local bigBlock = display.newRect( 0, 0, 128, 128 )
bigBlock.x = 160; bigBlock.y = 0
physics.addBody( bigBlock, { density=5.0, friction=0.4, bounce=0.2 } )

local anchor = display.newRect( 0, 0, 32, 32 )
anchor.x = 160; anchor.y = 400
physics.addBody( anchor, “static” )

local block = display.newRect( 0, 0, 64, 64 )
block.x = 160; block.y = 300
physics.addBody( block, { density=3.0, friction=0.4, bounce=0.2 } )

bigBlock:addEventListener( “touch”, startDrag )
block:addEventListener( “touch”, startDrag )

myJoint = physics.newJoint( “piston”, block, anchor, anchor.x, anchor.y, 0,5 )
myJoint.isLimitEnabled = true
myJoint:setLimits(1,1)
[/code] [import]uid: 10243 topic_id: 3208 reply_id: 20257[/import]

I, too, am extremely glad this is getting some attention. I’ve been banging the piston problem drum for some time now; The elastic joints issue has been a serious concern because it seriously impacts potential projects when compared with other SDKs - something Ansca should be very concerned about, I believe.

@Tim It would be excellent to have a central place for progress on this issue. I’ve submitted a number of bug reports, but if this gets it’s own ID, please post it here?

matt [import]uid: 8271 topic_id: 3208 reply_id: 20328[/import]

I agree with you guys. I’ve just recently started using Corona but I noticed that this does not perform like other Box2d programs very quickly.

I’m just shocked that as long as Corona has been up and running, that this hasn’t been noticed until lately. I know you’ve been trying for a while though, horacebury.

I just really hope this does in fact get some serious attention. I am optimistic and hopeful. I have used flash and cocos2d with box2d and I’ve used gamesalad as well, and one thing that I’ve always heard about corona is they actually care about their customers and are active on the forums.

I hope they don’t let us down with this one. I’ve had a great time with Corona so far and will be using it for all my apps as soon as the bugs are worked out. It has increased my speed very much over cocos2d and has removed the limitations of gamesalad.

I sent them an email in regards to the piston problem and they wanted a code sample, so once I hear anything on that I’ll post it here. [import]uid: 10243 topic_id: 3208 reply_id: 20344[/import]

I added an issue to our Issues database for easier tracking, and a corresponding internal bug (#3264).

http://developer.anscamobile.com/issues/5949

Thanks for your patience as we investigate this issue. We are serious about fixing it, just a bit resource constrained at the moment.

Tim [import]uid: 8196 topic_id: 3208 reply_id: 20414[/import]

Some more thoughts after discussing with an engineer here…in the startDrag() function posted in the test case, the x/y display coordinates are being manipulated directly, outside the Box2D physical world–in godlike fashion, so to speak. This makes the physics gods angry. Using a touch joint to perform the drag (mouse joint in Box2d lingo) keeps everything consistent within the physical world. For instance, this similar Box2D/AS3 rope sample uses a touch/mouse joint to make the ball at the end of the rope draggable:

http://www.emanueleferonato.com/2009/10/05/basic-box2d-rope/

Below is the Corona version of the same sample. If there’s a use case/scenario that we’re not understanding, please let us know/post some code.

thanks,
-Tim

[code]
–> Setup Display
display.setStatusBar (display.HiddenStatusBar)

–> Start Physics
local physics = require (“physics”)
physics.start ()
physics.setGravity (0, 10)

–physics.setDrawMode (“hybrid”)

–> Create Walls
local leftWall = display.newRect (0, 0, 1, display.contentHeight)
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight)
local ceiling = display.newRect (0, 0, display.contentWidth, 1)
local floor = display.newRect (0, display.contentHeight, display.contentWidth, 1)

physics.addBody (leftWall, “static”, {bounce = 0.0, friction = 10})
physics.addBody (rightWall, “static”, {bounce = 0.0, friction = 10})
physics.addBody (ceiling, “static”, {bounce = 0.0, friction = 10})
physics.addBody (floor, “static”, {bounce = 0.0, friction = 10})

local xCenter = 160
local wCeil = 120
local hCeil = 20
local ceiling = display.newRect( xCenter - wCeil*0.5, 0, wCeil, hCeil )
physics.addBody( ceiling, “static”, { density=0, friction=0.5,bounce=0.2 } )

local prevBody = ceiling

local w,h = 10,50
local halfW,halfH = 0.5*w,0.5*h

– center of body
local x = xCenter
local y = hCeil - halfH
local yJoint = y - halfH

– rope
for i = 1, 5 do
y = y + h
yJoint = yJoint + h

local body = display.newRect( x-halfW, y-halfH, w, h )

body:setFillColor( 255, 0, 0, 128 )
physics.addBody( body, { density=50, friction=0.5, bounce=.2 })
local joint = physics.newJoint( “pivot”, prevBody, body, xCenter, yJoint )

prevBody = body
end

– final body
y = y + halfH
local r = h*0.5
local body = display.newCircle( x, y, r )
body:setFillColor( 0, 0, 255, 128 )
physics.addBody( body, { density=2, friction=0.5, bounce=.2, radius=r })
local joint = physics.newJoint( “pivot”, prevBody, body, xCenter, y )

local ball = body
function dragBody( event, params )
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()

if “began” == phase then
stage:setFocus( body, event.id )
body.isFocus = true

– Create a temporary touch joint and store it in the object for later reference
if params and params.center then
– drag the body from its center point
body.tempJoint = physics.newJoint( “touch”, body, body.x, body.y )
else
– drag the body from the point where it was touched
body.tempJoint = physics.newJoint( “touch”, body, event.x, event.y )
end

– Apply optional joint parameters
if params then
local maxForce, frequency, dampingRatio

if params.maxForce then
– Internal default is (1000 * mass), so set this fairly high if setting manually
body.tempJoint.maxForce = params.maxForce
end

if params.frequency then
– This is the response speed of the elastic joint: higher numbers = less lag/bounce
body.tempJoint.frequency = params.frequency
end

if params.dampingRatio then
– Possible values: 0 (no damping) to 1.0 (critical damping)
body.tempJoint.dampingRatio = params.dampingRatio
end
end

elseif body.isFocus then
if “moved” == phase then

– Update the joint to track the touch
body.tempJoint:setTarget( event.x, event.y )

elseif “ended” == phase or “cancelled” == phase then
stage:setFocus( body, nil )
body.isFocus = false

– Remove the joint when the touch ends
body.tempJoint:removeSelf()

end
end

– Stop further propagation of touch event
return true
end
ball:addEventListener ( “touch”, dragBody )
[/code] [import]uid: 8196 topic_id: 3208 reply_id: 20469[/import]