planck-v2 2.0.0

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.

Potentially problematic release.


This version of planck-v2 might be problematic. Click here for more details.

Files changed (80) hide show
  1. package/LICENSE.txt +20 -0
  2. package/README.md +21 -0
  3. package/dist/planck-with-testbed.d.ts +4433 -0
  4. package/dist/planck-with-testbed.js +20730 -0
  5. package/dist/planck-with-testbed.js.map +1 -0
  6. package/dist/planck-with-testbed.umd.cjs +20730 -0
  7. package/dist/planck-with-testbed.umd.cjs.map +1 -0
  8. package/dist/planck.d.ts +4343 -0
  9. package/dist/planck.js +13516 -0
  10. package/dist/planck.js.map +1 -0
  11. package/dist/planck.umd.cjs +13516 -0
  12. package/dist/planck.umd.cjs.map +1 -0
  13. package/package.json +105 -0
  14. package/src/Settings.ts +238 -0
  15. package/src/__test__/Basic.test.ts +43 -0
  16. package/src/__test__/CCD.test.ts +70 -0
  17. package/src/__test__/Collision.test.ts +133 -0
  18. package/src/__test__/Math.test.ts +105 -0
  19. package/src/__test__/Pool.test.ts +48 -0
  20. package/src/__test__/World.test.ts +73 -0
  21. package/src/collision/AABB.ts +287 -0
  22. package/src/collision/BroadPhase.ts +210 -0
  23. package/src/collision/Distance.ts +962 -0
  24. package/src/collision/DynamicTree.ts +907 -0
  25. package/src/collision/Manifold.ts +420 -0
  26. package/src/collision/Raycast.ts +30 -0
  27. package/src/collision/Shape.ts +114 -0
  28. package/src/collision/TimeOfImpact.ts +502 -0
  29. package/src/collision/shape/BoxShape.ts +34 -0
  30. package/src/collision/shape/ChainShape.ts +360 -0
  31. package/src/collision/shape/CircleShape.ts +202 -0
  32. package/src/collision/shape/CollideCircle.ts +66 -0
  33. package/src/collision/shape/CollideCirclePolygon.ts +142 -0
  34. package/src/collision/shape/CollideEdgeCircle.ts +185 -0
  35. package/src/collision/shape/CollideEdgePolygon.ts +528 -0
  36. package/src/collision/shape/CollidePolygon.ts +280 -0
  37. package/src/collision/shape/EdgeShape.ts +316 -0
  38. package/src/collision/shape/PolygonShape.ts +581 -0
  39. package/src/common/Geo.ts +589 -0
  40. package/src/common/Jacobian.ts +17 -0
  41. package/src/common/Mat22.ts +221 -0
  42. package/src/common/Mat33.ts +224 -0
  43. package/src/common/Math.ts +96 -0
  44. package/src/common/Rot.ts +218 -0
  45. package/src/common/Sweep.ts +119 -0
  46. package/src/common/Transform.ts +203 -0
  47. package/src/common/Vec2.ts +624 -0
  48. package/src/common/Vec3.ts +188 -0
  49. package/src/dynamics/Body.ts +1198 -0
  50. package/src/dynamics/Contact.ts +1366 -0
  51. package/src/dynamics/Fixture.ts +506 -0
  52. package/src/dynamics/Joint.ts +226 -0
  53. package/src/dynamics/Position.ts +44 -0
  54. package/src/dynamics/Solver.ts +890 -0
  55. package/src/dynamics/Velocity.ts +18 -0
  56. package/src/dynamics/World.ts +1169 -0
  57. package/src/dynamics/joint/DistanceJoint.ts +463 -0
  58. package/src/dynamics/joint/FrictionJoint.ts +396 -0
  59. package/src/dynamics/joint/GearJoint.ts +591 -0
  60. package/src/dynamics/joint/MotorJoint.ts +430 -0
  61. package/src/dynamics/joint/MouseJoint.ts +390 -0
  62. package/src/dynamics/joint/PrismaticJoint.ts +903 -0
  63. package/src/dynamics/joint/PulleyJoint.ts +529 -0
  64. package/src/dynamics/joint/RevoluteJoint.ts +745 -0
  65. package/src/dynamics/joint/RopeJoint.ts +383 -0
  66. package/src/dynamics/joint/WeldJoint.ts +544 -0
  67. package/src/dynamics/joint/WheelJoint.ts +683 -0
  68. package/src/dynamics/joint/__test__/DistanceJoint.test.ts +66 -0
  69. package/src/index.ts +60 -0
  70. package/src/internal.ts +20 -0
  71. package/src/main.ts +3 -0
  72. package/src/serializer/__test__/Serialize.test.ts +52 -0
  73. package/src/serializer/__test__/Validator.test.ts +55 -0
  74. package/src/serializer/index.ts +257 -0
  75. package/src/serializer/schema.json +168 -0
  76. package/src/util/Pool.ts +120 -0
  77. package/src/util/Testbed.ts +157 -0
  78. package/src/util/Timer.ts +15 -0
  79. package/src/util/options.ts +28 -0
  80. package/src/util/stats.ts +26 -0
