littlejsengine 1.9.6 → 1.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +13 -8
- package/dist/littlejs.d.ts +85 -84
- package/dist/littlejs.esm.js +370 -390
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +365 -386
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +302 -355
- package/examples/box2d/game.js +138 -0
- package/examples/box2d/index.html +25 -0
- package/examples/box2d/scenes.js +412 -0
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +3 -3
- package/examples/breakout/index.html +1 -0
- package/examples/platformer/gameEffects.js +2 -2
- package/examples/platformer/gameLevel.js +0 -1
- package/package.json +1 -1
- package/plugins/Box2D_v2.3.1_min.wasm.js +630 -0
- package/plugins/Box2D_v2.3.1_min.wasm.wasm +0 -0
- package/plugins/box2d.js +873 -0
- package/plugins/newgrounds.js +169 -0
- package/plugins/postProcess.js +101 -0
- package/src/engine.js +45 -26
- package/src/engineAudio.js +72 -47
- package/src/engineDebug.js +68 -33
- package/src/engineDraw.js +1 -1
- package/src/engineExport.js +5 -4
- package/src/engineMedals.js +39 -171
- package/src/engineObject.js +47 -4
- package/src/engineParticles.js +3 -0
- package/src/engineRelease.js +5 -2
- package/src/engineSettings.js +8 -3
- package/src/engineUtilities.js +81 -7
- package/src/engineWebGL.js +1 -94
package/plugins/box2d.js
ADDED
|
@@ -0,0 +1,873 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS Box2D Plugin
|
|
3
|
+
* - Box2dObject extends EngineObject with Box2D physics
|
|
4
|
+
* - Uses box2d.js super fast web assembly port of Box2D
|
|
5
|
+
* - More info: https://github.com/kripken/box2d.js
|
|
6
|
+
* - Functions to create polygon, circle, and edge shapes
|
|
7
|
+
* - Raycasting and querying
|
|
8
|
+
* - Joint creation
|
|
9
|
+
* - Contact begin and end callbacks
|
|
10
|
+
* - Debug physics drawing
|
|
11
|
+
* - Call box2dEngineInit to start
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
let box2d;
|
|
17
|
+
let box2dWorld;
|
|
18
|
+
let box2dDebugDraw;
|
|
19
|
+
let box2dDebug = false;
|
|
20
|
+
let box2dStepIterations = 3;
|
|
21
|
+
const box2dBodyTypeStatic = 0;
|
|
22
|
+
const box2dBodyTypeKinematic = 1;
|
|
23
|
+
const box2dBodyTypeDynamic = 2;
|
|
24
|
+
|
|
25
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
26
|
+
// Box2D Object - extend with your own custom physics objects
|
|
27
|
+
|
|
28
|
+
class Box2dObject extends EngineObject
|
|
29
|
+
{
|
|
30
|
+
constructor(pos=vec2(), size, tileInfo, angle=0, color, bodyType=box2dBodyTypeDynamic, renderOrder=0)
|
|
31
|
+
{
|
|
32
|
+
super(pos, size, tileInfo, angle, color, renderOrder);
|
|
33
|
+
|
|
34
|
+
// create physics body
|
|
35
|
+
const bodyDef = new box2d.b2BodyDef();
|
|
36
|
+
bodyDef.set_type(bodyType);
|
|
37
|
+
bodyDef.set_position(pos.getBox2d());
|
|
38
|
+
bodyDef.set_angle(-angle);
|
|
39
|
+
this.body = box2dWorld.CreateBody(bodyDef);
|
|
40
|
+
this.body.object = this;
|
|
41
|
+
this.outlineColor = BLACK;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
destroy()
|
|
45
|
+
{
|
|
46
|
+
// destroy physics body and fixtures
|
|
47
|
+
box2dWorld.DestroyBody(this.body);
|
|
48
|
+
super.destroy();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
update()
|
|
52
|
+
{
|
|
53
|
+
// use box2d physics update
|
|
54
|
+
this.pos.setBox2d(this.body.GetPosition());
|
|
55
|
+
this.angle = -this.body.GetAngle();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
render()
|
|
59
|
+
{
|
|
60
|
+
// use default render or draw fixtures
|
|
61
|
+
if (this.tileInfo)
|
|
62
|
+
super.render();
|
|
63
|
+
else
|
|
64
|
+
this.box2dDrawFixtures(this.color, this.outlineColor, this.lineWidth);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
renderDebugInfo()
|
|
68
|
+
{
|
|
69
|
+
const isAsleep = !this.getIsAwake();
|
|
70
|
+
const isStatic = this.getIsStatic();
|
|
71
|
+
const color = rgb(isAsleep,isAsleep,isStatic,.5);
|
|
72
|
+
this.box2dDrawFixtures(color);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
box2dDrawFixtures(fillColor=WHITE, outlineColor, lineWidth=.1)
|
|
76
|
+
{
|
|
77
|
+
this.getFixtureList().forEach(fixture=>
|
|
78
|
+
box2dDrawFixture(fixture, this.pos, this.angle, fillColor, outlineColor, lineWidth));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
82
|
+
// physics contact callbacks
|
|
83
|
+
|
|
84
|
+
beginContact(otherObject, contact) {}
|
|
85
|
+
endContact(otherObject, contact) {}
|
|
86
|
+
|
|
87
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
88
|
+
// physics fixtures and shapes
|
|
89
|
+
|
|
90
|
+
addFixture(fixtureDef) { return this.body.CreateFixture(fixtureDef); }
|
|
91
|
+
addShape(shape, density, friction, restitution, isSensor)
|
|
92
|
+
{
|
|
93
|
+
const fd = box2dCreateFixtureDef(shape, density, friction, restitution, isSensor);
|
|
94
|
+
this.addFixture(fd);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
addBox(size=vec2(1), offset=vec2(), angle=0, density, friction, restitution, isSensor)
|
|
98
|
+
{
|
|
99
|
+
const shape = new box2d.b2PolygonShape();
|
|
100
|
+
shape.SetAsBox(size.x/2, size.y/2, offset.getBox2d(), angle);
|
|
101
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addPoly(points, density, friction, restitution, isSensor)
|
|
105
|
+
{
|
|
106
|
+
const shape = box2dCreatePolygonShape(points);
|
|
107
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
addRegularPoly(diameter=1, sides=8, density, friction, restitution, isSensor)
|
|
111
|
+
{
|
|
112
|
+
const points = [];
|
|
113
|
+
const radius = diameter/2;
|
|
114
|
+
for (let i=sides; i--;)
|
|
115
|
+
points.push(vec2(radius,0).rotate((i+.5)/sides*PI*2));
|
|
116
|
+
this.addPoly(points, density, friction, restitution, isSensor);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
addRandomPoly(diameter=1, density, friction, restitution, isSensor)
|
|
120
|
+
{
|
|
121
|
+
const sides = randInt(3, 9);
|
|
122
|
+
const points = [];
|
|
123
|
+
const radius = diameter/2;
|
|
124
|
+
for (let i=sides; i--;)
|
|
125
|
+
points.push(vec2(rand(radius/2,radius*1.5),0).rotate(i/sides*PI*2));
|
|
126
|
+
this.addPoly(points, density, friction, restitution, isSensor);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
addCircle(diameter=1, offset=vec2(), density, friction, restitution, isSensor)
|
|
130
|
+
{
|
|
131
|
+
const shape = new box2d.b2CircleShape();
|
|
132
|
+
shape.set_m_p(offset.getBox2d());
|
|
133
|
+
shape.set_m_radius(diameter/2);
|
|
134
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
addEdge(point1, point2, density, friction, restitution, isSensor)
|
|
138
|
+
{
|
|
139
|
+
const shape = new box2d.b2EdgeShape();
|
|
140
|
+
shape.Set(point1.getBox2d(), point2.getBox2d());
|
|
141
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
addEdgeLoop(points, density, friction, restitution, isSensor)
|
|
145
|
+
{
|
|
146
|
+
const getPoint = i=> points[mod(i,points.length)];
|
|
147
|
+
for (let i=0; i<points.length; ++i)
|
|
148
|
+
{
|
|
149
|
+
const shape = new box2d.b2EdgeShape();
|
|
150
|
+
shape.set_m_vertex0(getPoint(i-1).getBox2d());
|
|
151
|
+
shape.set_m_vertex1(getPoint(i+0).getBox2d());
|
|
152
|
+
shape.set_m_vertex2(getPoint(i+1).getBox2d());
|
|
153
|
+
shape.set_m_vertex3(getPoint(i+2).getBox2d());
|
|
154
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
addEdgeList(points, density, friction, restitution, isSensor)
|
|
159
|
+
{
|
|
160
|
+
for (let i=0; i<points.length-1; ++i)
|
|
161
|
+
{
|
|
162
|
+
const shape = new box2d.b2EdgeShape();
|
|
163
|
+
points[i-1] && shape.set_m_vertex0(points[i-1].getBox2d());
|
|
164
|
+
points[i+0] && shape.set_m_vertex1(points[i+0].getBox2d());
|
|
165
|
+
points[i+1] && shape.set_m_vertex2(points[i+1].getBox2d());
|
|
166
|
+
points[i+2] && shape.set_m_vertex3(points[i+2].getBox2d());
|
|
167
|
+
this.addShape(shape, density, friction, restitution, isSensor);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
getFixtureList()
|
|
172
|
+
{
|
|
173
|
+
const fixtureList = [];
|
|
174
|
+
for (let fixture=this.body.GetFixtureList(); !box2dIsNull(fixture); )
|
|
175
|
+
{
|
|
176
|
+
fixtureList.push(fixture);
|
|
177
|
+
fixture = fixture.GetNext();
|
|
178
|
+
}
|
|
179
|
+
return fixtureList;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
183
|
+
// physics get functions
|
|
184
|
+
|
|
185
|
+
getCenterOfMass() { return vec2(this.body.GetWorldCenter()); }
|
|
186
|
+
getLinearVelocity() { return vec2(this.body.GetLinearVelocity()); }
|
|
187
|
+
getAngularVelocity() { return this.body.GetAngularVelocity(); }
|
|
188
|
+
getMass() { return this.body.GetMass(); }
|
|
189
|
+
getInertia() { return this.body.GetInertia(); }
|
|
190
|
+
getIsAwake() { return this.body.IsAwake(); }
|
|
191
|
+
getBodyType() { return this.body.GetType(); }
|
|
192
|
+
getIsStatic() { return this.getBodyType() == box2dBodyTypeStatic; }
|
|
193
|
+
getIsKinematic() { return this.getBodyType() == box2dBodyTypeStatic; }
|
|
194
|
+
getIsDynamic() { return this.getBodyType() == box2dBodyTypeDynamic; }
|
|
195
|
+
|
|
196
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
197
|
+
// physics set functions
|
|
198
|
+
|
|
199
|
+
setTransform(position, angle)
|
|
200
|
+
{
|
|
201
|
+
this.pos = position;
|
|
202
|
+
this.angle = angle;
|
|
203
|
+
this.body.SetTransform(position.getBox2d(), angle);
|
|
204
|
+
}
|
|
205
|
+
setPosition(position) { this.setTransform(position, this.body.GetAngle()); }
|
|
206
|
+
setAngle(angle) { this.setTransform(vec2(this.body.GetPosition()), -angle); }
|
|
207
|
+
setLinearVelocity(velocity) { this.body.SetLinearVelocity(velocity.getBox2d()); }
|
|
208
|
+
setAngularVelocity(angularVelocity) { this.body.SetAngularVelocity(angularVelocity); }
|
|
209
|
+
setLinearDamping(damping) { this.body.SetLinearDamping(damping); }
|
|
210
|
+
setAngularDamping(damping) { this.body.SetAngularDamping(damping); }
|
|
211
|
+
setGravityScale(scale=1) { this.body.SetGravityScale(this.gravityScale = scale); }
|
|
212
|
+
setBullet(isBullet=true) { this.body.SetBullet(isBullet); }
|
|
213
|
+
setAwake(isAwake=true) { this.body.SetAwake(isAwake); }
|
|
214
|
+
setBodyType(type) { this.body.SetType(type); }
|
|
215
|
+
setSleepingAllowed(isAllowed=true) { this.body.SetSleepingAllowed(isAllowed); }
|
|
216
|
+
setFixedRotation(isFixed=true) { this.body.SetFixedRotation(isFixed); }
|
|
217
|
+
setFilterData(categoryBits=0, ignoreCategoryBits=0, groupIndex=0)
|
|
218
|
+
{
|
|
219
|
+
this.getFixtureList().forEach(fixture=>
|
|
220
|
+
{
|
|
221
|
+
const filter = fixture.GetFilterData();
|
|
222
|
+
filter.set_categoryBits(categoryBits);
|
|
223
|
+
filter.set_maskBits(0xffff & ~ignoreCategoryBits);
|
|
224
|
+
filter.set_groupIndex(groupIndex);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
setSensor(isSensor=true)
|
|
228
|
+
{ this.getFixtureList().forEach(f=>f.SetSensor(isSensor)); }
|
|
229
|
+
|
|
230
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
231
|
+
// physics kinematics
|
|
232
|
+
|
|
233
|
+
applyForce(force, pos)
|
|
234
|
+
{
|
|
235
|
+
pos = pos || this.getCenterOfMass();
|
|
236
|
+
this.setAwake();
|
|
237
|
+
this.body.ApplyForce(force.getBox2d(), pos.getBox2d());
|
|
238
|
+
}
|
|
239
|
+
applyAcceleration(acceleration, pos)
|
|
240
|
+
{
|
|
241
|
+
pos = pos || this.getCenterOfMass();
|
|
242
|
+
this.setAwake();
|
|
243
|
+
this.body.ApplyLinearImpulse(acceleration.getBox2d(), pos.getBox2d());
|
|
244
|
+
}
|
|
245
|
+
applyTorque(torque)
|
|
246
|
+
{
|
|
247
|
+
this.setAwake();
|
|
248
|
+
this.body.ApplyTorque(torque);
|
|
249
|
+
}
|
|
250
|
+
applyAngularAcceleration(acceleration)
|
|
251
|
+
{
|
|
252
|
+
this.setAwake();
|
|
253
|
+
this.ApplyAngularImpulse(acceleration);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
258
|
+
// Box2D Raycasting and Querying
|
|
259
|
+
|
|
260
|
+
// result info for raycasts
|
|
261
|
+
class Box2dRaycastResult
|
|
262
|
+
{
|
|
263
|
+
constructor(fixture, point, normal, fraction)
|
|
264
|
+
{
|
|
265
|
+
this.fixture = fixture;
|
|
266
|
+
this.point = point;
|
|
267
|
+
this.normal = normal;
|
|
268
|
+
this.fraction = fraction;
|
|
269
|
+
this.object = fixture.GetBody().object;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// raycast and return a list of all results
|
|
274
|
+
function box2dRaycastAll(start, end)
|
|
275
|
+
{
|
|
276
|
+
const raycastCallback = new box2d.JSRayCastCallback();
|
|
277
|
+
raycastCallback.ReportFixture = function(fixturePointer, point, normal, fraction)
|
|
278
|
+
{
|
|
279
|
+
const fixture = box2d.wrapPointer(fixturePointer, box2d.b2Fixture);
|
|
280
|
+
point = vec2().setBox2dPointer(point);
|
|
281
|
+
normal = vec2().setBox2dPointer(normal);
|
|
282
|
+
raycastResults.push(new Box2dRaycastResult(fixture, point, normal, fraction));
|
|
283
|
+
return 1; // continue getting results
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const raycastResults = [];
|
|
287
|
+
box2dWorld.RayCast(raycastCallback, start.getBox2d(), end.getBox2d());
|
|
288
|
+
debugRaycast && debugLine(start, end, raycastResults.length ? '#f00' : '#00f', .02);
|
|
289
|
+
return raycastResults;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// raycast and return the first result
|
|
293
|
+
function box2dRaycast(start, end)
|
|
294
|
+
{
|
|
295
|
+
const raycastResults = box2dRaycastAll(start, end);
|
|
296
|
+
return raycastResults.length ?
|
|
297
|
+
raycastResults.reduce((a,b)=>a.fraction < b.fraction ? a : b) : undefined;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// box aabb cast and return the all results
|
|
301
|
+
function box2dBoxCastAll(pos, size)
|
|
302
|
+
{
|
|
303
|
+
const queryCallback = new box2d.JSQueryCallback();
|
|
304
|
+
queryCallback.ReportFixture = function(fixturePointer)
|
|
305
|
+
{
|
|
306
|
+
const fixture = box2d.wrapPointer(fixturePointer, box2d.b2Fixture);
|
|
307
|
+
const o = fixture.GetBody().object;
|
|
308
|
+
if (!queryObjects.includes(o))
|
|
309
|
+
queryObjects.push(o); // add if not already in list
|
|
310
|
+
return true; // continue getting results
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const aabb = new box2d.b2AABB();
|
|
314
|
+
aabb.set_lowerBound(pos.subtract(size.scale(.5)).getBox2d());
|
|
315
|
+
aabb.set_upperBound(pos.add(size.scale(.5)).getBox2d());
|
|
316
|
+
|
|
317
|
+
let queryObjects = [];
|
|
318
|
+
box2dWorld.QueryAABB(queryCallback, aabb);
|
|
319
|
+
debugRaycast && debugRect(pos, size, raycstResult ? '#f00' : '#00f', .02);
|
|
320
|
+
return queryObjects;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// box aabb cast and return the first result
|
|
324
|
+
function box2dBoxCast(pos, size)
|
|
325
|
+
{
|
|
326
|
+
const queryCallback = new box2d.JSQueryCallback();
|
|
327
|
+
queryCallback.ReportFixture = function(fixturePointer)
|
|
328
|
+
{
|
|
329
|
+
const fixture = box2d.wrapPointer(fixturePointer, box2d.b2Fixture);
|
|
330
|
+
queryObject = fixture.GetBody().object;
|
|
331
|
+
return false; // stop getting results
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const aabb = new box2d.b2AABB();
|
|
335
|
+
aabb.set_lowerBound(pos.subtract(size.scale(.5)).getBox2d());
|
|
336
|
+
aabb.set_upperBound(pos.add(size.scale(.5)).getBox2d());
|
|
337
|
+
|
|
338
|
+
let queryObject;
|
|
339
|
+
box2dWorld.QueryAABB(queryCallback, aabb);
|
|
340
|
+
debugRaycast && debugRect(pos, size, raycstResult ? '#f00' : '#00f', .02);
|
|
341
|
+
return queryObject;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// circle cast and return the all results
|
|
345
|
+
function box2dCircleCastAll(pos, diameter)
|
|
346
|
+
{
|
|
347
|
+
const radius2 = (diameter/2)**2;
|
|
348
|
+
const results = box2dBoxCastAll(pos, vec2(diameter));
|
|
349
|
+
return results.filter(o=>o.pos.distanceSquared(pos) < radius2);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// circle cast and return the first result
|
|
353
|
+
function box2dCircleCast(pos, diameter)
|
|
354
|
+
{
|
|
355
|
+
const radius2 = (diameter/2)**2;
|
|
356
|
+
let results = box2dBoxCastAll(pos, vec2(diameter));
|
|
357
|
+
results = results.filter(o=>o.pos.distanceSquared(pos) < radius2);
|
|
358
|
+
results = results.sort((a,b)=>a.pos.distanceSquared(pos)-b.pos.distanceSquared(pos));
|
|
359
|
+
return results[0];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// point cast and return the first result
|
|
363
|
+
function box2dPointCast(pos, dynamicOnly=true)
|
|
364
|
+
{
|
|
365
|
+
const queryCallback = new box2d.JSQueryCallback();
|
|
366
|
+
queryCallback.ReportFixture = function(fixturePointer)
|
|
367
|
+
{
|
|
368
|
+
const fixture = box2d.wrapPointer(fixturePointer, box2d.b2Fixture);
|
|
369
|
+
if (dynamicOnly && fixture.GetBody().GetType() != box2d.b2_dynamicBody)
|
|
370
|
+
return true; // continue getting results
|
|
371
|
+
if (!fixture.TestPoint(pos.getBox2d()))
|
|
372
|
+
return true; // continue getting results
|
|
373
|
+
queryResult = fixture.GetBody().object;
|
|
374
|
+
return false; // stop getting results
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const aabb = new box2d.b2AABB();
|
|
378
|
+
aabb.set_lowerBound(pos.getBox2d());
|
|
379
|
+
aabb.set_upperBound(pos.getBox2d());
|
|
380
|
+
|
|
381
|
+
let queryResult;
|
|
382
|
+
debugRaycast && debugRect(pos, vec2(), queryResult ? '#f00' : '#00f', .02);
|
|
383
|
+
box2dWorld.QueryAABB(queryCallback, aabb);
|
|
384
|
+
return queryResult;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
388
|
+
// Box2D Joints
|
|
389
|
+
|
|
390
|
+
function box2dCreateMouseJoint(object, fixedObject, worldPos)
|
|
391
|
+
{
|
|
392
|
+
object.setAwake();
|
|
393
|
+
const jointDef = new box2d.b2MouseJointDef();
|
|
394
|
+
jointDef.set_bodyA(fixedObject.body);
|
|
395
|
+
jointDef.set_bodyB(object.body);
|
|
396
|
+
jointDef.set_target(worldPos.getBox2d());
|
|
397
|
+
jointDef.set_maxForce(1e3 * object.getMass());
|
|
398
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function box2dCreateDistanceJoint(objectA, objectB, anchorA, anchorB, collide=false)
|
|
402
|
+
{
|
|
403
|
+
anchorA = anchorA || vec2(objectA.body.GetPosition());
|
|
404
|
+
anchorB = anchorB || vec2(objectB.body.GetPosition());
|
|
405
|
+
const localAnchorA = objectA.worldToLocal(anchorA);
|
|
406
|
+
const localAnchorB = objectB.worldToLocal(anchorB);
|
|
407
|
+
const jointDef = new box2d.b2DistanceJointDef();
|
|
408
|
+
jointDef.set_bodyA(objectA.body);
|
|
409
|
+
jointDef.set_bodyB(objectB.body);
|
|
410
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
411
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
412
|
+
jointDef.set_length(anchorA.distance(anchorB));
|
|
413
|
+
jointDef.set_collideConnected(collide);
|
|
414
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function box2dCreateRevoluteJoint(objectA, objectB, anchor, collide=false)
|
|
418
|
+
{
|
|
419
|
+
anchor = anchor || vec2(objectB.body.GetPosition());
|
|
420
|
+
const localAnchorA = objectA.worldToLocal(anchor);
|
|
421
|
+
const localAnchorB = objectB.worldToLocal(anchor);
|
|
422
|
+
const jointDef = new box2d.b2RevoluteJointDef();
|
|
423
|
+
jointDef.set_bodyA(objectA.body);
|
|
424
|
+
jointDef.set_bodyB(objectB.body);
|
|
425
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
426
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
427
|
+
jointDef.set_referenceAngle(objectA.body.GetAngle() - objectB.body.GetAngle());
|
|
428
|
+
jointDef.set_collideConnected(collide);
|
|
429
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function box2dCreatePrismaticJoint(objectA, objectB, anchor, worldAxis=vec2(0,1), collide=false)
|
|
433
|
+
{
|
|
434
|
+
anchor = anchor || vec2(objectB.body.GetPosition());
|
|
435
|
+
const localAnchorA = objectA.worldToLocal(anchor);
|
|
436
|
+
const localAnchorB = objectB.worldToLocal(anchor);
|
|
437
|
+
const localAxisA = objectB.worldToLocalVector(worldAxis);
|
|
438
|
+
const jointDef = new box2d.b2PrismaticJointDef();
|
|
439
|
+
jointDef.set_bodyA(objectA.body);
|
|
440
|
+
jointDef.set_bodyB(objectB.body);
|
|
441
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
442
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
443
|
+
jointDef.set_localAxisA(localAxisA.getBox2d());
|
|
444
|
+
jointDef.set_referenceAngle(objectA.body.GetAngle() - objectB.body.GetAngle());
|
|
445
|
+
jointDef.set_collideConnected(collide);
|
|
446
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function box2dCreateWheelJoint(objectA, objectB, anchor, worldAxis=vec2(0,1), collide=false)
|
|
450
|
+
{
|
|
451
|
+
anchor = anchor || vec2(objectB.body.GetPosition());
|
|
452
|
+
const localAnchorA = objectA.worldToLocal(anchor);
|
|
453
|
+
const localAnchorB = objectB.worldToLocal(anchor);
|
|
454
|
+
const localAxisA = objectB.worldToLocalVector(worldAxis);
|
|
455
|
+
const jointDef = new box2d.b2WheelJointDef();
|
|
456
|
+
jointDef.set_bodyA(objectA.body);
|
|
457
|
+
jointDef.set_bodyB(objectB.body);
|
|
458
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
459
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
460
|
+
jointDef.set_localAxisA(localAxisA.getBox2d());
|
|
461
|
+
jointDef.set_collideConnected(collide);
|
|
462
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function box2dCreateWeldJoint(objectA, objectB, anchor, collide=false)
|
|
466
|
+
{
|
|
467
|
+
anchor = anchor || vec2(objectB.body.GetPosition());
|
|
468
|
+
const localAnchorA = objectA.worldToLocal(anchor);
|
|
469
|
+
const localAnchorB = objectB.worldToLocal(anchor);
|
|
470
|
+
const jointDef = new box2d.b2WeldJointDef();
|
|
471
|
+
jointDef.set_bodyA(objectA.body);
|
|
472
|
+
jointDef.set_bodyB(objectB.body);
|
|
473
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
474
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
475
|
+
jointDef.set_referenceAngle(objectA.body.GetAngle() - objectB.body.GetAngle());
|
|
476
|
+
jointDef.set_collideConnected(collide);
|
|
477
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function box2dCreateFrictionJoint(objectA, objectB, anchor, collide=false)
|
|
481
|
+
{
|
|
482
|
+
anchor = anchor || vec2(objectB.body.GetPosition());
|
|
483
|
+
const localAnchorA = objectA.worldToLocal(anchor);
|
|
484
|
+
const localAnchorB = objectB.worldToLocal(anchor);
|
|
485
|
+
const jointDef = new box2d.b2FrictionJointDef();
|
|
486
|
+
jointDef.set_bodyA(objectA.body);
|
|
487
|
+
jointDef.set_bodyB(objectB.body);
|
|
488
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
489
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
490
|
+
jointDef.set_collideConnected(collide);
|
|
491
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function box2dCreateRopeJoint(objectA, objectB, anchorA, anchorB, extraLength=0, collide=false)
|
|
495
|
+
{
|
|
496
|
+
anchorA = anchorA || vec2(objectA.body.GetPosition());
|
|
497
|
+
anchorB = anchorB || vec2(objectB.body.GetPosition());
|
|
498
|
+
const localAnchorA = objectA.worldToLocal(anchorA);
|
|
499
|
+
const localAnchorB = objectB.worldToLocal(anchorB);
|
|
500
|
+
const jointDef = new box2d.b2RopeJointDef();
|
|
501
|
+
jointDef.set_bodyA(objectA.body);
|
|
502
|
+
jointDef.set_bodyB(objectB.body);
|
|
503
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
504
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
505
|
+
jointDef.set_maxLength(anchorA.distance(anchorB)+extraLength);
|
|
506
|
+
jointDef.set_collideConnected(collide);
|
|
507
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function box2dCreatePulleyJoint(objectA, objectB, groundAnchorA, groundAnchorB, anchorA, anchorB, ratio=1, collide=false)
|
|
511
|
+
{
|
|
512
|
+
anchorA = anchorA || vec2(objectA.body.GetPosition());
|
|
513
|
+
anchorB = anchorB || vec2(objectB.body.GetPosition());
|
|
514
|
+
const localAnchorA = objectA.worldToLocal(anchorA);
|
|
515
|
+
const localAnchorB = objectB.worldToLocal(anchorB);
|
|
516
|
+
const jointDef = new box2d.b2PulleyJointDef();
|
|
517
|
+
jointDef.set_bodyA(objectA.body);
|
|
518
|
+
jointDef.set_bodyB(objectB.body);
|
|
519
|
+
jointDef.set_groundAnchorA(groundAnchorA.getBox2d());
|
|
520
|
+
jointDef.set_groundAnchorB(groundAnchorB.getBox2d());
|
|
521
|
+
jointDef.set_localAnchorA(localAnchorA.getBox2d());
|
|
522
|
+
jointDef.set_localAnchorB(localAnchorB.getBox2d());
|
|
523
|
+
jointDef.set_ratio(ratio);
|
|
524
|
+
jointDef.set_lengthA(groundAnchorA.distance(anchorA));
|
|
525
|
+
jointDef.set_lengthB(groundAnchorB.distance(anchorB));
|
|
526
|
+
jointDef.set_collideConnected(collide);
|
|
527
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function box2dCreateMotorJoint(objectA, objectB)
|
|
531
|
+
{
|
|
532
|
+
const linearOffset = objectA.worldToLocal(vec2(objectB.body.GetPosition()));
|
|
533
|
+
const angularOffset = objectB.body.GetAngle() - objectA.body.GetAngle();
|
|
534
|
+
const jointDef = new box2d.b2MotorJointDef();
|
|
535
|
+
jointDef.set_bodyA(objectA.body);
|
|
536
|
+
jointDef.set_bodyB(objectB.body);
|
|
537
|
+
jointDef.set_linearOffset(linearOffset.getBox2d());
|
|
538
|
+
jointDef.set_angularOffset(angularOffset);
|
|
539
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function box2dCreateGearJoint(objectA, objectB, joint1, joint2, ratio=1)
|
|
543
|
+
{
|
|
544
|
+
const jointDef = new box2d.b2GearJointDef();
|
|
545
|
+
jointDef.set_bodyA(objectA.body);
|
|
546
|
+
jointDef.set_bodyB(objectB.body);
|
|
547
|
+
jointDef.set_joint1(joint1);
|
|
548
|
+
jointDef.set_joint2(joint2);
|
|
549
|
+
jointDef.set_ratio(ratio);
|
|
550
|
+
return box2dCastObject(box2dWorld.CreateJoint(jointDef));
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function box2dDestroyJoint(joint) { box2dWorld.DestroyJoint(joint); }
|
|
554
|
+
|
|
555
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
556
|
+
// Box2D Helper Functions
|
|
557
|
+
|
|
558
|
+
function box2dIsNull(object) { return !box2d.getPointer(object); }
|
|
559
|
+
|
|
560
|
+
function box2dCreateFixtureDef(shape, density=1, friction=.2, restitution=0, isSensor=false)
|
|
561
|
+
{
|
|
562
|
+
const fd = new box2d.b2FixtureDef();
|
|
563
|
+
fd.set_shape(shape);
|
|
564
|
+
fd.set_density(density);
|
|
565
|
+
fd.set_friction(friction);
|
|
566
|
+
fd.set_restitution(restitution);
|
|
567
|
+
fd.set_isSensor(isSensor);
|
|
568
|
+
return fd;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function box2dCreatePointList(points)
|
|
572
|
+
{
|
|
573
|
+
const buffer = box2d._malloc(points.length * 8);
|
|
574
|
+
for (let i=0, offset=0; i<points.length; ++i)
|
|
575
|
+
{
|
|
576
|
+
box2d.HEAPF32[buffer + offset >> 2] = points[i].x;
|
|
577
|
+
offset += 4;
|
|
578
|
+
box2d.HEAPF32[buffer + offset >> 2] = points[i].y;
|
|
579
|
+
offset += 4;
|
|
580
|
+
}
|
|
581
|
+
return box2d.wrapPointer(buffer, box2d.b2Vec2);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function box2dCreatePolygonShape(points)
|
|
585
|
+
{
|
|
586
|
+
ASSERT(3 <= points.length && points.length <= 8);
|
|
587
|
+
const shape = new box2d.b2PolygonShape();
|
|
588
|
+
const box2dPoints = box2dCreatePointList(points);
|
|
589
|
+
shape.Set(box2dPoints, points.length);
|
|
590
|
+
return shape;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function box2dCastObject(object)
|
|
594
|
+
{
|
|
595
|
+
if (object instanceof box2d.b2Shape)
|
|
596
|
+
{
|
|
597
|
+
switch (object.GetType())
|
|
598
|
+
{
|
|
599
|
+
case box2d.b2Shape.e_circle:
|
|
600
|
+
return box2d.castObject(object, box2d.b2CircleShape);
|
|
601
|
+
case box2d.b2Shape.e_edge:
|
|
602
|
+
return box2d.castObject(object, box2d.b2EdgeShape);
|
|
603
|
+
case box2d.b2Shape.e_polygon:
|
|
604
|
+
return box2d.castObject(object, box2d.b2PolygonShape);
|
|
605
|
+
case box2d.b2Shape.e_chain:
|
|
606
|
+
return box2d.castObject(object, box2d.b2ChainShape);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else if (object instanceof box2d.b2Joint)
|
|
610
|
+
{
|
|
611
|
+
switch (object.GetType())
|
|
612
|
+
{
|
|
613
|
+
case box2d.e_revoluteJoint:
|
|
614
|
+
return box2d.castObject(object, box2d.b2RevoluteJoint);
|
|
615
|
+
case box2d.e_prismaticJoint:
|
|
616
|
+
return box2d.castObject(object, box2d.b2PrismaticJoint);
|
|
617
|
+
case box2d.e_distanceJoint:
|
|
618
|
+
return box2d.castObject(object, box2d.b2DistanceJoint);
|
|
619
|
+
case box2d.e_pulleyJoint:
|
|
620
|
+
return box2d.castObject(object, box2d.b2PulleyJoint);
|
|
621
|
+
case box2d.e_mouseJoint:
|
|
622
|
+
return box2d.castObject(object, box2d.b2MouseJoint);
|
|
623
|
+
case box2d.e_gearJoint:
|
|
624
|
+
return box2d.castObject(object, box2d.b2GearJoint);
|
|
625
|
+
case box2d.e_wheelJoint:
|
|
626
|
+
return box2d.castObject(object, box2d.b2WheelJoint);
|
|
627
|
+
case box2d.e_weldJoint:
|
|
628
|
+
return box2d.castObject(object, box2d.b2WeldJoint);
|
|
629
|
+
case box2d.e_frictionJoint:
|
|
630
|
+
return box2d.castObject(object, box2d.b2FrictionJoint);
|
|
631
|
+
case box2d.e_ropeJoint:
|
|
632
|
+
return box2d.castObject(object, box2d.b2RopeJoint);
|
|
633
|
+
case box2d.e_motorJoint:
|
|
634
|
+
return box2d.castObject(object, box2d.b2MotorJoint);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
ASSERT(false, 'Unknown object type');
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
642
|
+
// Box2D Drawing
|
|
643
|
+
|
|
644
|
+
function box2dDrawFixture(fixture, pos, angle, fillColor, outlineColor, lineWidth)
|
|
645
|
+
{
|
|
646
|
+
const shape = box2dCastObject(fixture.GetShape());
|
|
647
|
+
switch (shape.GetType())
|
|
648
|
+
{
|
|
649
|
+
case box2d.b2Shape.e_polygon:
|
|
650
|
+
{
|
|
651
|
+
let points = [];
|
|
652
|
+
for (let i=shape.GetVertexCount(); i--;)
|
|
653
|
+
points.push(vec2(shape.GetVertex(i)));
|
|
654
|
+
box2dDrawPoly(pos, angle, points, fillColor, outlineColor, lineWidth);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
case box2d.b2Shape.e_circle:
|
|
658
|
+
{
|
|
659
|
+
const radius = shape.get_m_radius();
|
|
660
|
+
box2dDrawCircle(pos, radius, fillColor, outlineColor, lineWidth);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
case box2d.b2Shape.e_edge:
|
|
664
|
+
{
|
|
665
|
+
const v1 = vec2(shape.get_m_vertex1());
|
|
666
|
+
const v2 = vec2(shape.get_m_vertex2());
|
|
667
|
+
box2dDrawLine(pos, angle, v1, v2, fillColor, lineWidth);
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function box2dDrawCircle(pos, radius, color=WHITE, outlineColor, lineWidth=.1, context)
|
|
674
|
+
{
|
|
675
|
+
drawCanvas2D(pos, vec2(1), 0, 0, context=>
|
|
676
|
+
{
|
|
677
|
+
context.beginPath();
|
|
678
|
+
context.arc(0, 0, radius, 0, 9);
|
|
679
|
+
box2dDrawFillStroke(context, color, outlineColor, lineWidth);
|
|
680
|
+
}, 0, context);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function box2dDrawPoly(pos, angle, points, color=WHITE, outlineColor, lineWidth=.1, context)
|
|
684
|
+
{
|
|
685
|
+
drawCanvas2D(pos, vec2(1), angle, 0, context=>
|
|
686
|
+
{
|
|
687
|
+
context.beginPath();
|
|
688
|
+
points.forEach(p=>context.lineTo(p.x, p.y));
|
|
689
|
+
context.closePath();
|
|
690
|
+
box2dDrawFillStroke(context, color, outlineColor, lineWidth);
|
|
691
|
+
}, 0, context);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function box2dDrawLine(pos, angle, posA, posB, color=WHITE, lineWidth=.1, context)
|
|
695
|
+
{
|
|
696
|
+
drawCanvas2D(pos, vec2(1), angle, 0, context=>
|
|
697
|
+
{
|
|
698
|
+
context.beginPath();
|
|
699
|
+
context.lineTo(posA.x, posA.y);
|
|
700
|
+
context.lineTo(posB.x, posB.y);
|
|
701
|
+
box2dDrawFillStroke(context, 0, color, lineWidth);
|
|
702
|
+
}, 0, context);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function box2dDrawFillStroke(context, color, outlineColor, lineWidth)
|
|
706
|
+
{
|
|
707
|
+
if (color)
|
|
708
|
+
{
|
|
709
|
+
context.fillStyle = color.toString();
|
|
710
|
+
context.fill();
|
|
711
|
+
}
|
|
712
|
+
if (outlineColor && lineWidth)
|
|
713
|
+
{
|
|
714
|
+
context.lineWidth = lineWidth;
|
|
715
|
+
context.lineJoin = context.lineCap = 'round';
|
|
716
|
+
context.strokeStyle = outlineColor.toString();
|
|
717
|
+
context.stroke();
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
722
|
+
// Box2D Setup
|
|
723
|
+
|
|
724
|
+
function box2dEngineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources)
|
|
725
|
+
{
|
|
726
|
+
Box2D().then(_box2d=>
|
|
727
|
+
{
|
|
728
|
+
// setup box2d
|
|
729
|
+
box2d = _box2d;
|
|
730
|
+
box2dWorld = new box2d.b2World();
|
|
731
|
+
|
|
732
|
+
// override functions for box2d
|
|
733
|
+
setGravity = function(newGravity)
|
|
734
|
+
{
|
|
735
|
+
box2dWorld.SetGravity(vec2(0,newGravity).getBox2d());
|
|
736
|
+
gravity = newGravity*timeDelta*timeDelta; // engine gravity
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// allow passing box2d vectors to vec2
|
|
740
|
+
const defaultVec2 = vec2;
|
|
741
|
+
vec2 = function(x, y)
|
|
742
|
+
{
|
|
743
|
+
return (x instanceof box2d.b2Vec2) ?
|
|
744
|
+
new Vector2(x.get_x(), x.get_y()) : defaultVec2(x, y);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// functions to convert between vec2 and box2d vectors
|
|
748
|
+
Vector2.prototype.setBox2d = function(p) { return this.set(p.get_x(), p.get_y()); }
|
|
749
|
+
Vector2.prototype.getBox2d = function() { return new box2d.b2Vec2(this.x, this.y); }
|
|
750
|
+
Vector2.prototype.setBox2dPointer = function(p)
|
|
751
|
+
{ return this.setBox2d(box2d.wrapPointer(p, box2d.b2Vec2)); }
|
|
752
|
+
|
|
753
|
+
// functions to convert between color and box2d colors
|
|
754
|
+
Color.prototype.setBox2d = function(c)
|
|
755
|
+
{ return this.set(c.get_r(), c.get_g(), c.get_b()); }
|
|
756
|
+
Color.prototype.setBox2dPointer = function(c)
|
|
757
|
+
{ return this.setBox2d(box2d.wrapPointer(c, box2d.b2Color)); }
|
|
758
|
+
|
|
759
|
+
// setup contact listener
|
|
760
|
+
const listener = new box2d.JSContactListener();
|
|
761
|
+
listener.BeginContact = function(contactPtr)
|
|
762
|
+
{
|
|
763
|
+
const contact = box2d.wrapPointer(contactPtr, box2d.b2Contact);
|
|
764
|
+
const fixtureA = contact.GetFixtureA();
|
|
765
|
+
const fixtureB = contact.GetFixtureB();
|
|
766
|
+
const objectA = fixtureA.GetBody().object;
|
|
767
|
+
const objectB = fixtureB.GetBody().object;
|
|
768
|
+
objectA.beginContact(objectB, contact);
|
|
769
|
+
objectB.beginContact(objectA, contact);
|
|
770
|
+
}
|
|
771
|
+
listener.EndContact = function(contactPtr)
|
|
772
|
+
{
|
|
773
|
+
const contact = box2d.wrapPointer(contactPtr, box2d.b2Contact);
|
|
774
|
+
const fixtureA = contact.GetFixtureA();
|
|
775
|
+
const fixtureB = contact.GetFixtureB();
|
|
776
|
+
const objectA = fixtureA.GetBody().object;
|
|
777
|
+
const objectB = fixtureB.GetBody().object;
|
|
778
|
+
objectA.endContact(objectB, contact);
|
|
779
|
+
objectB.endContact(objectA, contact);
|
|
780
|
+
};
|
|
781
|
+
listener.PreSolve = function() {};
|
|
782
|
+
listener.PostSolve = function() {};
|
|
783
|
+
box2dWorld.SetContactListener(listener);
|
|
784
|
+
|
|
785
|
+
// setup debug draw
|
|
786
|
+
box2dDebugDraw = box2dGetDebugDraw();
|
|
787
|
+
box2dDebugDraw.AppendFlags(box2d.b2Draw.e_shapeBit);
|
|
788
|
+
box2dDebugDraw.AppendFlags(box2d.b2Draw.e_jointBit);
|
|
789
|
+
//box2dDebugDraw.AppendFlags(box2d.b2Draw.e_aabbBit);
|
|
790
|
+
//box2dDebugDraw.AppendFlags(box2d.b2Draw.e_pairBit);
|
|
791
|
+
//box2dDebugDraw.AppendFlags(box2d.b2Draw.e_centerOfMassBit);
|
|
792
|
+
box2dWorld.SetDebugDraw(box2dDebugDraw);
|
|
793
|
+
|
|
794
|
+
// hook up box2d plugin to update and render
|
|
795
|
+
addPluginUpdate(function()
|
|
796
|
+
{
|
|
797
|
+
const velocityIterations = box2dStepIterations;
|
|
798
|
+
const positionIterations = box2dStepIterations;
|
|
799
|
+
box2dWorld.Step(timeDelta, velocityIterations, positionIterations);
|
|
800
|
+
});
|
|
801
|
+
addPluginRender(function()
|
|
802
|
+
{
|
|
803
|
+
if (box2dDebug || debugPhysics && debugOverlay)
|
|
804
|
+
box2dWorld.DrawDebugData();
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// start littlejs
|
|
808
|
+
engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources);
|
|
809
|
+
|
|
810
|
+
// box2d debug drawing implementation
|
|
811
|
+
function box2dGetDebugDraw()
|
|
812
|
+
{
|
|
813
|
+
const debugDraw = new box2d.JSDraw();
|
|
814
|
+
debugDraw.DrawSegment = function(point1, point2, color)
|
|
815
|
+
{
|
|
816
|
+
color = getDebugColor(color);
|
|
817
|
+
point1 = vec2().setBox2dPointer(point1);
|
|
818
|
+
point2 = vec2().setBox2dPointer(point2);
|
|
819
|
+
box2dDrawLine(vec2(), 0, point1, point2, color, undefined, overlayContext);
|
|
820
|
+
};
|
|
821
|
+
debugDraw.DrawPolygon = function(vertices, vertexCount, color)
|
|
822
|
+
{
|
|
823
|
+
color = getDebugColor(color);
|
|
824
|
+
const points = getPointsList(vertices, vertexCount);
|
|
825
|
+
box2dDrawPoly(vec2(), 0, points, undefined, color, undefined, overlayContext);
|
|
826
|
+
};
|
|
827
|
+
debugDraw.DrawSolidPolygon = function(vertices, vertexCount, color)
|
|
828
|
+
{
|
|
829
|
+
color = getDebugColor(color);
|
|
830
|
+
const points = getPointsList(vertices, vertexCount);
|
|
831
|
+
box2dDrawPoly(vec2(), 0, points, color, color, undefined, overlayContext);
|
|
832
|
+
};
|
|
833
|
+
debugDraw.box2dDrawCircle = function(center, radius, color)
|
|
834
|
+
{
|
|
835
|
+
color = getDebugColor(color);
|
|
836
|
+
center = vec2().setBox2dPointer(center);
|
|
837
|
+
box2dDrawCircle(center, radius, undefined, color, undefined, overlayContext);
|
|
838
|
+
};
|
|
839
|
+
debugDraw.DrawSolidCircle = function(center, radius, axis, color)
|
|
840
|
+
{
|
|
841
|
+
color = getDebugColor(color);
|
|
842
|
+
center = vec2().setBox2dPointer(center);
|
|
843
|
+
axis = vec2().setBox2dPointer(axis).scale(radius);
|
|
844
|
+
box2dDrawCircle(center, radius, color, color, undefined, overlayContext);
|
|
845
|
+
box2dDrawLine(center, 0, vec2(), axis, color, undefined, overlayContext);
|
|
846
|
+
};
|
|
847
|
+
debugDraw.DrawTransform = function(transform)
|
|
848
|
+
{
|
|
849
|
+
transform = box2d.wrapPointer(transform, box2d.b2Transform);
|
|
850
|
+
const pos = vec2(transform.get_p());
|
|
851
|
+
const angle = -transform.get_q().GetAngle();
|
|
852
|
+
const p1 = vec2(1,0), c1 = rgb(.75,0,0,.8)
|
|
853
|
+
const p2 = vec2(0,1), c2 = rgb(0,.75,0,.8);
|
|
854
|
+
box2dDrawLine(pos, angle, vec2(), p1, c1, undefined, overlayContext);
|
|
855
|
+
box2dDrawLine(pos, angle, vec2(), p2, c2, undefined, overlayContext);
|
|
856
|
+
}
|
|
857
|
+
function getDebugColor(color)
|
|
858
|
+
{
|
|
859
|
+
color = rgb().setBox2dPointer(color);
|
|
860
|
+
color.a = .8;
|
|
861
|
+
return color;
|
|
862
|
+
}
|
|
863
|
+
function getPointsList(vertices, vertexCount)
|
|
864
|
+
{
|
|
865
|
+
const points = [];
|
|
866
|
+
for (let i=vertexCount; i--;)
|
|
867
|
+
points.push(vec2().setBox2dPointer(vertices+i*8));
|
|
868
|
+
return points
|
|
869
|
+
}
|
|
870
|
+
return debugDraw;
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|