Pivot Joints and apparent elasticity

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?

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

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?

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.

So... rag dolls difficult in Corona?

I was hoping to start building those next.

m

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.

A user posted a good ragdoll example on the forum

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

Tim

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

Can someone post a reproducible test case demonstrating the problem?

This requires the link.png from the chains example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
--> 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 )

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

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.

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.

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.

I'm so glad this is getting attention. I knew I wasn't crazy when I originally posted this. :)

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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)

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

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.

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
--> 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 )

It's cool you have some provided some better code for dragging stuff around but it does not address the core issue.

Corona is advertised as using Box 2d physics and it isn't doing it correctly. This is major issue and causing a lot of developers to have major issues with their projects. Many don't even know that is bug because they might think they are doing something wrong.

The ragdolls will still get hung up and have parts get separated whether dragged, flung or dropped in a simulation.

Try setting all of the joints to weld joints in that chain example and see the results. I tried to make a wheel joint and couldn't get it to do what I want. I thought it was something that I was doing and now after seeing the piston joint problem I doubt it since the wheel inherits from the piston joint.

As far as I can tell pivot, weld, piston and wheel joints exhibit some type of problem with separation or lack of constraints.

How can you make a game similar to Angry Birds or Ragdoll Blaster 2 with this engines current problems? At least with any kind of real professional polish?

I would like to see this issue taken very serious and put as high priority among the Corona developer. This should take precedence above most things being worked like windows mobile sdk work or even new features.

I would like to hear opinions from other developers.

-Monte

I have had instances with bad joints that have nothing to do with touch joints of player interaction at all.

Here's an easy test.

Make a rope.

Attach it to a static object.

Attach something dynamic to the other end

now drag stuff past the dynamic object

the rope unfailingly stretches out and it's not hard to get to the point where the joints are separated by entire screen lengths and begin to go nuts

this is using rope construction techniques straight out of the example code, checked and triple checked

While I would like to say that I do believe that the Corona SDK is the best available for the gamut it runs and the way it does, I have to agree with @montage and @desetto. The rag doll model (as well as the bridge sample, when many, many rocks are dropped) demonstrate something is very wrong and I believe this will turn away developers who have not found this issue in other SDK's.

Matt.

Thanks for the code tim. That seemed to work well. I noticed in the API reference joint.frequency and joint.dampingRatio says it is only used in distance joints. I guess it can be used in other types of joints as well?

I'm having trouble understanding the code sample.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 -- 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

It's important to realize that Box2D performs real physical simulations. Therefore, you must be careful to understand what is happening physically.

So first thing's first, the mass (as controlled by the "density" property) is critical. From a physical standpoint, the mass (via density) is where inertia comes from, meaning it determines how much it displaces due to momentum transfer.

This issue of mass is actually explained in the official Box2D documentation (Ch 13 of http://www.box2d.org/manual.html#_Toc258082979):

"Chains of bodies connected by joints may stretch if a lighter body is supporting a heavier body. For example, a wrecking ball connect to a chain of light weight bodies may not be stable. Stability degrades as the mass ratio passes 10:1."

In order for a chain of bodies to not stretch, the density must be sufficiently high. That's why in our Bridge sample code, there's a lot of bounce --- the density of the links is roughly the same as an individual boulder.

If you increase the density from 0.8 to 100, the bridge no longer stretches when the boulders fall. That's b/c, physically, the mass of the links is so large that inertia wins over any momentum of the boulder.

Now, regarding the issue of dragging objects around and stretching, you can either operate within the laws of physics (touch joints) or outside the laws of physics (directly setting x,y of the display object).

I've looked at other non-Corona sample code, and they all consistently do the former, i.e. they use touch joints (aka "mouse" joints) just like Tim's example above. With touch joints, you won't see the kind of stretching or elasticity you do if you bypass Box2D and set the x,y property of the display object directly.

(As an aside, in various non-Corona forum discussions around Box2D), there's mention of Box2D not liking the transforms for objects to be set directly, i.e. outside of Box2D, so it's a miracle that directly setting transform properties of physics objects works in Corona at all!)

