New to Corona - Any Radgoll Examples?

25 replies [Last post]
ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

Just started using Corona and have done quite a few of the tutorials, was wondering if there was a simple ragdoll style example anyplace I could play around with?

If not could someone point me in the right direction as to where an explanation of this might be? Could really be in any language I guess and I could try and fiddle around with re-creating in Lua.

Thank you!

Replies

DavidBFox
User offline. Last seen 2 years 36 weeks ago. Offline
Joined: 10 Oct 2010

I'd love an example too!

ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

Well here is a first stab at some ragdoll code. I have a couple questions:

  1. 1. Is there a way to create an "object" or "group" like my ragdoll with multiple parts without having to set their coordinates based on the global position? It seems like it would be very difficult to make multiple ragdolls at different positions on the screen trying to keep the arms/legs/etc. all relative to the new positions.
  2. 2. Is there a way to optimize performance? It runs smoothly but the limbs get disjointed from time to time.

Please let me know of any better ways to do this. Thank you! This requires the "gameUI.lua" file also.

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
--> Setup Display
display.setStatusBar (display.HiddenStatusBar)
 
system.activate ("multitouch")
 
--> Start Physics
local physics = require ("physics")
local gameUI = require("gameUI")
 
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})
        
--> Create Ragdoll Group
 
local originX = 160
local originY = 50
 
local spacing = 1
 
local ragdoll = display.newGroup ()
 
local head = display.newCircle( 0, 0, 15 )
--local head = display.newImage( "head.png" )
head.x = originX
head.y = originY
head:setFillColor (255, 255, 255, 128)
ragdoll:insert (head)
 
local torsoA = display.newRect( 0, 0, 45, 24 )
torsoA.x = originX
torsoA.y = originY + head.height
torsoA:setFillColor (255, 255, 255, 128)
ragdoll:insert (torsoA)
 
local torsoB = display.newRect( 0, 0, 37.5, 24 )
torsoB.x = originX
torsoB.y = torsoA.y + (torsoA.height * 0.5) + spacing
torsoB:setFillColor (255, 255, 255, 128)
ragdoll:insert (torsoB)
 
local torsoC = display.newRect( 0, 0, 30, 24 )
torsoC.x = originX
torsoC.y = torsoB.y + (torsoB.height * 0.5) + spacing
torsoC:setFillColor (255, 255, 255, 128)
ragdoll:insert (torsoC)
 
local pelvis = display.newRect( 0, 0, 30, 24 )
pelvis.x = originX
pelvis.y = torsoC.y + (torsoC.height * 0.5) + spacing
pelvis:setFillColor (255, 255, 255, 128)
ragdoll:insert (pelvis)
 
local leftLegA = display.newRect( 0, 0, 12, 52.5 )
leftLegA.x = pelvis.x - ((pelvis.width - leftLegA.width) * 0.5)
leftLegA.y = pelvis.y + (leftLegA.height * 0.5) + spacing
leftLegA:setFillColor (255, 255, 255, 128)
ragdoll:insert (leftLegA)
 
local rightLegA = display.newRect( 0, 0, 12, 52.5 )
rightLegA.x = pelvis.x + ((pelvis.width - rightLegA.width) * 0.5)
rightLegA.y = pelvis.y + (rightLegA.height * 0.5) + spacing
rightLegA:setFillColor (255, 255, 255, 128)
ragdoll:insert (rightLegA)
 
local leftLegB = display.newRect( 0, 0, 12, 45 )
leftLegB.x = leftLegA.x
leftLegB.y = leftLegA.y + rightLegA.height - 12
leftLegB:setFillColor (255, 255, 255, 128)
ragdoll:insert (leftLegB)
 
local rightLegB = display.newRect( 0, 0, 12, 45 )
rightLegB.x = rightLegA.x
rightLegB.y = rightLegA.y + rightLegA.height - 12
rightLegB:setFillColor (255, 255, 255, 128)
ragdoll:insert (rightLegB)
 
local leftArmA = display.newRect( 125, 70, 10.5, 39 )
leftArmA.x = torsoA.x - (torsoA.width * 0.5) - 3
leftArmA.y = torsoA.y + (leftArmA.height * 0.5) - 6
leftArmA:setFillColor (255, 255, 255, 128)
ragdoll:insert (leftArmA)
 
local rightArmA = display.newRect( 185, 70, 10.5, 39 )
rightArmA.x = torsoA.x + (torsoA.width * 0.5) + 3
rightArmA.y = torsoA.y + (rightArmA.height * 0.5) - 6
rightArmA:setFillColor (255, 255, 255, 128)
ragdoll:insert (rightArmA)
 