@@ -0,0 +1,506 @@
1
+ /*
2
+ * Planck.js
3
+ *
4
+ * Copyright (c) Erin Catto, Ali Shakiba
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ import * as geo from "../common/Geo";
11
+ import { options } from "../util/options";
12
+ import { Vec2Value } from "../common/Vec2";
13
+ import { AABB } from "../collision/AABB";
14
+ import { RayCastInput, RayCastOutput } from "../collision/Raycast";
15
+ import { Shape, ShapeType } from "../collision/Shape";
16
+ import { Body, MassData } from "./Body";
17
+ import { BroadPhase } from "../collision/BroadPhase";
18
+ import { TransformValue } from "../common/Transform";
19
+ import { Style } from "../util/Testbed";
20
+
21
+ /** @internal */ const _ASSERT = typeof ASSERT === "undefined" ? false : ASSERT;
22
+
23
+ /** @internal */ const synchronize_aabb1 = new AABB();
24
+ /** @internal */ const synchronize_aabb2 = new AABB();
25
+ /** @internal */ const displacement = geo.vec2(0, 0);
26
+
27
+ /**
28
+ * A fixture definition is used to create a fixture. This class defines an
29
+ * abstract fixture definition. You can reuse fixture definitions safely.
30
+ */
31
+ export interface FixtureOpt {
32
+ userData?: unknown;
33
+ /**
34
+ * The friction coefficient, usually in the range [0,1]
35
+ */
36
+ friction?: number;
37
+ /**
38
+ * The restitution (elasticity) usually in the range [0,1]
39
+ */
40
+ restitution?: number;
41
+ /**
42
+ * The density, usually in kg/m^2
43
+ */
44
+ density?: number;
45
+ /**
46
+ * A sensor shape collects contact information but never generates a collision response.
47
+ */
48
+ isSensor?: boolean;
49
+ /**
50
+ * Zero, positive or negative collision group.
51
+ * Fixtures with same positive groupIndex always collide and fixtures with same negative groupIndex never collide.
52
+ */
53
+ filterGroupIndex?: number;
54
+ /**
55
+ * Collision category bit or bits that this fixture belongs to.
56
+ * If groupIndex is zero or not matching, then at least one bit in this fixture categoryBits should match other fixture maskBits and vice versa.
57
+ */
58
+ filterCategoryBits?: number;
59
+ /**
60
+ * Collision category bit or bits that this fixture accept for collision.
61
+ */
62
+ filterMaskBits?: number;
63
+
64
+ /** Styling for dev-tools. */
65
+ style?: Style;
66
+ }
67
+
68
+ export interface FixtureDef extends FixtureOpt {
69
+ shape: Shape;
70
+ }
71
+
72
+ /** @internal */ const FixtureDefDefault: FixtureOpt = {
73
+ userData: null,
74
+ friction: 0.2,
75
+ restitution: 0.0,
76
+ density: 0.0,
77
+ isSensor: false,
78
+
79
+ filterGroupIndex: 0,
80
+ filterCategoryBits: 0x0001,
81
+ filterMaskBits: 0xffff,
82
+ };
83
+
84
+ /**
85
+ * This proxy is used internally to connect shape children to the broad-phase.
86
+ */
87
+ export class FixtureProxy {
88
+ aabb: AABB;
89
+ fixture: Fixture;
90
+ childIndex: number;
91
+ proxyId: number;
92
+ constructor(fixture: Fixture, childIndex: number) {
93
+ this.aabb = new AABB();
94
+ this.fixture = fixture;
95
+ this.childIndex = childIndex;
96
+ // this.proxyId;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * A fixture is used to attach a shape to a body for collision detection. A
102
+ * fixture inherits its transform from its parent. Fixtures hold additional
103
+ * non-geometric data such as friction, collision filters, etc.
104
+ *
105
+ * To create a new Fixture use {@link Body.createFixture}.
106
+ */
107
+ export class Fixture {
108
+ /** @internal */ m_body: Body;
109
+ /** @internal */ m_friction: number;
110
+ /** @internal */ m_restitution: number;
111
+ /** @internal */ m_density: number;
112
+ /** @internal */ m_isSensor: boolean;
113
+ /** @internal */ m_filterGroupIndex: number;
114
+ /** @internal */ m_filterCategoryBits: number;
115
+ /** @internal */ m_filterMaskBits: number;
116
+ /** @internal */ m_shape: Shape;
117
+ /** @internal */ m_next: Fixture | null;
118
+ /** @internal */ m_proxies: FixtureProxy[];
119
+ // 0 indicates inactive state, this is not the same as m_proxies.length
120
+ /** @internal */ m_proxyCount: number;
121
+ /** @internal */ m_userData: unknown;
122
+
123
+ /** Styling for dev-tools. */
124
+ style: Style = {};
125
+
126
+ /** @hidden @experimental Similar to userData, but used by dev-tools or runtime environment. */
127
+ appData: Record<string, any> = {};
128
+
129
+ constructor(body: Body, def: FixtureDef);
130
+ constructor(body: Body, shape: Shape, def?: FixtureOpt);
131
+ constructor(body: Body, shape: Shape, density?: number);
132
+ /** @internal */
133
+ constructor(body: Body, shape?, def?) {
134
+ if (shape.shape) {
135
+ def = shape;
136
+ shape = shape.shape;
137
+ } else if (typeof def === "number") {
138
+ def = { density: def };
139
+ }
140
+
141
+ def = options(def, FixtureDefDefault);
142
+
143
+ this.m_body = body;
144
+
145
+ this.m_friction = def.friction;
146
+ this.m_restitution = def.restitution;
147
+ this.m_density = def.density;
148
+ this.m_isSensor = def.isSensor;
149
+
150
+ this.m_filterGroupIndex = def.filterGroupIndex;
151
+ this.m_filterCategoryBits = def.filterCategoryBits;
152
+ this.m_filterMaskBits = def.filterMaskBits;
153
+
154
+ // TODO validate shape
155
+ this.m_shape = shape; // .clone();
156
+
157
+ this.m_next = null;
158
+
159
+ this.m_proxies = [];
160
+ this.m_proxyCount = 0;
161
+
162
+ // fixture proxies are created here,
163
+ // but they are activate in when a fixture is added to body
164
+ const childCount = this.m_shape.getChildCount();
165
+ for (let i = 0; i < childCount; ++i) {
166
+ this.m_proxies[i] = new FixtureProxy(this, i);
167
+ }
168
+
169
+ this.m_userData = def.userData;
170
+
171
+ if (typeof def.style === "object" && def.style !== null) {
172
+ this.style = def.style;
173
+ }
174
+ }
175
+
176
+ /** @hidden Re-setup fixture. */
177
+ _reset(): void {
178
+ const body = this.getBody();
179
+ const broadPhase = body.m_world.m_broadPhase;
180
+ this.destroyProxies(broadPhase);
181
+ if (this.m_shape._reset) {
182
+ this.m_shape._reset();
183
+ }
184
+ const childCount = this.m_shape.getChildCount();
185
+ for (let i = 0; i < childCount; ++i) {
186
+ this.m_proxies[i] = new FixtureProxy(this, i);
187
+ }
188
+ this.createProxies(broadPhase, body.m_xf);
189
+ body.resetMassData();
190
+ }
191
+
192
+ /** @hidden */
193
+ _serialize(): object {
194
+ return {
195
+ friction: this.m_friction,
196
+ restitution: this.m_restitution,
197
+ density: this.m_density,
198
+ isSensor: this.m_isSensor,
199
+
200
+ filterGroupIndex: this.m_filterGroupIndex,
201
+ filterCategoryBits: this.m_filterCategoryBits,
202
+ filterMaskBits: this.m_filterMaskBits,
203
+
204
+ shape: this.m_shape,
205
+ };
206
+ }
207
+
208
+ /** @hidden */
209
+ static _deserialize(data: any, body: any, restore: any): Fixture {
210
+ const shape = restore(Shape, data.shape);
211
+ const fixture = shape && new Fixture(body, shape, data);
212
+ return fixture;
213
+ }
214
+
215
+ /**
216
+ * Get the type of the child shape. You can use this to down cast to the
217
+ * concrete shape.
218
+ */
219
+ getType(): ShapeType {
220
+ return this.m_shape.m_type;
221
+ }
222
+
223
+ /**
224
+ * Get the child shape. You can modify the child shape, however you should not
225
+ * change the number of vertices because this will crash some collision caching
226
+ * mechanisms. Manipulating the shape may lead to non-physical behavior.
227
+ */
228
+ getShape(): Shape {
229
+ return this.m_shape;
230
+ }
231
+
232
+ /**
233
+ * A sensor shape collects contact information but never generates a collision
234
+ * response.
235
+ */
236
+ isSensor(): boolean {
237
+ return this.m_isSensor;
238
+ }
239
+
240
+ /**
241
+ * Set if this fixture is a sensor.
242
+ */
243
+ setSensor(sensor: boolean): void {
244
+ if (sensor != this.m_isSensor) {
245
+ this.m_body.setAwake(true);
246
+ this.m_isSensor = sensor;
247
+ }
248
+ }
249
+
250
+ // /**
251
+ // * Get the contact filtering data.
252
+ // */
253
+ // getFilterData() {
254
+ // return this.m_filter;
255
+ // }
256
+
257
+ /**
258
+ * Get the user data that was assigned in the fixture definition. Use this to
259
+ * store your application specific data.
260
+ */
261
+ getUserData(): unknown {
262
+ return this.m_userData;
263
+ }
264
+
265
+ /**
266
+ * Set the user data. Use this to store your application specific data.
267
+ */
268
+ setUserData(data: unknown): void {
269
+ this.m_userData = data;
270
+ }
271
+
272
+ /**
273
+ * Get the parent body of this fixture. This is null if the fixture is not
274
+ * attached.
275
+ */
276
+ getBody(): Body {
277
+ return this.m_body;
278
+ }
279
+
280
+ /**
281
+ * Get the next fixture in the parent body's fixture list.
282
+ */
283
+ getNext(): Fixture | null {
284
+ return this.m_next;
285
+ }
286
+
287
+ /**
288
+ * Get the density of this fixture.
289
+ */
290
+ getDensity(): number {
291
+ return this.m_density;
292
+ }
293
+
294
+ /**
295
+ * Set the density of this fixture. This will _not_ automatically adjust the
296
+ * mass of the body. You must call Body.resetMassData to update the body's mass.
297
+ */
298
+ setDensity(density: number): void {
299
+ if (_ASSERT) console.assert(Number.isFinite(density) && density >= 0.0);
300
+ this.m_density = density;
301
+ }
302
+
303
+ /**
304
+ * Get the coefficient of friction, usually in the range [0,1].
305
+ */
306
+ getFriction(): number {
307
+ return this.m_friction;
308
+ }
309
+
310
+ /**
311
+ * Set the coefficient of friction. This will not change the friction of
312
+ * existing contacts.
313
+ */
314
+ setFriction(friction: number): void {
315
+ this.m_friction = friction;
316
+ }
317
+
318
+ /**
319
+ * Get the coefficient of restitution.
320
+ */
321
+ getRestitution(): number {
322
+ return this.m_restitution;
323
+ }
324
+
325
+ /**
326
+ * Set the coefficient of restitution. This will not change the restitution of
327
+ * existing contacts.
328
+ */
329
+ setRestitution(restitution: number): void {
330
+ this.m_restitution = restitution;
331
+ }
332
+
333
+ /**
334
+ * Test a point in world coordinates for containment in this fixture.
335
+ */
336
+ testPoint(p: Vec2Value): boolean {
337
+ return this.m_shape.testPoint(this.m_body.getTransform(), p);
338
+ }
339
+
340
+ /**
341
+ * Cast a ray against this shape.
342
+ */
343
+ rayCast(output: RayCastOutput, input: RayCastInput, childIndex: number): boolean {
344
+ return this.m_shape.rayCast(output, input, this.m_body.getTransform(), childIndex);
345
+ }
346
+
347
+ /**
348
+ * Get the mass data for this fixture. The mass data is based on the density and
349
+ * the shape. The rotational inertia is about the shape's origin. This operation
350
+ * may be expensive.
351
+ */
352
+ getMassData(massData: MassData): void {
353
+ this.m_shape.computeMass(massData, this.m_density);
354
+ }
355
+
356
+ /**
357
+ * Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a
358
+ * more accurate AABB, compute it using the shape and the body transform.
359
+ */
360
+ getAABB(childIndex: number): AABB {
361
+ if (_ASSERT) console.assert(0 <= childIndex && childIndex < this.m_proxies.length);
362
+ return this.m_proxies[childIndex].aabb;
363
+ }
364
+
365
+ /**
366
+ * These support body activation/deactivation.
367
+ */
368
+ createProxies(broadPhase: BroadPhase, xf: TransformValue): void {
369
+ if (_ASSERT) console.assert(this.m_proxyCount == 0);
370
+
371
+ // Create proxies in the broad-phase.
372
+ this.m_proxyCount = this.m_shape.getChildCount();
373
+
374
+ for (let i = 0; i < this.m_proxyCount; ++i) {
375
+ const proxy = this.m_proxies[i];
376
+ this.m_shape.computeAABB(proxy.aabb, xf, i);
377
+ proxy.proxyId = broadPhase.createProxy(proxy.aabb, proxy);
378
+ }
379
+ }
380
+
381
+ destroyProxies(broadPhase: BroadPhase): void {
382
+ // Destroy proxies in the broad-phase.
383
+ for (let i = 0; i < this.m_proxyCount; ++i) {
384
+ const proxy = this.m_proxies[i];
385
+ broadPhase.destroyProxy(proxy.proxyId);
386
+ proxy.proxyId = null;
387
+ }
388
+
389
+ this.m_proxyCount = 0;
390
+ }
391
+
392
+ /**
393
+ * Updates this fixture proxy in broad-phase (with combined AABB of current and
394
+ * next transformation).
395
+ */
396
+ synchronize(broadPhase: BroadPhase, xf1: TransformValue, xf2: TransformValue): void {
397
+ for (let i = 0; i < this.m_proxyCount; ++i) {
398
+ const proxy = this.m_proxies[i];
399
+ // Compute an AABB that covers the swept shape (may miss some rotation
400
+ // effect).
401
+ this.m_shape.computeAABB(synchronize_aabb1, xf1, proxy.childIndex);
402
+ this.m_shape.computeAABB(synchronize_aabb2, xf2, proxy.childIndex);
403
+
404
+ proxy.aabb.combine(synchronize_aabb1, synchronize_aabb2);
405
+
406
+ geo.subVec2(displacement, xf2.p, xf1.p);
407
+
408
+ broadPhase.moveProxy(proxy.proxyId, proxy.aabb, displacement);
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Set the contact filtering data. This will not update contacts until the next
414
+ * time step when either parent body is active and awake. This automatically
415
+ * calls refilter.
416
+ */
417
+ setFilterData(filter: { groupIndex: number; categoryBits: number; maskBits: number }): void {
418
+ this.m_filterGroupIndex = filter.groupIndex;
419
+ this.m_filterCategoryBits = filter.categoryBits;
420
+ this.m_filterMaskBits = filter.maskBits;
421
+ this.refilter();
422
+ }
423
+
424
+ getFilterGroupIndex(): number {
425
+ return this.m_filterGroupIndex;
426
+ }
427
+
428
+ setFilterGroupIndex(groupIndex: number): void {
429
+ this.m_filterGroupIndex = groupIndex;
430
+ this.refilter();
431
+ }
432
+
433
+ getFilterCategoryBits(): number {
434
+ return this.m_filterCategoryBits;
435
+ }
436
+
437
+ setFilterCategoryBits(categoryBits: number): void {
438
+ this.m_filterCategoryBits = categoryBits;
439
+ this.refilter();
440
+ }
441
+
442
+ getFilterMaskBits(): number {
443
+ return this.m_filterMaskBits;
444
+ }
445
+
446
+ setFilterMaskBits(maskBits: number): void {
447
+ this.m_filterMaskBits = maskBits;
448
+ this.refilter();
449
+ }
450
+
451
+ /**
452
+ * Call this if you want to establish collision that was previously disabled by
453
+ * ContactFilter.
454
+ */
455
+ refilter(): void {
456
+ if (this.m_body == null) {
457
+ return;
458
+ }
459
+
460
+ // Flag associated contacts for filtering.
461
+ let edge = this.m_body.getContactList();
462
+ while (edge) {
463
+ const contact = edge.contact;
464
+ const fixtureA = contact.getFixtureA();
465
+ const fixtureB = contact.getFixtureB();
466
+ if (fixtureA == this || fixtureB == this) {
467
+ contact.flagForFiltering();
468
+ }
469
+
470
+ edge = edge.next;
471
+ }
472
+
473
+ const world = this.m_body.getWorld();
474
+
475
+ if (world == null) {
476
+ return;
477
+ }
478
+
479
+ // Touch each proxy so that new pairs may be created
480
+ const broadPhase = world.m_broadPhase;
481
+ for (let i = 0; i < this.m_proxyCount; ++i) {
482
+ broadPhase.touchProxy(this.m_proxies[i].proxyId);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Implement this method to provide collision filtering, if you want finer
488
+ * control over contact creation.
489
+ *
490
+ * Return true if contact calculations should be performed between these two
491
+ * fixtures.
492
+ *
493
+ * Warning: for performance reasons this is only called when the AABBs begin to
494
+ * overlap.
495
+ */
496
+ shouldCollide(that: Fixture): boolean {
497
+ if (that.m_filterGroupIndex === this.m_filterGroupIndex && that.m_filterGroupIndex !== 0) {
498
+ return that.m_filterGroupIndex > 0;
499
+ }
500
+
501
+ const collideA = (that.m_filterMaskBits & this.m_filterCategoryBits) !== 0;
502
+ const collideB = (that.m_filterCategoryBits & this.m_filterMaskBits) !== 0;
503
+ const collide = collideA && collideB;
504
+ return collide;
505
+ }
506
+ }