In terms of best practices, here are our recommendations:
* If you don't want stretching, I recommend you use touch joints to allow the user to drag, like Tim's example above.
* If you want a more ragdoll effect where stretching does occur as you drag the object around, then you should directly set x,y of the object to allow the user to drag, like @montage's example above.

The best analogy I can come up with for the difference between the 2 dragging models is that with touch joints, Box2D applies a realistic force to the object, so you'll get physically realistic effects, whereas if you directly set x,y then you are letting the user act like a supernatural being who operates above the laws of physics --- in this case, you are applying what amounts to infinite forces, something no joint could possibly withstand.

Hope that helps!
walter

@ericdg123, that drag function came from the gameUI library that's in some of the sample code. I was looking at that too and it looks a little broken, since you can't actually pass a params argument to the listener function when the event occurs.

One solution is to create a closure. Below is a modification of Tim's example. You have a function (createDragBody) that creates another function (dragBody) that you pass as the listener. The created function (dragBody) is a closure b/c it stores values you passed to createDragBody. In the example below, I set the dampingRatio to 1.0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
--> 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
local function createDragBody( params )
        local function dragBody( event )
                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
                                print( "ratio", params.dampingRatio )
                                        -- 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
 
        return dragBody
end
 
local dragBody = createDragBody( { dampingRatio = 1.0 })
ball:addEventListener ( "touch", dragBody )

Much appreciated Walter and Tim. If you could address the piston/prismatic joint issue posted above and shed some of your insight on that I would be snug as a bug in a rug.

Judging from the complexity of the above responses and code, I am probably just doing something wrong or omitting something that needs to be there.

Walter? Tim? I have sent an email and was told to respond with sample code, which I did. I still have not heard anything back.

Please help with the piston joint issue.

@ericdg123, yes, there were issues with the piston joints. Essentially a unit conversion from screen pixels to box2d world units. Once daily builds are widely available, any daily build #280 or after should contain the fix.

#WIN

I had a quick followup question regarding the elastic quality of joints when used on rag doll. I understand that increasing the density of chains will help prevent elastic behaviour in those joints. What i'm encountering however is an issue when a ragdoll collides with a static object.

What happens now, is when the ragdoll hits a static block, limbs will often get caught on the corners stretching the joint of the rag doll. Ideally, the rag doll would either get caught on the object, or slink around it.

I'm currently using pivot joints with a rope / character of high density and static platforms of low density (unsure if density even matters for static objects).

Does anyone know of a potential solution for this behaviour? As it stands, the rag doll's functionality is potentially gamebreaking for my project.

Thanks!
-Nick

I'm in same boat as marouhn. For example, if my ragdoll is falling and its head hits the corner of a static object, such as a rectangular brick, the body will continue to fall while the head remains stuck to the brick. At a certain point the head will snap back to the body, but for a second or two there is a rather large and growing space between the head and the rest of the body. It's a very gruesome result for my otherwise family friendly game. I don't want to earn an "M" rating due to "simulated decapitation" so I don't think I can ship with this as is.

I've tried increasing body density 100x but get an identical result. I changed most physics bodies to spheres in hopes that there would be less corners for the ragdoll to get hung up on, and while that seems to help somewhat there are still many places where joints get stuck.

Ideally I'd like the ragdoll to slide around corners like a greased pig. But if not that at least have the object get hung up/stuck without the added injury of joint stretching.

If this isn't an issue with other implementations of Box2D (when Googling "box2d pivot joints separating" this thread is near the top) then it seems likely there's something broken with Corona's version. Ansca, please take a closer look at this issue.

Same problem here. Limbs get caught on corners and body torn apart in a morbid way :)

Been playing around different densities and joint overlaps for a couple of days already. Did anybody find solution to this ? If not, apparent issues with physics engine will be a definite dealbreaker for me. I really like the workflow and APIs in Corona, but this implementation of physics engine is just too faulty and limiting, so it's probably going to be for me:
"Good bye Corona, nice to see you again Cocos2D..."