local leftArmB = display.newRect( 125, 105, 10.5, 37.5 )
leftArmB.x = leftArmA.x
leftArmB.y = leftArmA.y + (leftArmA.height) - 6
leftArmB:setFillColor (255, 255, 255, 128)
ragdoll:insert (leftArmB)
 
local rightArmB = display.newRect( 185, 105, 10.5, 37.5 )
rightArmB.x = rightArmA.x
rightArmB.y = rightArmA.y + (rightArmA.height) - 6
rightArmB:setFillColor (255, 255, 255, 128)
ragdoll:insert (rightArmB)
 
physics.addBody (head, {bounce = 0.0, friction = 1.0})
physics.addBody (torsoA, {bounce = 0.0, friction = 1.0})
physics.addBody (torsoB, {bounce = 0.0, friction = 1.0})
physics.addBody (torsoC, {bounce = 0.0, friction = 1.0})
physics.addBody (pelvis, {bounce = 0.0, friction = 1.0})
physics.addBody (leftLegA, {bounce = 0.0, friction = 1.0})
physics.addBody (rightLegA, {bounce = 0.0, friction = 1.0})
physics.addBody (leftLegB, {bounce = 0.0, friction = 1.0})
physics.addBody (rightLegB, {bounce = 0.0, friction = 1.0})
physics.addBody (leftArmA, {bounce = 0.0, friction = 1.0})
physics.addBody (rightArmA, {bounce = 0.0, friction = 1.0})
physics.addBody (leftArmB, {bounce = 0.0, friction = 1.0})
physics.addBody (rightArmB, {bounce = 0.0, friction = 1.0})
 
local neckJoint = physics.newJoint ( "pivot", head, torsoA, torsoA.x, torsoA.y)
neckJoint.isLimitEnabled = true
neckJoint:setRotationLimits ( -22.5, 22.5 )
 
local backboneA = physics.newJoint ( "pivot", torsoA, torsoB, torsoB.x, torsoB.y )
backboneA.isLimitEnabled = true
backboneA:setRotationLimits ( -22.5, 22.5 )
 
local backboneB = physics.newJoint ( "pivot", torsoB, torsoC, torsoC.x, torsoC.y )
backboneB.isLimitEnabled = true
backboneB:setRotationLimits ( -22.5, 22.5 )
 
local backboneC = physics.newJoint ( "pivot", torsoC, pelvis, pelvis.x, pelvis.y )
backboneC.isLimitEnabled = true
backboneC:setRotationLimits ( -22.5, 22.5 )
 
local leftHip = physics.newJoint ( "pivot", pelvis, leftLegA, leftLegA.x, pelvis.y )
leftHip.isLimitEnabled = true
leftHip:setRotationLimits ( -45, 90 )
 
local rightHip = physics.newJoint ( "pivot", pelvis, rightLegA, rightLegA.x, pelvis.y )
rightHip.isLimitEnabled = true
rightHip:setRotationLimits ( -90, 45 )
 
local leftKnee = physics.newJoint ( "pivot", leftLegA, leftLegB, leftLegB.x, leftLegA.y + (leftLegA.height * 0.5) - 6 )
leftKnee.isLimitEnabled = true
leftKnee:setRotationLimits ( -45, 90 )
 
local rightKnee = physics.newJoint ( "pivot", rightLegA, rightLegB, rightLegB.x, rightLegA.y + (rightLegA.height * 0.5) - 6 )
rightKnee.isLimitEnabled = true
rightKnee:setRotationLimits ( -90, 45 )
 
local leftShoulder = physics.newJoint ( "pivot", torsoA, leftArmA, leftArmA.x, torsoA.y )
leftShoulder.isLimitEnabled = true
leftShoulder:setRotationLimits ( 0, 180 )
 
local rightShoulder = physics.newJoint ( "pivot", torsoA, rightArmA, rightArmA.x, torsoA.y )
rightShoulder.isLimitEnabled = true
rightShoulder:setRotationLimits ( -180, 0 )
 
local leftElbow = physics.newJoint ( "pivot", leftArmA, leftArmB, leftArmB.x, leftArmA.y + (leftArmA.height * 0.5) - 6 )
leftElbow.isLimitEnabled = true
leftElbow:setRotationLimits ( -45, 90 )
 
