box2d-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/box2d-rails.gemspec +20 -0
- data/lib/box2d-rails.rb +8 -0
- data/lib/box2d-rails/version.rb +5 -0
- data/vendor/assets/javascripts/box2d/collision/ClipVertex.js +35 -0
- data/vendor/assets/javascripts/box2d/collision/Features.js +61 -0
- data/vendor/assets/javascripts/box2d/collision/b2AABB.js +45 -0
- data/vendor/assets/javascripts/box2d/collision/b2Bound.js +43 -0
- data/vendor/assets/javascripts/box2d/collision/b2BoundValues.js +31 -0
- data/vendor/assets/javascripts/box2d/collision/b2BroadPhase.js +898 -0
- data/vendor/assets/javascripts/box2d/collision/b2BufferedPair.js +26 -0
- data/vendor/assets/javascripts/box2d/collision/b2Collision.js +738 -0
- data/vendor/assets/javascripts/box2d/collision/b2ContactID.js +52 -0
- data/vendor/assets/javascripts/box2d/collision/b2ContactPoint.js +35 -0
- data/vendor/assets/javascripts/box2d/collision/b2Distance.js +333 -0
- data/vendor/assets/javascripts/box2d/collision/b2Manifold.js +34 -0
- data/vendor/assets/javascripts/box2d/collision/b2OBB.js +34 -0
- data/vendor/assets/javascripts/box2d/collision/b2Pair.js +60 -0
- data/vendor/assets/javascripts/box2d/collision/b2PairCallback.js +34 -0
- data/vendor/assets/javascripts/box2d/collision/b2PairManager.js +386 -0
- data/vendor/assets/javascripts/box2d/collision/b2Proxy.js +40 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2BoxDef.js +49 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2CircleDef.js +49 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2CircleShape.js +198 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2MassData.js +36 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2PolyDef.js +58 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2PolyShape.js +492 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2Shape.js +339 -0
- data/vendor/assets/javascripts/box2d/collision/shapes/b2ShapeDef.js +109 -0
- data/vendor/assets/javascripts/box2d/common/b2Settings.js +72 -0
- data/vendor/assets/javascripts/box2d/common/math/b2Mat22.js +130 -0
- data/vendor/assets/javascripts/box2d/common/math/b2Math.js +218 -0
- data/vendor/assets/javascripts/box2d/common/math/b2Vec2.js +131 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2Body.js +469 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2BodyDef.js +69 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2CollisionFilter.js +42 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2ContactManager.js +337 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2Island.js +331 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2TimeStep.js +27 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2World.js +522 -0
- data/vendor/assets/javascripts/box2d/dynamics/b2WorldListener.js +52 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2CircleContact.js +102 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2Conservative.js +228 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2Contact.js +201 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2ContactConstraint.js +45 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2ContactConstraintPoint.js +40 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2ContactNode.js +33 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2ContactRegister.js +30 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2ContactSolver.js +537 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2NullContact.js +65 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2PolyAndCircleContact.js +103 -0
- data/vendor/assets/javascripts/box2d/dynamics/contacts/b2PolyContact.js +163 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2DistanceJoint.js +264 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2DistanceJointDef.js +49 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2GearJoint.js +307 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2GearJointDef.js +50 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2Jacobian.js +49 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2Joint.js +200 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2JointDef.js +40 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2JointNode.js +33 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2MouseJoint.js +234 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2MouseJointDef.js +53 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2PrismaticJoint.js +676 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2PrismaticJointDef.js +56 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2PulleyJoint.js +618 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2PulleyJointDef.js +70 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2RevoluteJoint.js +491 -0
- data/vendor/assets/javascripts/box2d/dynamics/joints/b2RevoluteJointDef.js +55 -0
- metadata +133 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2006-2007 Erin Catto http:
|
3
|
+
*
|
4
|
+
* This software is provided 'as-is', without any express or implied
|
5
|
+
* warranty. In no event will the authors be held liable for any damages
|
6
|
+
* arising from the use of this software.
|
7
|
+
* Permission is granted to anyone to use this software for any purpose,
|
8
|
+
* including commercial applications, and to alter it and redistribute it
|
9
|
+
* freely, subject to the following restrictions:
|
10
|
+
* 1. The origin of this software must not be misrepresented; you must not
|
11
|
+
* claim that you wrote the original software. If you use this software
|
12
|
+
* in a product, an acknowledgment in the product documentation would be
|
13
|
+
* appreciated but is not required.
|
14
|
+
* 2. Altered source versions must be plainly marked, and must not be
|
15
|
+
* misrepresented the original software.
|
16
|
+
* 3. This notice may not be removed or altered from any source distribution.
|
17
|
+
*/
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
/*
|
24
|
+
Position Correction Notes
|
25
|
+
=========================
|
26
|
+
I tried the several algorithms for position correction of the 2D revolute joint.
|
27
|
+
I looked at these systems:
|
28
|
+
- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
|
29
|
+
- suspension bridge with 30 1m long planks of length 1m.
|
30
|
+
- multi-link chain with 30 1m long links.
|
31
|
+
|
32
|
+
Here are the algorithms:
|
33
|
+
|
34
|
+
Baumgarte - A fraction of the position error is added to the velocity error. There is no
|
35
|
+
separate position solver.
|
36
|
+
|
37
|
+
Pseudo Velocities - After the velocity solver and position integration,
|
38
|
+
the position error, Jacobian, and effective mass are recomputed. Then
|
39
|
+
the velocity constraints are solved with pseudo velocities and a fraction
|
40
|
+
of the position error is added to the pseudo velocity error. The pseudo
|
41
|
+
velocities are initialized to zero and there is no warm-starting. After
|
42
|
+
the position solver, the pseudo velocities are added to the positions.
|
43
|
+
This is also called the First Order World method or the Position LCP method.
|
44
|
+
|
45
|
+
Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
|
46
|
+
position error is re-computed for each constraint and the positions are updated
|
47
|
+
after the constraint is solved. The radius vectors (aka Jacobians) are
|
48
|
+
re-computed too (otherwise the algorithm has horrible instability). The pseudo
|
49
|
+
velocity states are not needed because they are effectively zero at the beginning
|
50
|
+
of each iteration. Since we have the current position error, we allow the
|
51
|
+
iterations to terminate early if the error becomes smaller than b2_linearSlop.
|
52
|
+
|
53
|
+
Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
|
54
|
+
each time a constraint is solved.
|
55
|
+
|
56
|
+
Here are the results:
|
57
|
+
Baumgarte - this is the cheapest algorithm but it has some stability problems,
|
58
|
+
especially with the bridge. The chain links separate easily close to the root
|
59
|
+
and they jitter struggle to pull together. This is one of the most common
|
60
|
+
methods in the field. The big drawback is that the position correction artificially
|
61
|
+
affects the momentum, thus leading to instabilities and false bounce. I used a
|
62
|
+
bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
|
63
|
+
factor makes joints and contacts more spongy.
|
64
|
+
|
65
|
+
Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
|
66
|
+
stable. However, joints still separate with large angular velocities. Drag the
|
67
|
+
simple pendulum in a circle quickly and the joint will separate. The chain separates
|
68
|
+
easily and does not recover. I used a bias factor of 0.2. A larger value lead to
|
69
|
+
the bridge collapsing when a heavy cube drops on it.
|
70
|
+
|
71
|
+
Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
|
72
|
+
Velocities, but in other ways it is worse. The bridge and chain are much more
|
73
|
+
stable, but the simple pendulum goes unstable at high angular velocities.
|
74
|
+
|
75
|
+
Full NGS - stable in all tests. The joints display good stiffness. The bridge
|
76
|
+
still sags, but this is better than infinite forces.
|
77
|
+
|
78
|
+
Recommendations
|
79
|
+
Pseudo Velocities are not really worthwhile because the bridge and chain cannot
|
80
|
+
recover from joint separation. In other cases the benefit over Baumgarte is small.
|
81
|
+
|
82
|
+
Modified NGS is not a robust method for the revolute joint due to the violent
|
83
|
+
instability seen in the simple pendulum. Perhaps it is viable with other constraint
|
84
|
+
types, especially scalar constraints where the effective mass is a scalar.
|
85
|
+
|
86
|
+
This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
|
87
|
+
and is very fast. I don't think we can escape Baumgarte, especially in highly
|
88
|
+
demanding cases where high constraint fidelity is not needed.
|
89
|
+
|
90
|
+
Full NGS is robust and easy on the eyes. I recommend this option for
|
91
|
+
higher fidelity simulation and certainly for suspension bridges and long chains.
|
92
|
+
Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
|
93
|
+
joint separation can be problematic. The number of NGS iterations can be reduced
|
94
|
+
for better performance without harming robustness much.
|
95
|
+
|
96
|
+
Each joint in a can be handled differently in the position solver. So I recommend
|
97
|
+
a system where the user can select the algorithm on a per joint basis. I would
|
98
|
+
probably default to the slower Full NGS and let the user select the faster
|
99
|
+
Baumgarte method in performance critical scenarios.
|
100
|
+
*/
|
101
|
+
|
102
|
+
|
103
|
+
var b2Island = Class.create();
|
104
|
+
b2Island.prototype =
|
105
|
+
{
|
106
|
+
initialize: function(bodyCapacity, contactCapacity, jointCapacity, allocator)
|
107
|
+
{
|
108
|
+
var i = 0;
|
109
|
+
|
110
|
+
this.m_bodyCapacity = bodyCapacity;
|
111
|
+
this.m_contactCapacity = contactCapacity;
|
112
|
+
this.m_jointCapacity = jointCapacity;
|
113
|
+
this.m_bodyCount = 0;
|
114
|
+
this.m_contactCount = 0;
|
115
|
+
this.m_jointCount = 0;
|
116
|
+
|
117
|
+
|
118
|
+
//this.m_bodies = (b2Body**)allocator->Allocate(bodyCapacity * sizeof(b2Body*));
|
119
|
+
this.m_bodies = new Array(bodyCapacity);
|
120
|
+
for (i = 0; i < bodyCapacity; i++)
|
121
|
+
this.m_bodies[i] = null;
|
122
|
+
|
123
|
+
//this.m_contacts = (b2Contact**)allocator->Allocate(contactCapacity * sizeof(b2Contact*));
|
124
|
+
this.m_contacts = new Array(contactCapacity);
|
125
|
+
for (i = 0; i < contactCapacity; i++)
|
126
|
+
this.m_contacts[i] = null;
|
127
|
+
|
128
|
+
//this.m_joints = (b2Joint**)allocator->Allocate(jointCapacity * sizeof(b2Joint*));
|
129
|
+
this.m_joints = new Array(jointCapacity);
|
130
|
+
for (i = 0; i < jointCapacity; i++)
|
131
|
+
this.m_joints[i] = null;
|
132
|
+
|
133
|
+
this.m_allocator = allocator;
|
134
|
+
},
|
135
|
+
//~b2Island();
|
136
|
+
|
137
|
+
Clear: function()
|
138
|
+
{
|
139
|
+
this.m_bodyCount = 0;
|
140
|
+
this.m_contactCount = 0;
|
141
|
+
this.m_jointCount = 0;
|
142
|
+
},
|
143
|
+
|
144
|
+
Solve: function(step, gravity)
|
145
|
+
{
|
146
|
+
var i = 0;
|
147
|
+
var b;
|
148
|
+
|
149
|
+
for (i = 0; i < this.m_bodyCount; ++i)
|
150
|
+
{
|
151
|
+
b = this.m_bodies[i];
|
152
|
+
|
153
|
+
if (b.m_invMass == 0.0)
|
154
|
+
continue;
|
155
|
+
|
156
|
+
b.m_linearVelocity.Add( b2Math.MulFV (step.dt, b2Math.AddVV(gravity, b2Math.MulFV( b.m_invMass, b.m_force ) ) ) );
|
157
|
+
b.m_angularVelocity += step.dt * b.m_invI * b.m_torque;
|
158
|
+
|
159
|
+
//b.m_linearVelocity *= b.m_linearDamping;
|
160
|
+
b.m_linearVelocity.Multiply(b.m_linearDamping);
|
161
|
+
b.m_angularVelocity *= b.m_angularDamping;
|
162
|
+
|
163
|
+
// Store positions for conservative advancement.
|
164
|
+
b.m_position0.SetV(b.m_position);
|
165
|
+
b.m_rotation0 = b.m_rotation;
|
166
|
+
}
|
167
|
+
|
168
|
+
var contactSolver = new b2ContactSolver(this.m_contacts, this.m_contactCount, this.m_allocator);
|
169
|
+
|
170
|
+
// Pre-solve
|
171
|
+
contactSolver.PreSolve();
|
172
|
+
|
173
|
+
for (i = 0; i < this.m_jointCount; ++i)
|
174
|
+
{
|
175
|
+
this.m_joints[i].PrepareVelocitySolver();
|
176
|
+
}
|
177
|
+
|
178
|
+
// this.Solve velocity constraints.
|
179
|
+
for (i = 0; i < step.iterations; ++i)
|
180
|
+
{
|
181
|
+
contactSolver.SolveVelocityConstraints();
|
182
|
+
|
183
|
+
for (var j = 0; j < this.m_jointCount; ++j)
|
184
|
+
{
|
185
|
+
this.m_joints[j].SolveVelocityConstraints(step);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
// Integrate positions.
|
190
|
+
for (i = 0; i < this.m_bodyCount; ++i)
|
191
|
+
{
|
192
|
+
b = this.m_bodies[i];
|
193
|
+
|
194
|
+
if (b.m_invMass == 0.0)
|
195
|
+
continue;
|
196
|
+
|
197
|
+
//b.m_position.Add( b2Math.MulFV (step.dt, b.m_linearVelocity) );
|
198
|
+
b.m_position.x += step.dt * b.m_linearVelocity.x;
|
199
|
+
b.m_position.y += step.dt * b.m_linearVelocity.y;
|
200
|
+
b.m_rotation += step.dt * b.m_angularVelocity;
|
201
|
+
|
202
|
+
b.m_R.Set(b.m_rotation);
|
203
|
+
}
|
204
|
+
|
205
|
+
for (i = 0; i < this.m_jointCount; ++i)
|
206
|
+
{
|
207
|
+
this.m_joints[i].PreparePositionSolver();
|
208
|
+
}
|
209
|
+
|
210
|
+
// this.Solve position constraints.
|
211
|
+
if (b2World.s_enablePositionCorrection)
|
212
|
+
{
|
213
|
+
for (b2Island.m_positionIterationCount = 0; b2Island.m_positionIterationCount < step.iterations; ++b2Island.m_positionIterationCount)
|
214
|
+
{
|
215
|
+
var contactsOkay = contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte);
|
216
|
+
|
217
|
+
var jointsOkay = true;
|
218
|
+
for (i = 0; i < this.m_jointCount; ++i)
|
219
|
+
{
|
220
|
+
var jointOkay = this.m_joints[i].SolvePositionConstraints();
|
221
|
+
jointsOkay = jointsOkay && jointOkay;
|
222
|
+
}
|
223
|
+
|
224
|
+
if (contactsOkay && jointsOkay)
|
225
|
+
{
|
226
|
+
break;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
// Post-solve.
|
232
|
+
contactSolver.PostSolve();
|
233
|
+
|
234
|
+
// Synchronize shapes and reset forces.
|
235
|
+
for (i = 0; i < this.m_bodyCount; ++i)
|
236
|
+
{
|
237
|
+
b = this.m_bodies[i];
|
238
|
+
|
239
|
+
if (b.m_invMass == 0.0)
|
240
|
+
continue;
|
241
|
+
|
242
|
+
b.m_R.Set(b.m_rotation);
|
243
|
+
|
244
|
+
b.SynchronizeShapes();
|
245
|
+
b.m_force.Set(0.0, 0.0);
|
246
|
+
b.m_torque = 0.0;
|
247
|
+
}
|
248
|
+
},
|
249
|
+
|
250
|
+
UpdateSleep: function(dt)
|
251
|
+
{
|
252
|
+
var i = 0;
|
253
|
+
var b;
|
254
|
+
|
255
|
+
var minSleepTime = Number.MAX_VALUE;
|
256
|
+
|
257
|
+
var linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance;
|
258
|
+
var angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance;
|
259
|
+
|
260
|
+
for (i = 0; i < this.m_bodyCount; ++i)
|
261
|
+
{
|
262
|
+
b = this.m_bodies[i];
|
263
|
+
if (b.m_invMass == 0.0)
|
264
|
+
{
|
265
|
+
continue;
|
266
|
+
}
|
267
|
+
|
268
|
+
if ((b.m_flags & b2Body.e_allowSleepFlag) == 0)
|
269
|
+
{
|
270
|
+
b.m_sleepTime = 0.0;
|
271
|
+
minSleepTime = 0.0;
|
272
|
+
}
|
273
|
+
|
274
|
+
if ((b.m_flags & b2Body.e_allowSleepFlag) == 0 ||
|
275
|
+
b.m_angularVelocity * b.m_angularVelocity > angTolSqr ||
|
276
|
+
b2Math.b2Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr)
|
277
|
+
{
|
278
|
+
b.m_sleepTime = 0.0;
|
279
|
+
minSleepTime = 0.0;
|
280
|
+
}
|
281
|
+
else
|
282
|
+
{
|
283
|
+
b.m_sleepTime += dt;
|
284
|
+
minSleepTime = b2Math.b2Min(minSleepTime, b.m_sleepTime);
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
if (minSleepTime >= b2Settings.b2_timeToSleep)
|
289
|
+
{
|
290
|
+
for (i = 0; i < this.m_bodyCount; ++i)
|
291
|
+
{
|
292
|
+
b = this.m_bodies[i];
|
293
|
+
b.m_flags |= b2Body.e_sleepFlag;
|
294
|
+
}
|
295
|
+
}
|
296
|
+
},
|
297
|
+
|
298
|
+
AddBody: function(body)
|
299
|
+
{
|
300
|
+
//b2Settings.b2Assert(this.m_bodyCount < this.m_bodyCapacity);
|
301
|
+
this.m_bodies[this.m_bodyCount++] = body;
|
302
|
+
},
|
303
|
+
|
304
|
+
AddContact: function(contact)
|
305
|
+
{
|
306
|
+
//b2Settings.b2Assert(this.m_contactCount < this.m_contactCapacity);
|
307
|
+
this.m_contacts[this.m_contactCount++] = contact;
|
308
|
+
},
|
309
|
+
|
310
|
+
AddJoint: function(joint)
|
311
|
+
{
|
312
|
+
//b2Settings.b2Assert(this.m_jointCount < this.m_jointCapacity);
|
313
|
+
this.m_joints[this.m_jointCount++] = joint;
|
314
|
+
},
|
315
|
+
|
316
|
+
m_allocator: null,
|
317
|
+
|
318
|
+
m_bodies: null,
|
319
|
+
m_contacts: null,
|
320
|
+
m_joints: null,
|
321
|
+
|
322
|
+
m_bodyCount: 0,
|
323
|
+
m_jointCount: 0,
|
324
|
+
m_contactCount: 0,
|
325
|
+
|
326
|
+
m_bodyCapacity: 0,
|
327
|
+
m_contactCapacity: 0,
|
328
|
+
m_jointCapacity: 0,
|
329
|
+
|
330
|
+
m_positionError: null};
|
331
|
+
b2Island.m_positionIterationCount = 0;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2006-2007 Erin Catto http:
|
3
|
+
*
|
4
|
+
* This software is provided 'as-is', without any express or implied
|
5
|
+
* warranty. In no event will the authors be held liable for any damages
|
6
|
+
* arising from the use of this software.
|
7
|
+
* Permission is granted to anyone to use this software for any purpose,
|
8
|
+
* including commercial applications, and to alter it and redistribute it
|
9
|
+
* freely, subject to the following restrictions:
|
10
|
+
* 1. The origin of this software must not be misrepresented; you must not
|
11
|
+
* claim that you wrote the original software. If you use this software
|
12
|
+
* in a product, an acknowledgment in the product documentation would be
|
13
|
+
* appreciated but is not required.
|
14
|
+
* 2. Altered source versions must be plainly marked, and must not be
|
15
|
+
* misrepresented the original software.
|
16
|
+
* 3. This notice may not be removed or altered from any source distribution.
|
17
|
+
*/
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
var b2TimeStep = Class.create();
|
22
|
+
b2TimeStep.prototype =
|
23
|
+
{
|
24
|
+
dt: null,
|
25
|
+
inv_dt: null,
|
26
|
+
iterations: 0,
|
27
|
+
initialize: function() {}};
|
@@ -0,0 +1,522 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2006-2007 Erin Catto http:
|
3
|
+
*
|
4
|
+
* This software is provided 'as-is', without any express or implied
|
5
|
+
* warranty. In no event will the authors be held liable for any damages
|
6
|
+
* arising from the use of this software.
|
7
|
+
* Permission is granted to anyone to use this software for any purpose,
|
8
|
+
* including commercial applications, and to alter it and redistribute it
|
9
|
+
* freely, subject to the following restrictions:
|
10
|
+
* 1. The origin of this software must not be misrepresented; you must not
|
11
|
+
* claim that you wrote the original software. If you use this software
|
12
|
+
* in a product, an acknowledgment in the product documentation would be
|
13
|
+
* appreciated but is not required.
|
14
|
+
* 2. Altered source versions must be plainly marked, and must not be
|
15
|
+
* misrepresented the original software.
|
16
|
+
* 3. This notice may not be removed or altered from any source distribution.
|
17
|
+
*/
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
var b2World = Class.create();
|
23
|
+
b2World.prototype =
|
24
|
+
{
|
25
|
+
initialize: function(worldAABB, gravity, doSleep){
|
26
|
+
// initialize instance variables for references
|
27
|
+
this.step = new b2TimeStep();
|
28
|
+
this.m_contactManager = new b2ContactManager();
|
29
|
+
//
|
30
|
+
|
31
|
+
|
32
|
+
this.m_listener = null;
|
33
|
+
this.m_filter = b2CollisionFilter.b2_defaultFilter;
|
34
|
+
|
35
|
+
this.m_bodyList = null;
|
36
|
+
this.m_contactList = null;
|
37
|
+
this.m_jointList = null;
|
38
|
+
|
39
|
+
this.m_bodyCount = 0;
|
40
|
+
this.m_contactCount = 0;
|
41
|
+
this.m_jointCount = 0;
|
42
|
+
|
43
|
+
this.m_bodyDestroyList = null;
|
44
|
+
|
45
|
+
this.m_allowSleep = doSleep;
|
46
|
+
|
47
|
+
this.m_gravity = gravity;
|
48
|
+
|
49
|
+
this.m_contactManager.m_world = this;
|
50
|
+
this.m_broadPhase = new b2BroadPhase(worldAABB, this.m_contactManager);
|
51
|
+
|
52
|
+
var bd = new b2BodyDef();
|
53
|
+
this.m_groundBody = this.CreateBody(bd);
|
54
|
+
},
|
55
|
+
//~b2World(){
|
56
|
+
// this.DestroyBody(this.m_groundBody);
|
57
|
+
// delete this.m_broadPhase;
|
58
|
+
//}
|
59
|
+
|
60
|
+
// Set a callback to notify you when a joint is implicitly destroyed
|
61
|
+
// when an attached body is destroyed.
|
62
|
+
SetListener: function(listener){
|
63
|
+
this.m_listener = listener;
|
64
|
+
},
|
65
|
+
|
66
|
+
// Register a collision filter to provide specific control over collision.
|
67
|
+
// Otherwise the default filter is used (b2CollisionFilter).
|
68
|
+
SetFilter: function(filter){
|
69
|
+
this.m_filter = filter;
|
70
|
+
},
|
71
|
+
|
72
|
+
// Create and destroy rigid bodies. Destruction is deferred until the
|
73
|
+
// the next call to this.Step. This is done so that bodies may be destroyed
|
74
|
+
// while you iterate through the contact list.
|
75
|
+
CreateBody: function(def){
|
76
|
+
//void* mem = this.m_blockAllocator.Allocate(sizeof(b2Body));
|
77
|
+
var b = new b2Body(def, this);
|
78
|
+
b.m_prev = null;
|
79
|
+
|
80
|
+
b.m_next = this.m_bodyList;
|
81
|
+
if (this.m_bodyList)
|
82
|
+
{
|
83
|
+
this.m_bodyList.m_prev = b;
|
84
|
+
}
|
85
|
+
this.m_bodyList = b;
|
86
|
+
++this.m_bodyCount;
|
87
|
+
|
88
|
+
return b;
|
89
|
+
},
|
90
|
+
// Body destruction is deferred to make contact processing more robust.
|
91
|
+
DestroyBody: function(b)
|
92
|
+
{
|
93
|
+
|
94
|
+
if (b.m_flags & b2Body.e_destroyFlag)
|
95
|
+
{
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
// Remove from normal body list.
|
100
|
+
if (b.m_prev)
|
101
|
+
{
|
102
|
+
b.m_prev.m_next = b.m_next;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (b.m_next)
|
106
|
+
{
|
107
|
+
b.m_next.m_prev = b.m_prev;
|
108
|
+
}
|
109
|
+
|
110
|
+
if (b == this.m_bodyList)
|
111
|
+
{
|
112
|
+
this.m_bodyList = b.m_next;
|
113
|
+
}
|
114
|
+
|
115
|
+
b.m_flags |= b2Body.e_destroyFlag;
|
116
|
+
//b2Settings.b2Assert(this.m_bodyCount > 0);
|
117
|
+
--this.m_bodyCount;
|
118
|
+
|
119
|
+
//b->~b2Body();
|
120
|
+
//b.Destroy();
|
121
|
+
// Add to the deferred destruction list.
|
122
|
+
b.m_prev = null;
|
123
|
+
b.m_next = this.m_bodyDestroyList;
|
124
|
+
this.m_bodyDestroyList = b;
|
125
|
+
},
|
126
|
+
|
127
|
+
CleanBodyList: function()
|
128
|
+
{
|
129
|
+
this.m_contactManager.m_destroyImmediate = true;
|
130
|
+
|
131
|
+
var b = this.m_bodyDestroyList;
|
132
|
+
while (b)
|
133
|
+
{
|
134
|
+
//b2Settings.b2Assert((b.m_flags & b2Body.e_destroyFlag) != 0);
|
135
|
+
|
136
|
+
// Preserve the next pointer.
|
137
|
+
var b0 = b;
|
138
|
+
b = b.m_next;
|
139
|
+
|
140
|
+
// Delete the attached joints
|
141
|
+
var jn = b0.m_jointList;
|
142
|
+
while (jn)
|
143
|
+
{
|
144
|
+
var jn0 = jn;
|
145
|
+
jn = jn.next;
|
146
|
+
|
147
|
+
if (this.m_listener)
|
148
|
+
{
|
149
|
+
this.m_listener.NotifyJointDestroyed(jn0.joint);
|
150
|
+
}
|
151
|
+
|
152
|
+
this.DestroyJoint(jn0.joint);
|
153
|
+
}
|
154
|
+
|
155
|
+
b0.Destroy();
|
156
|
+
//this.m_blockAllocator.Free(b0, sizeof(b2Body));
|
157
|
+
}
|
158
|
+
|
159
|
+
// Reset the list.
|
160
|
+
this.m_bodyDestroyList = null;
|
161
|
+
|
162
|
+
this.m_contactManager.m_destroyImmediate = false;
|
163
|
+
},
|
164
|
+
|
165
|
+
CreateJoint: function(def){
|
166
|
+
var j = b2Joint.Create(def, this.m_blockAllocator);
|
167
|
+
|
168
|
+
// Connect to the world list.
|
169
|
+
j.m_prev = null;
|
170
|
+
j.m_next = this.m_jointList;
|
171
|
+
if (this.m_jointList)
|
172
|
+
{
|
173
|
+
this.m_jointList.m_prev = j;
|
174
|
+
}
|
175
|
+
this.m_jointList = j;
|
176
|
+
++this.m_jointCount;
|
177
|
+
|
178
|
+
// Connect to the bodies
|
179
|
+
j.m_node1.joint = j;
|
180
|
+
j.m_node1.other = j.m_body2;
|
181
|
+
j.m_node1.prev = null;
|
182
|
+
j.m_node1.next = j.m_body1.m_jointList;
|
183
|
+
if (j.m_body1.m_jointList) j.m_body1.m_jointList.prev = j.m_node1;
|
184
|
+
j.m_body1.m_jointList = j.m_node1;
|
185
|
+
|
186
|
+
j.m_node2.joint = j;
|
187
|
+
j.m_node2.other = j.m_body1;
|
188
|
+
j.m_node2.prev = null;
|
189
|
+
j.m_node2.next = j.m_body2.m_jointList;
|
190
|
+
if (j.m_body2.m_jointList) j.m_body2.m_jointList.prev = j.m_node2;
|
191
|
+
j.m_body2.m_jointList = j.m_node2;
|
192
|
+
|
193
|
+
// If the joint prevents collisions, then reset collision filtering.
|
194
|
+
if (def.collideConnected == false)
|
195
|
+
{
|
196
|
+
// Reset the proxies on the body with the minimum number of shapes.
|
197
|
+
var b = def.body1.m_shapeCount < def.body2.m_shapeCount ? def.body1 : def.body2;
|
198
|
+
for (var s = b.m_shapeList; s; s = s.m_next)
|
199
|
+
{
|
200
|
+
s.ResetProxy(this.m_broadPhase);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
return j;
|
205
|
+
},
|
206
|
+
DestroyJoint: function(j)
|
207
|
+
{
|
208
|
+
|
209
|
+
var collideConnected = j.m_collideConnected;
|
210
|
+
|
211
|
+
// Remove from the world.
|
212
|
+
if (j.m_prev)
|
213
|
+
{
|
214
|
+
j.m_prev.m_next = j.m_next;
|
215
|
+
}
|
216
|
+
|
217
|
+
if (j.m_next)
|
218
|
+
{
|
219
|
+
j.m_next.m_prev = j.m_prev;
|
220
|
+
}
|
221
|
+
|
222
|
+
if (j == this.m_jointList)
|
223
|
+
{
|
224
|
+
this.m_jointList = j.m_next;
|
225
|
+
}
|
226
|
+
|
227
|
+
// Disconnect from island graph.
|
228
|
+
var body1 = j.m_body1;
|
229
|
+
var body2 = j.m_body2;
|
230
|
+
|
231
|
+
// Wake up touching bodies.
|
232
|
+
body1.WakeUp();
|
233
|
+
body2.WakeUp();
|
234
|
+
|
235
|
+
// Remove from body 1
|
236
|
+
if (j.m_node1.prev)
|
237
|
+
{
|
238
|
+
j.m_node1.prev.next = j.m_node1.next;
|
239
|
+
}
|
240
|
+
|
241
|
+
if (j.m_node1.next)
|
242
|
+
{
|
243
|
+
j.m_node1.next.prev = j.m_node1.prev;
|
244
|
+
}
|
245
|
+
|
246
|
+
if (j.m_node1 == body1.m_jointList)
|
247
|
+
{
|
248
|
+
body1.m_jointList = j.m_node1.next;
|
249
|
+
}
|
250
|
+
|
251
|
+
j.m_node1.prev = null;
|
252
|
+
j.m_node1.next = null;
|
253
|
+
|
254
|
+
// Remove from body 2
|
255
|
+
if (j.m_node2.prev)
|
256
|
+
{
|
257
|
+
j.m_node2.prev.next = j.m_node2.next;
|
258
|
+
}
|
259
|
+
|
260
|
+
if (j.m_node2.next)
|
261
|
+
{
|
262
|
+
j.m_node2.next.prev = j.m_node2.prev;
|
263
|
+
}
|
264
|
+
|
265
|
+
if (j.m_node2 == body2.m_jointList)
|
266
|
+
{
|
267
|
+
body2.m_jointList = j.m_node2.next;
|
268
|
+
}
|
269
|
+
|
270
|
+
j.m_node2.prev = null;
|
271
|
+
j.m_node2.next = null;
|
272
|
+
|
273
|
+
b2Joint.Destroy(j, this.m_blockAllocator);
|
274
|
+
|
275
|
+
//b2Settings.b2Assert(this.m_jointCount > 0);
|
276
|
+
--this.m_jointCount;
|
277
|
+
|
278
|
+
// If the joint prevents collisions, then reset collision filtering.
|
279
|
+
if (collideConnected == false)
|
280
|
+
{
|
281
|
+
// Reset the proxies on the body with the minimum number of shapes.
|
282
|
+
var b = body1.m_shapeCount < body2.m_shapeCount ? body1 : body2;
|
283
|
+
for (var s = b.m_shapeList; s; s = s.m_next)
|
284
|
+
{
|
285
|
+
s.ResetProxy(this.m_broadPhase);
|
286
|
+
}
|
287
|
+
}
|
288
|
+
},
|
289
|
+
|
290
|
+
// The world provides a single ground body with no collision shapes. You
|
291
|
+
// can use this to simplify the creation of joints.
|
292
|
+
GetGroundBody: function(){
|
293
|
+
return this.m_groundBody;
|
294
|
+
},
|
295
|
+
|
296
|
+
|
297
|
+
step: new b2TimeStep(),
|
298
|
+
// this.Step
|
299
|
+
Step: function(dt, iterations){
|
300
|
+
|
301
|
+
var b;
|
302
|
+
var other;
|
303
|
+
|
304
|
+
|
305
|
+
this.step.dt = dt;
|
306
|
+
this.step.iterations = iterations;
|
307
|
+
if (dt > 0.0)
|
308
|
+
{
|
309
|
+
this.step.inv_dt = 1.0 / dt;
|
310
|
+
}
|
311
|
+
else
|
312
|
+
{
|
313
|
+
this.step.inv_dt = 0.0;
|
314
|
+
}
|
315
|
+
|
316
|
+
this.m_positionIterationCount = 0;
|
317
|
+
|
318
|
+
// Handle deferred contact destruction.
|
319
|
+
this.m_contactManager.CleanContactList();
|
320
|
+
|
321
|
+
// Handle deferred body destruction.
|
322
|
+
this.CleanBodyList();
|
323
|
+
|
324
|
+
// Update contacts.
|
325
|
+
this.m_contactManager.Collide();
|
326
|
+
|
327
|
+
// Size the island for the worst case.
|
328
|
+
var island = new b2Island(this.m_bodyCount, this.m_contactCount, this.m_jointCount, this.m_stackAllocator);
|
329
|
+
|
330
|
+
// Clear all the island flags.
|
331
|
+
for (b = this.m_bodyList; b != null; b = b.m_next)
|
332
|
+
{
|
333
|
+
b.m_flags &= ~b2Body.e_islandFlag;
|
334
|
+
}
|
335
|
+
for (var c = this.m_contactList; c != null; c = c.m_next)
|
336
|
+
{
|
337
|
+
c.m_flags &= ~b2Contact.e_islandFlag;
|
338
|
+
}
|
339
|
+
for (var j = this.m_jointList; j != null; j = j.m_next)
|
340
|
+
{
|
341
|
+
j.m_islandFlag = false;
|
342
|
+
}
|
343
|
+
|
344
|
+
// Build and simulate all awake islands.
|
345
|
+
var stackSize = this.m_bodyCount;
|
346
|
+
//var stack = (b2Body**)this.m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));
|
347
|
+
var stack = new Array(this.m_bodyCount);
|
348
|
+
for (var k = 0; k < this.m_bodyCount; k++)
|
349
|
+
stack[k] = null;
|
350
|
+
|
351
|
+
for (var seed = this.m_bodyList; seed != null; seed = seed.m_next)
|
352
|
+
{
|
353
|
+
if (seed.m_flags & (b2Body.e_staticFlag | b2Body.e_islandFlag | b2Body.e_sleepFlag | b2Body.e_frozenFlag))
|
354
|
+
{
|
355
|
+
continue;
|
356
|
+
}
|
357
|
+
|
358
|
+
// Reset island and stack.
|
359
|
+
island.Clear();
|
360
|
+
var stackCount = 0;
|
361
|
+
stack[stackCount++] = seed;
|
362
|
+
seed.m_flags |= b2Body.e_islandFlag;;
|
363
|
+
|
364
|
+
// Perform a depth first search (DFS) on the constraint graph.
|
365
|
+
while (stackCount > 0)
|
366
|
+
{
|
367
|
+
// Grab the next body off the stack and add it to the island.
|
368
|
+
b = stack[--stackCount];
|
369
|
+
island.AddBody(b);
|
370
|
+
|
371
|
+
// Make sure the body is awake.
|
372
|
+
b.m_flags &= ~b2Body.e_sleepFlag;
|
373
|
+
|
374
|
+
// To keep islands, we don't
|
375
|
+
// propagate islands across static bodies.
|
376
|
+
if (b.m_flags & b2Body.e_staticFlag)
|
377
|
+
{
|
378
|
+
continue;
|
379
|
+
}
|
380
|
+
|
381
|
+
// Search all contacts connected to this body.
|
382
|
+
for (var cn = b.m_contactList; cn != null; cn = cn.next)
|
383
|
+
{
|
384
|
+
if (cn.contact.m_flags & b2Contact.e_islandFlag)
|
385
|
+
{
|
386
|
+
continue;
|
387
|
+
}
|
388
|
+
|
389
|
+
island.AddContact(cn.contact);
|
390
|
+
cn.contact.m_flags |= b2Contact.e_islandFlag;
|
391
|
+
|
392
|
+
other = cn.other;
|
393
|
+
if (other.m_flags & b2Body.e_islandFlag)
|
394
|
+
{
|
395
|
+
continue;
|
396
|
+
}
|
397
|
+
|
398
|
+
//b2Settings.b2Assert(stackCount < stackSize);
|
399
|
+
stack[stackCount++] = other;
|
400
|
+
other.m_flags |= b2Body.e_islandFlag;
|
401
|
+
}
|
402
|
+
|
403
|
+
// Search all joints connect to this body.
|
404
|
+
for (var jn = b.m_jointList; jn != null; jn = jn.next)
|
405
|
+
{
|
406
|
+
if (jn.joint.m_islandFlag == true)
|
407
|
+
{
|
408
|
+
continue;
|
409
|
+
}
|
410
|
+
|
411
|
+
island.AddJoint(jn.joint);
|
412
|
+
jn.joint.m_islandFlag = true;
|
413
|
+
|
414
|
+
other = jn.other;
|
415
|
+
if (other.m_flags & b2Body.e_islandFlag)
|
416
|
+
{
|
417
|
+
continue;
|
418
|
+
}
|
419
|
+
|
420
|
+
//b2Settings.b2Assert(stackCount < stackSize);
|
421
|
+
stack[stackCount++] = other;
|
422
|
+
other.m_flags |= b2Body.e_islandFlag;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
426
|
+
island.Solve(this.step, this.m_gravity);
|
427
|
+
|
428
|
+
this.m_positionIterationCount = b2Math.b2Max(this.m_positionIterationCount, b2Island.m_positionIterationCount);
|
429
|
+
|
430
|
+
if (this.m_allowSleep)
|
431
|
+
{
|
432
|
+
island.UpdateSleep(dt);
|
433
|
+
}
|
434
|
+
|
435
|
+
// Post solve cleanup.
|
436
|
+
for (var i = 0; i < island.m_bodyCount; ++i)
|
437
|
+
{
|
438
|
+
// Allow static bodies to participate in other islands.
|
439
|
+
b = island.m_bodies[i];
|
440
|
+
if (b.m_flags & b2Body.e_staticFlag)
|
441
|
+
{
|
442
|
+
b.m_flags &= ~b2Body.e_islandFlag;
|
443
|
+
}
|
444
|
+
|
445
|
+
// Handle newly frozen bodies.
|
446
|
+
if (b.IsFrozen() && this.m_listener)
|
447
|
+
{
|
448
|
+
var response = this.m_listener.NotifyBoundaryViolated(b);
|
449
|
+
if (response == b2WorldListener.b2_destroyBody)
|
450
|
+
{
|
451
|
+
this.DestroyBody(b);
|
452
|
+
b = null;
|
453
|
+
island.m_bodies[i] = null;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
459
|
+
this.m_broadPhase.Commit();
|
460
|
+
|
461
|
+
//this.m_stackAllocator.Free(stack);
|
462
|
+
},
|
463
|
+
|
464
|
+
// this.Query the world for all shapes that potentially overlap the
|
465
|
+
// provided AABB. You provide a shape pointer buffer of specified
|
466
|
+
// size. The number of shapes found is returned.
|
467
|
+
Query: function(aabb, shapes, maxCount){
|
468
|
+
|
469
|
+
//void** results = (void**)this.m_stackAllocator.Allocate(maxCount * sizeof(void*));
|
470
|
+
var results = new Array();
|
471
|
+
var count = this.m_broadPhase.QueryAABB(aabb, results, maxCount);
|
472
|
+
|
473
|
+
for (var i = 0; i < count; ++i)
|
474
|
+
{
|
475
|
+
shapes[i] = results[i];
|
476
|
+
}
|
477
|
+
|
478
|
+
//this.m_stackAllocator.Free(results);
|
479
|
+
return count;
|
480
|
+
},
|
481
|
+
|
482
|
+
// You can use these to iterate over all the bodies, joints, and contacts.
|
483
|
+
GetBodyList: function(){
|
484
|
+
return this.m_bodyList;
|
485
|
+
},
|
486
|
+
GetJointList: function(){
|
487
|
+
return this.m_jointList;
|
488
|
+
},
|
489
|
+
GetContactList: function(){
|
490
|
+
return this.m_contactList;
|
491
|
+
},
|
492
|
+
|
493
|
+
//--------------- Internals Below -------------------
|
494
|
+
|
495
|
+
m_blockAllocator: null,
|
496
|
+
m_stackAllocator: null,
|
497
|
+
|
498
|
+
m_broadPhase: null,
|
499
|
+
m_contactManager: new b2ContactManager(),
|
500
|
+
|
501
|
+
m_bodyList: null,
|
502
|
+
m_contactList: null,
|
503
|
+
m_jointList: null,
|
504
|
+
|
505
|
+
m_bodyCount: 0,
|
506
|
+
m_contactCount: 0,
|
507
|
+
m_jointCount: 0,
|
508
|
+
|
509
|
+
// These bodies will be destroyed at the next time this.step.
|
510
|
+
m_bodyDestroyList: null,
|
511
|
+
|
512
|
+
m_gravity: null,
|
513
|
+
m_allowSleep: null,
|
514
|
+
|
515
|
+
m_groundBody: null,
|
516
|
+
|
517
|
+
m_listener: null,
|
518
|
+
m_filter: null,
|
519
|
+
|
520
|
+
m_positionIterationCount: 0};
|
521
|
+
b2World.s_enablePositionCorrection = 1;
|
522
|
+
b2World.s_enableWarmStarting = 1;
|