The problem is that in Box2D pivot joints don't play well with any static objects. It's ok to have your borders as static objects or anything else that the ragdoll can't get hung up on as static. You can have platforms or other objects but they must be dynamic. You can use pivot joints to attach the platform to a static object and make the static object not collide with anything. Now your ragdoll will not tear apart when iteracting with the platform. You can make it so the platform doesn't rotate which will basicall lock it in place. You can use a weld joint or a pivot joint with body.isFixedrotation

The only problem is pivot joints aren't that cheap. Maybe weld joints are cheaper? I haven't tested that.

I hope this helps.

-Monte

With my ragdoll I've noticed increasing overall density does help with the joint separation problem. Also, try increasing the relative density of objects that tend to get hung up on static objects. For example, increasing the density of the head on my radgoll relative to the rest of the body parts removed the decapitation problem I was having. Once that problem went away the body getting stuck on static object corners became much less noticeable.

From my experience it seems that Box2D is just plain finicky about density. I'm not sure what the magic recipe is that prevents joint separation in Corona, other than to increase density, use 60 fps, and don't hang high density objects off low density objects (such as a heavy wrecking ball off the end of a low density chain).

Static object will apply infinite force to the joints so it doesn't matter how much desity you use it can still cause separation.

We did a lot of experimentation to try and solve this problem as well.

Like I said above the only solution we came up with to keep this from happening is to only use dynamic objects even if they are fixed in your scene. This will solve the problem. If it isn't a viable solution to your problem then I guess you're out of luck.

Someone from Ansca should chime in on this.

I almost emailed Carlos about this a few days ago because it is a big issue and if the solution is simply to do it a different way then someone should know. If the dynamic object solution what they use in flash? I find that hard to believe.

Of course, the dynamic object issue doesn't solve things like isFixedRotation conflicting with the pivot joint, but that's another issue...

Montage, thanks for an interesting workaround. It does make sense from a real-world perspective that no object can realistically be static, but from engine perspective I am not sure that Box2D doesn't take that into account.
The reason I say this is that I've been playing with various implementations of Box2D engine ( Flash, Cocos2D, OpenFrameworks ) and all across these platforms the results appeared consistent. I never seen such a drastic unexpected behavior as with Corona where it appears as if physics has a mind of its own, and a stubborn one.
So the time I am investing in trying to tame the wild physics is starting to slowly offset the time I gain by using Corona versus Cocos2D or even writing the game from scratch in pure C++.
Humm...... I guess I am so frustrated because otherwise I really like Corona but these issues render it practically useless for a range of projects I am planning to do :)

Works Well With Dynamic Platforms
Hi again, just wanted to confirm that works well with using platforms as dynamic objects welded to static objects. Great stuff and out of the box(2D) thinking :), thanks again ! :)
N

The link for entry #6 is no longer available!!

@fdt40: link works for me.

So I tried Montage's solution and made all my static objects dynamic, and attached them to non-colliding static "anchor" invisible objects. While it did seem to improve the stretchy joints on the ragdoll somewhat it didn't remove the problem for especially hard/fast collisions, and adding an extra display object, physics body, and joint to fake each static object was way too slow on devices I tested on, for the # of objects I have in a level. It basically halved my framerate. As Montage said, I guess I am out of luck.

I have spent probably a week on this one particular problem without a satisfactory solution or workaround. It seemed like there was some traction with Ansca on this issue a few months ago. Are stretchy joints still being looked at as an issue, or are they working as intended?