local rightElbow = physics.newJoint ( "pivot", rightArmA, rightArmB, rightArmB.x, rightArmA.y + (rightArmA.height * 0.5) - 6 )
rightElbow.isLimitEnabled = true
rightElbow:setRotationLimits ( -90, 45 )
 
local function dragBody( event )
        gameUI.dragBody( event )
end
 
head:addEventListener ( "touch", dragBody )
leftLegA:addEventListener ( "touch", dragBody )
leftLegB:addEventListener ( "touch", dragBody )
rightLegA:addEventListener ( "touch", dragBody )
rightLegB:addEventListener ( "touch", dragBody )
leftArmA:addEventListener ( "touch", dragBody )
leftArmB:addEventListener ( "touch", dragBody )
rightArmA:addEventListener ( "touch", dragBody )
rightArmB:addEventListener ( "touch", dragBody )

MarkHenryC
User offline. Last seen 22 weeks 6 days ago. Offline
Joined: 11 Nov 2009

Nice work!

Here's a simple way to bundle it into a module. Firstly, the calling code in main.lua:

1
2
3
4
5
6
7
8
9
10
require "ragdoll"
 
--> Setup Display
display.setStatusBar (display.HiddenStatusBar)
 
system.activate ("multitouch")
 
local walls = ragdoll.createWalls()
local doll1 = ragdoll.newRagDoll(40, 320) 
local doll2 = ragdoll.newRagDoll(280, 320) 

And here's ragdoll.lua (all your code of course):

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
module(..., package.seeall)
 
local gameUI = require("gameUI")
 
--> Start Physics
local physics = require ("physics")
 
physics.start ()
physics.setGravity (0, 10)
 
--physics.setDrawMode ("hybrid")
 
function createWalls()
        --> Create Walls
        
        local walls = display.newGroup()
        
        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})
        
        walls:insert(leftWall)
        walls:insert(rightWall)
        walls:insert(ceiling)
        walls:insert(floor)
        
        return walls
end
 
function newRagDoll(originX, originY) 
       
        --> Create Ragdoll Group
         
        local spacing = 1
         
        local ragdoll = display.newGroup ()
         
        local head = display.newCircle( 0, 0, 15 )
        --local head = display.newImage( "head.png" )
        head.x = originX
        head.y = originY
        head:setFillColor (255, 255, 255, 128)
        ragdoll:insert (head)
         
        local torsoA = display.newRect( 0, 0, 45, 24 )
        torsoA.x = originX
        torsoA.y = originY + head.height
        torsoA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoA)
         
        local torsoB = display.newRect( 0, 0, 37.5, 24 )
        torsoB.x = originX
        torsoB.y = torsoA.y + (torsoA.height * 0.5) + spacing
        torsoB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoB)
         
        local torsoC = display.newRect( 0, 0, 30, 24 )
        torsoC.x = originX
        torsoC.y = torsoB.y + (torsoB.height * 0.5) + spacing
        torsoC:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoC)
         
        local pelvis = display.newRect( 0, 0, 30, 24 )
        pelvis.x = originX
        pelvis.y = torsoC.y + (torsoC.height * 0.5) + spacing
        pelvis:setFillColor (255, 255, 255, 128)
        ragdoll:insert (pelvis)
         
        local leftLegA = display.newRect( 0, 0, 12, 52.5 )
        leftLegA.x = pelvis.x - ((pelvis.width - leftLegA.width) * 0.5)
        leftLegA.y = pelvis.y + (leftLegA.height * 0.5) + spacing
        leftLegA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftLegA)
         
        local rightLegA = display.newRect( 0, 0, 12, 52.5 )
        rightLegA.x = pelvis.x + ((pelvis.width - rightLegA.width) * 0.5)
        rightLegA.y = pelvis.y + (rightLegA.height * 0.5) + spacing
        rightLegA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightLegA)
         
        local leftLegB = display.newRect( 0, 0, 12, 45 )
        leftLegB.x = leftLegA.x
        leftLegB.y = leftLegA.y + rightLegA.height - 12
        leftLegB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftLegB)
         
        local rightLegB = display.newRect( 0, 0, 12, 45 )
        rightLegB.x = rightLegA.x
        rightLegB.y = rightLegA.y + rightLegA.height - 12
        rightLegB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightLegB)
         
        local leftArmA = display.newRect( 125, 70, 10.5, 39 )
        leftArmA.x = torsoA.x - (torsoA.width * 0.5) - 3
        leftArmA.y = torsoA.y + (leftArmA.height * 0.5) - 6
        leftArmA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftArmA)
         
        local rightArmA = display.newRect( 185, 70, 10.5, 39 )
        rightArmA.x = torsoA.x + (torsoA.width * 0.5) + 3
        rightArmA.y = torsoA.y + (rightArmA.height * 0.5) - 6
        rightArmA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightArmA)
         
        local leftArmB = display.newRect( 125, 105, 10.5, 37.5 )
        leftArmB.x = leftArmA.x
        leftArmB.y = leftArmA.y + (leftArmA.height) - 6
        leftArmB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftArmB)
         
        local rightArmB = display.newRect( 185, 105, 10.5, 37.5 )
        rightArmB.x = rightArmA.x
        rightArmB.y = rightArmA.y + (rightArmA.height) - 6
        rightArmB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightArmB)
         
        physics.addBody (head, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoA, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoB, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoC, {bounce = 0.0, friction = 1.0})
        physics.addBody (pelvis, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftLegA, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightLegA, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftLegB, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightLegB, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftArmA, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightArmA, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftArmB, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightArmB, {bounce = 0.0, friction = 1.0})
         
        local neckJoint = physics.newJoint ( "pivot", head, torsoA, torsoA.x, torsoA.y)
        neckJoint.isLimitEnabled = true
        neckJoint:setRotationLimits ( -22.5, 22.5 )
         
        local backboneA = physics.newJoint ( "pivot", torsoA, torsoB, torsoB.x, torsoB.y )
        backboneA.isLimitEnabled = true
        backboneA:setRotationLimits ( -22.5, 22.5 )
         
        local backboneB = physics.newJoint ( "pivot", torsoB, torsoC, torsoC.x, torsoC.y )
        backboneB.isLimitEnabled = true
        backboneB:setRotationLimits ( -22.5, 22.5 )
         
        local backboneC = physics.newJoint ( "pivot", torsoC, pelvis, pelvis.x, pelvis.y )
        backboneC.isLimitEnabled = true
        backboneC:setRotationLimits ( -22.5, 22.5 )
         
        local leftHip = physics.newJoint ( "pivot", pelvis, leftLegA, leftLegA.x, pelvis.y )
        leftHip.isLimitEnabled = true
        leftHip:setRotationLimits ( -45, 90 )
         
        local rightHip = physics.newJoint ( "pivot", pelvis, rightLegA, rightLegA.x, pelvis.y )
        rightHip.isLimitEnabled = true
        rightHip:setRotationLimits ( -90, 45 )
         
        local leftKnee = physics.newJoint ( "pivot", leftLegA, leftLegB, leftLegB.x, leftLegA.y + (leftLegA.height * 0.5) - 6 )
        leftKnee.isLimitEnabled = true
        leftKnee:setRotationLimits ( -45, 90 )
         
        local rightKnee = physics.newJoint ( "pivot", rightLegA, rightLegB, rightLegB.x, rightLegA.y + (rightLegA.height * 0.5) - 6 )
        rightKnee.isLimitEnabled = true
        rightKnee:setRotationLimits ( -90, 45 )
         
        local leftShoulder = physics.newJoint ( "pivot", torsoA, leftArmA, leftArmA.x, torsoA.y )
        leftShoulder.isLimitEnabled = true
        leftShoulder:setRotationLimits ( 0, 180 )
         
        local rightShoulder = physics.newJoint ( "pivot", torsoA, rightArmA, rightArmA.x, torsoA.y )
        rightShoulder.isLimitEnabled = true
        rightShoulder:setRotationLimits ( -180, 0 )
         
        local leftElbow = physics.newJoint ( "pivot", leftArmA, leftArmB, leftArmB.x, leftArmA.y + (leftArmA.height * 0.5) - 6 )
        leftElbow.isLimitEnabled = true
        leftElbow:setRotationLimits ( -45, 90 )
         
        local rightElbow = physics.newJoint ( "pivot", rightArmA, rightArmB, rightArmB.x, rightArmA.y + (rightArmA.height * 0.5) - 6 )
        rightElbow.isLimitEnabled = true
        rightElbow:setRotationLimits ( -90, 45 )
         
        function ragdoll:touch( event )
                gameUI.dragBody( event )
        end
         
        head:addEventListener ( "touch", ragdoll )
        leftLegA:addEventListener ( "touch", ragdoll )
        leftLegB:addEventListener ( "touch", ragdoll )
        rightLegA:addEventListener ( "touch", ragdoll )
        rightLegB:addEventListener ( "touch", ragdoll )
        leftArmA:addEventListener ( "touch", ragdoll )
        leftArmB:addEventListener ( "touch", ragdoll )
        rightArmA:addEventListener ( "touch", ragdoll )
        rightArmB:addEventListener ( "touch", ragdoll )
        
        return ragdoll