@XenonBL
Same here. After spending a month on/off trying to work around these issues including countless experiments with various joints connections and tweaking of density, physics iterations, and such, it just looks like there are some thing that you can't do with Corona and you should either try to work this limits into your advantage by altering the gameplay where applicable or use another platform.
Some things that, at least for me, never worked and as such are out of question when Corona is in question are whatever physics that involve strong forces and collisions with joints, especially things like shooting ragdolls, ball-chains and such. I would love to see an example of Ragdoll-Blaster type of game, but I guess doing it you would need so much additional joints/static bodies, so many physics iterations and not to say countless hours of tweaking parameters that the whole thing may not be feasible.
But then again, believable physics is not an easy thing to do on any platform. What I learned from month of (mostly unsuccessfully) trying to fix these issues is that the good physics is as much (or more) a question of thoughtful game design as of skillful coding. By that I mean balancing all gameplay parameters so that the user never gets the chance to put the physics world in a state of illogical distress. So if your game is all about throwing things as forcefully as possible into joint-ridden structures (as one of my prototypes was) then I guess you really are out of luck. But if you can think of the ways to introduce subtle gameplay modifications that would guide user interactions to produce a more acceptable physic behavior, then you might not need to spend countless hours tweaking.
I am just starting to apply this advice to my own prototypes. While it might not still have produced acceptable results it's certainly more fun to spend time thinking and experimenting with gameplay itself rather than tweaking the parameters, so I'm already much better. Hope this helps a bit.
Cheers :)

@junk

Yeah, it's good advice in general. Every platform has its limitations, and you can either spend months trying to fit a square peg in a round hole or be clever and work your game design around the limitations. I guess what's frustrating for me is that some features in Corona only seem half implemented, or there are bugs that are not even acknowledged, so it's difficult to know what the true limitations are.

During my testing on the stretchy joints issue I discovered that weld joints can't be destroyed using removeSelf, and friction joints don't appear to function at all. So while there is definitely something flaky about Corona's version of Box2D, it's difficult to know if my problems are due to inherent limitations of Box2D, bugs in Corona's implementation, or my own ineptitude as a programmer.

The issue is that you already spent a considerable amount of time "investigating". In my case, I studied Lua from zero, then started developing for the game, the physics was left for the last part because I THOUGHT it would work fine, but it doesnt!
I managed to convince a partner for the project, now he is disappointed and wants to abort the project!
I dont get why we have to waste time with trial and error and at the end hit the wall anyways.
A pivot is something simple, but then doesnt work and you have to find a workaround.
I dont think is fair, if the guys of Ansca "promised" physics, we should have physics and pivot is the simplest form of it.. why it doesnt work like a charm!
So, seems that the physics promised by Ansca is just for balloons or pillars, but you try do do a simple ragdoll and ends up with the legs inside the body, trembling in the floor and not lying flat but as if he is doing push-ups instead.
Again, I think it is not fair.

Any update to any of this?

I am working on creating something like a pendulum or chained ball swinging for an iPad game - and even using these examples, things are really weird and buggy.

The joints seem to stick together somewhat at least, but I am facing another problem:

Basically, the pendulum keeps swinging forever - the force seems to be constant or decreasing so slowly that it seems constant. I mean, ideally i would like, say, 10 swings and then to see everything settle - but this seems to go into tens of thousands.

To me, it seems like this relates to the gravity - I've tried changing it to higher values, changing the density of my ball body to no luck. And setting the physics scale doesn't work either - according to the "width of a sprite in pixels and divide it by its real-world width" guide, at the scale I want things (something the size a yoyo pretty close-up), I need to set my scale to something in the 1000s which just makes everything super buggy.

You can see the same thing in the example codes posted, as far as I can see, and my code is basically the same.

So how would you create a rope pendulum that actually stops swinging?

I guess I'll have to work around it, so it saddens me that I might have to settle for something that's not nearly as good looking as I would like to because of weird physics implementations. Every project I've approached with something relating to physics has been filled with headaches because of the way everything has been implemented.

That said I am grateful for everything Corona allows me to do – I really love it and I'll stick with it!

Any news on this? I've spent the last two months learning lua/corona and now it seems that the physics will be a deal breaker!

The only 'working' example of a vehicle I've seen is 'Billy Cart', which is all very good but is a hack, is not using the correct joints and would not do for an actual driving game.

The second example at the link below is how joints should work - is this still not possible using Corona?

http://www.emanueleferonato.com/2009/04/06/two-ways-to-make-box2d-cars/

Thanks!

views:12913 update:2011/10/4 8:06:35
corona forums © 2003-2011