end

Tim
User offline. Last seen 9 years 16 weeks ago. Offline
Alumni
Joined: 12 Aug 2010

Really very cool. Thanks for sharing!

ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

Wow this is great! Thank you MarkHenryC, going to play a bit more with this today.

DavidBFox
User offline. Last seen 2 years 36 weeks ago. Offline
Joined: 10 Oct 2010

I'm wondering how we might add dampening to the joints so there's not so much jiggle/twitchiness (so when you drop one, you don't see it continuing to animate).

Also, if I wanted to use this to animate a stuffed animal, where the hinges feel less mechanical (and lubricated), how would I change this? For example, right now if you pick one up by the head, it tends to swing back and forth for a long time. Can friction be added to the joint?

I ended up adding touch listeners to every body part... made it easy to just pick it up at any point. I also added 'return true' at the end of the touch function... seemed to make it more stable.

ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

I was just looking around a bit in the docs and it doesn't seem as though you can control the angularDamping of a joint. You can control this on a body but unfortunately this has no effect once a joint has been applied.

Not sure if there is a work-around for this.

DavidBFox
User offline. Last seen 2 years 36 weeks ago. Offline
Joined: 10 Oct 2010

I see something called a friction joint, but it seems to break the program if I use it.

http://developer.anscamobile.com/content/friction-joint

I tried replacing

1
local neckJoint = physics.newJoint ( "pivot", head, torsoA, torsoA.x, torsoA.y)

with

1
local neckJoint = physics.newJoint ( "friction", head, torsoA, torsoA.x, torsoA.y)

and I get an error:

1
2
3
4
5
Runtime error: ...ev/Corona/Corona Game SampleCode/RagDoll/ragdoll.lua:139: attempt to call method 'setRotationLimits' (a string value)
stack traceback:
        [C]: in function 'setRotationLimits'
        ...ev/Corona/Corona Game SampleCode/RagDoll/ragdoll.lua:139: in function 'newRagDoll'
        ...e Dev/Corona/Corona Game SampleCode/RagDoll/main.lua:9: in main chunk

and commenting out the setRotationLimits line just makes the heads fall off.

Maybe this isn't actually implemented? Or I'm misunderstanding its use. From the documentation, it seems that rotation limits isn't supported by this, but even without limits, it still seems to not work.

I also see something called myJoint.dampingRatio for 'distance' joints. But this also doesn't support rotation limits, which I think you'd want for a rag doll.

MarkHenryC
User offline. Last seen 22 weeks 6 days ago. Offline
Joined: 11 Nov 2009

I see what you mean. According to the docs, friction joints are a type of pivot joint but clearly they're not as they don't support setRotationLimits(). And they don't seem to behave properly either. You can pull them off the join point.

Unless Ansca can provide working example, it might be worth posting to the bug database.

Meanwhile, this is the Box2D way of doing friction, which seems to work OK. Add these properties to create resistance:

1
2
3
        leftElbow.isMotorEnabled = true
        leftElbow.motorSpeed = 0
        leftElbow.maxMotorTorque = 100

MarkHenryC
User offline. Last seen 22 weeks 6 days ago. Offline
Joined: 11 Nov 2009

@ridiculous (nice sensible name that): now we have a bunch of Gumbies!

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
module(..., package.seeall)
 
local gameUI = require("gameUI")
 
--> Start Physics
local physics = require ("physics")
 
physics.start ()
physics.setGravity (0, 10)
 
--physics.setDrawMode ("hybrid")
 
function createWalls()
        --> Create Walls
        
        local walls = display.newGroup()
        
        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})
        
        walls:insert(leftWall)
        walls:insert(rightWall)
        walls:insert(ceiling)
        walls:insert(floor)
        
        return walls
end
 
function newRagDoll(originX, originY) 
       
        --> Create Ragdoll Group
         
        local spacing = 1
         
        local ragdoll = display.newGroup ()
         
        local head = display.newCircle( 0, 0, 15 )
        --local head = display.newImage( "head.png" )
        head.x = originX
        head.y = originY
        head:setFillColor (255, 255, 255, 128)
        ragdoll:insert (head)
         
        local torsoA = display.newRect( 0, 0, 45, 24 )
        torsoA.x = originX
        torsoA.y = originY + head.height
        torsoA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoA)
         
        local torsoB = display.newRect( 0, 0, 37.5, 24 )
        torsoB.x = originX
        torsoB.y = torsoA.y + (torsoA.height * 0.5) + spacing
        torsoB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoB)
         
        local torsoC = display.newRect( 0, 0, 30, 24 )
        torsoC.x = originX
        torsoC.y = torsoB.y + (torsoB.height * 0.5) + spacing
        torsoC:setFillColor (255, 255, 255, 128)
        ragdoll:insert (torsoC)
         
        local pelvis = display.newRect( 0, 0, 30, 24 )
        pelvis.x = originX
        pelvis.y = torsoC.y + (torsoC.height * 0.5) + spacing
        pelvis:setFillColor (255, 255, 255, 128)
        ragdoll:insert (pelvis)
         
        local leftLegA = display.newRect( 0, 0, 12, 52.5 )
        leftLegA.x = pelvis.x - ((pelvis.width - leftLegA.width) * 0.5)
        leftLegA.y = pelvis.y + (leftLegA.height * 0.5) + spacing
        leftLegA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftLegA)
         
        local rightLegA = display.newRect( 0, 0, 12, 52.5 )
        rightLegA.x = pelvis.x + ((pelvis.width - rightLegA.width) * 0.5)
        rightLegA.y = pelvis.y + (rightLegA.height * 0.5) + spacing
        rightLegA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightLegA)
         
        local leftLegB = display.newRect( 0, 0, 12, 45 )
        leftLegB.x = leftLegA.x
        leftLegB.y = leftLegA.y + rightLegA.height - 12
        leftLegB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftLegB)
         
        local rightLegB = display.newRect( 0, 0, 12, 45 )
        rightLegB.x = rightLegA.x
        rightLegB.y = rightLegA.y + rightLegA.height - 12
        rightLegB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightLegB)
         
        local leftArmA = display.newRect( 125, 70, 10.5, 39 )
        leftArmA.x = torsoA.x - (torsoA.width * 0.5) - 3
        leftArmA.y = torsoA.y + (leftArmA.height * 0.5) - 6
        leftArmA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftArmA)
         
        local rightArmA = display.newRect( 185, 70, 10.5, 39 )
        rightArmA.x = torsoA.x + (torsoA.width * 0.5) + 3
        rightArmA.y = torsoA.y + (rightArmA.height * 0.5) - 6
        rightArmA:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightArmA)
         
        local leftArmB = display.newRect( 125, 105, 10.5, 37.5 )
        leftArmB.x = leftArmA.x
        leftArmB.y = leftArmA.y + (leftArmA.height) - 6
        leftArmB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (leftArmB)
         
        local rightArmB = display.newRect( 185, 105, 10.5, 37.5 )
        rightArmB.x = rightArmA.x
        rightArmB.y = rightArmA.y + (rightArmA.height) - 6
        rightArmB:setFillColor (255, 255, 255, 128)
        ragdoll:insert (rightArmB)
         
        physics.addBody (head, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoA, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoB, {bounce = 0.0, friction = 1.0})
        physics.addBody (torsoC, {bounce = 0.0, friction = 1.0})
        physics.addBody (pelvis, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftLegA, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightLegA, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftLegB, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightLegB, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftArmA, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightArmA, {bounce = 0.0, friction = 1.0})
        physics.addBody (leftArmB, {bounce = 0.0, friction = 1.0})
        physics.addBody (rightArmB, {bounce = 0.0, friction = 1.0})
         
        function ragdoll:addFrictionJoint(a, b, posX, posY, rFrom, rTo, mT) 
                local j = physics.newJoint ( "pivot", a, b, posX, posY, rFrom, rTo)
                j.isLimitEnabled = true
                j:setRotationLimits (rFrom, rTo)
                j.isMotorEnabled = true
                j.motorSpeed = 0
                j.maxMotorTorque = mT or 1
                return j
        end
 
        -- neck 
        ragdoll:addFrictionJoint(head, torsoA, torsoA.x, torsoA.y, -22.5, 22.5)
        
        -- backboneA
         ragdoll:addFrictionJoint(torsoA, torsoB, torsoB.x, torsoB.y, -22.5, 22.5)
         
        -- backboneB
        ragdoll:addFrictionJoint(torsoB, torsoC, torsoC.x, torsoC.y, -22.5, 22.5)
        
        -- backboneC     
        ragdoll:addFrictionJoint(torsoC, pelvis, pelvis.x, pelvis.y, -22.5, 22.5)
        
        -- leftHip
        ragdoll:addFrictionJoint(pelvis, leftLegA, leftLegA.x, pelvis.y, -45, 90)
         
        -- rightHip
        ragdoll:addFrictionJoint(pelvis, rightLegA, rightLegA.x, pelvis.y, -90, 45)
         
        -- leftKnee
        ragdoll:addFrictionJoint(leftLegA, leftLegB, leftLegB.x, 
                leftLegA.y + leftLegA.height * 0.5 - 6, -45, 90)
 
        -- rightKnee
        ragdoll:addFrictionJoint(rightLegA, rightLegB, rightLegB.x, 
                rightLegA.y + rightLegA.height * 0.5 - 6, -90, 45)
        
        -- leftShoulder
        ragdoll:addFrictionJoint(torsoA, leftArmA, leftArmA.x, torsoA.y, 0, 180)
        
        -- rightShoulder
        ragdoll:addFrictionJoint(torsoA, rightArmA, rightArmA.x, torsoA.y, -180, 0)
        
        -- leftElbow
        ragdoll:addFrictionJoint(leftArmA, leftArmB, leftArmB.x, leftArmA.y + 
                leftArmA.height * 0.5 - 6, -45, 90)
        
        -- rightElbow
        ragdoll:addFrictionJoint(rightArmA, rightArmB, rightArmB.x, rightArmA.y + 
                rightArmA.height * 0.5 - 6, -90, 45)
         
        function ragdoll:touch( event )
                gameUI.dragBody( event )
        end
         
        head:addEventListener ( "touch", ragdoll )
        leftLegA:addEventListener ( "touch", ragdoll )
        leftLegB:addEventListener ( "touch", ragdoll )
        rightLegA:addEventListener ( "touch", ragdoll )
        rightLegB:addEventListener ( "touch", ragdoll )
        leftArmA:addEventListener ( "touch", ragdoll )
        leftArmB:addEventListener ( "touch", ragdoll )
        rightArmA:addEventListener ( "touch", ragdoll )
        rightArmB:addEventListener ( "touch", ragdoll )
        
        return ragdoll
end

ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

What fun!!! That's awesome!

Now we have battling action figures. Very cool, may I ask where you found the information about using motors to create resistance?

I can see I've now opened up a can of worms here, I'm supposed to be working in Flash but I'm afraid Corona will be taking up much of my time from now on :)

DavidBFox
User offline. Last seen 2 years 36 weeks ago. Offline
Joined: 10 Oct 2010

Nice, Mark!

I found that using a very small value for maxMotorTorque seems to do what I wanted. With values like .05 or .005, it gets rid of a lot of the twitchiness.

Also, I posted the friction joint question into the bug database.

MarkHenryC
User offline. Last seen 22 weeks 6 days ago. Offline
Joined: 11 Nov 2009

@ridiculous: I checked the Box2D docs. Good luck tearing yourself away from physics sims.
@David: thanks, that's useful info.

Swiftelf
User offline. Last seen 5 years 10 weeks ago. Offline
Joined: 24 Oct 2010

it's not working..

i copied and pasted the code in my main.lua and ragdoll.lua, and all i get is a black screen.

What am i doing wrong?

J. A. Whye
User offline. Last seen 4 weeks 4 days ago. Offline
Joined: 25 Sep 2010

Make sure you find the gameUI.lua file somewhere and put it in with the other two.

That's one thing I'd like to see -- all those Lua files that are needed for different things all in one spot. As it is I find myself scanning through the sample code folders trying to find them as I realize I need them.

The other thing to do is run it from the terminal-based simulator, that way you can see whatever error message is being produced.

Jay

Swiftelf
User offline. Last seen 5 years 10 weeks ago. Offline
Joined: 24 Oct 2010

thanks Jay, It worked :)

DavidBFox
User offline. Last seen 2 years 36 weeks ago. Offline
Joined: 10 Oct 2010

Jay, I'd like to see that too... or maybe some sort of path environment setup so that the compiler first looks in the local directory for the file, and if it's not there, looks in your designated lua library directory(s).

ridiculous
User offline. Last seen 9 years 37 weeks ago. Offline
Joined: 29 Oct 2010

Perhaps the files could be bundled in with the install? And imported directly from the app install dir?

achesser
User offline. Last seen 9 years 28 weeks ago. Offline
Joined: 14 Jan 2011

This is fantastic! I'm playing with it now. I've got a question if anyone else can help figure this out.
How the heck can you get the current X & Y coordinates of the component pieces or the group as a whole?

I'm running the code from above and it's making it's way on the screen and it's touchable and moveable... but the code I'm using to try and access the parts of the whole are unavailable.

1
2
3
4
r = newRagdoll
print ( r.x ) -- Outputs 0
print ( r.head.x ) -- Outputs "[string "return (r.head.x)"]:1: attempt to index field 'head' (a nil value)
"

Anyone see what I'm missing here?

EDIT - this seems to work.

1
2
3
4
        function ragdoll:touch( event )
           gameUI.dragBody( event )
           print (event.target.x)
        end

Edit 2 - grr... still need to access it from everywhere, not just the event.
I wish I understood how to access variables. Tips and links to tutorials are welcome!

BeyondtheTech
User offline. Last seen 18 weeks 2 hours ago. Offline
Joined: 14 Apr 2010

This example is great.

I just have a couple of questions...

With the first large code snippet, the ragdoll has no "strength," and the second, updated code snippet, the ragdoll is more rigid, but his joints act weird, like arms and legs sticking up a little too unnaturally.

Also, how do you adjust the size? I tried changing doll1.xScale or doll.width and, while it changes the size, it also affects the range. For example, if I change the width to 1/2, it bounces off in the middle of the screen and doesn't bounce at the wall.

ericdg123
User offline. Last seen 8 years 44 weeks ago. Offline
Joined: 19 Oct 2010

I just manually changed the sizes of the rects and then changed the pivot points accordingly. Most of the values are based on the sizes of other parts so it makes it easier.

The second example uses friction joints which reduces the movement of the joints. You can play around with the values and make it resist more or less.

gyrospeter
User offline. Last seen 8 years 28 weeks ago. Offline
Joined: 8 Jul 2011

Let's reanimate this old thread ;).

Is it possible to animate the ragdoll as if it is walking?
Any idea how to implement such thing? (I'm new to corona ;))

bcairns
User offline. Last seen 7 years 17 weeks ago. Offline
Joined: 19 Jun 2011

This is a great example thread, I wish I had found it earlier. One area the docs and sample code seem a little sparse is with regard to complex body/joint construction.

I just wanted to chip in about co-ordinate spaces and groups, in particular with respect to achesser's question above.

You don't HAVE to add all the component pieces to a group, as done in the example above. You can just attach them with joints via global (ie, "content") co-ordinates. If you do this, all the components will still exist in global co-ordinate system, and report all their values (x,y,rotation,etc) accordingly.

This is very useful if you want these components to interact with other objects specified in global co-ordinates!

For example, I have a spaceship with a gun turret attached via pivot joint. It makes more sense for these turrets to exist in the global co-ordinate space (instead of the ship group's local co-ordinate space), since they need to aim and fire at other objects in the global space. Therefore, I do NOT add the turrets to the ship's group.

If you do add the components to a group, you can convert local to global co-ordinates using the function: myGroup:localToContent( x, y ), and vice-versa with myGroup:contentToLocal( x, y ). But if you find yourself doing a lot of co-ordinate conversion, maybe ask yourself if your object is simply in the wrong co-ordinate space. :)

For people familiar with CSS, display groups are a lot like a container with "position: relative" set; all children of the group will be positioned relative to the parent. Of course unlike CSS containers, groups can be rotated, etc, which makes things considerably more complex.

Also, per ridiculous's original question: "1. Is there a way to create an "object" or "group" like my ragdoll with multiple parts without having to set their coordinates based on the global position?", I think if you provide object(s) to the group in its constructor, the group will be centered on those object(s) and everything added after that will be relative to those objects. So in the above code, since the head seems to be the origin point of the ragdoll, I think you could initialize the group with display.newGroup( head ), and then everything you add to the group after that will be relative to the head's position, instead of global position.

chicagodaly
User offline. Last seen 5 years 9 weeks ago. Offline
Joined: 11 Jul 2011

First off, great examples and tutorial.

I had a question - how does one manipulate the entire body/object as one? For example, if I wanted to create a "rag doll cannon" or launch this body/object in its entirety?

arlenraisbeck
User offline. Last seen 1 year 24 weeks ago. Offline
Joined: 7 Dec 2011

Have you tried applying a linear impulse to each body part simultaneously?

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.