emeraldengine 3.0.0 → 3.1.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.
Files changed (103) hide show
  1. package/README.md +1498 -1659
  2. package/dist/types/index.d.ts +4 -1
  3. package/dist/types/src/Animator.d.ts +1 -1
  4. package/dist/types/src/CollisionLayers.d.ts +2 -2
  5. package/dist/types/src/Color.d.ts +1 -0
  6. package/dist/types/src/Drawable.d.ts +1 -1
  7. package/dist/types/src/EmeraldDB.d.ts +2 -2
  8. package/dist/types/src/InstancedTexture.d.ts +17 -2
  9. package/dist/types/src/Material.d.ts +2 -2
  10. package/dist/types/src/MathUtils.d.ts +2 -1
  11. package/dist/types/src/ParticleEmitter.d.ts +1 -1
  12. package/dist/types/src/Physics.d.ts +148 -18
  13. package/dist/types/src/Scene.d.ts +1 -1
  14. package/dist/types/src/Shaders.d.ts +2 -2
  15. package/dist/types/src/Tilemap.d.ts +1 -1
  16. package/dist/types/src/UI.d.ts +1 -1
  17. package/dist/types/src/components/Behaviour.d.ts +2 -2
  18. package/dist/types/src/components/Collider.d.ts +7 -1
  19. package/dist/types/src/components/GameObject.d.ts +2 -2
  20. package/dist/types/src/components/PolygonCollider.d.ts +33 -0
  21. package/dist/types/src/components/RigidBody.d.ts +281 -8
  22. package/dist/types/src/importers/Aseprite.d.ts +2 -2
  23. package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
  24. package/dist/types/src/importers/TiledMap.d.ts +1 -1
  25. package/dist/types/src/managers/EventManager.d.ts +1 -1
  26. package/dist/types/src/managers/Gamepad.d.ts +102 -0
  27. package/dist/types/src/managers/InputManager.d.ts +93 -2
  28. package/dist/types/src/managers/NetworkManager.d.ts +2 -2
  29. package/dist/types/src/managers/RenderStats.d.ts +1 -1
  30. package/dist/types/src/managers/TextureManager.d.ts +1 -1
  31. package/dist/types/src/physics/AABB.d.ts +92 -0
  32. package/dist/types/src/physics/Body.d.ts +435 -0
  33. package/dist/types/src/physics/BodyType.d.ts +6 -0
  34. package/dist/types/src/physics/BroadPhase.d.ts +210 -0
  35. package/dist/types/src/physics/Collision.d.ts +102 -0
  36. package/dist/types/src/physics/Contact.d.ts +206 -0
  37. package/dist/types/src/physics/ContactSolver.d.ts +108 -0
  38. package/dist/types/src/physics/Distance.d.ts +54 -0
  39. package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
  40. package/dist/types/src/physics/Fixture.d.ts +221 -0
  41. package/dist/types/src/physics/Island.d.ts +52 -0
  42. package/dist/types/src/physics/Joint.d.ts +59 -0
  43. package/dist/types/src/physics/Math2D.d.ts +371 -0
  44. package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
  45. package/dist/types/src/physics/Settings.d.ts +22 -0
  46. package/dist/types/src/physics/Shapes.d.ts +207 -0
  47. package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
  48. package/dist/types/src/physics/World.d.ts +274 -0
  49. package/dist/types/src/physics/index.d.ts +34 -0
  50. package/index.js +6 -0
  51. package/package.json +2 -3
  52. package/src/Animator.js +1 -1
  53. package/src/CollisionLayers.js +3 -3
  54. package/src/Color.js +8 -0
  55. package/src/Drawable.js +1 -1
  56. package/src/Emerald.js +1 -1
  57. package/src/EmeraldDB.js +2 -2
  58. package/src/InstancedTexture.js +57 -9
  59. package/src/Material.js +2 -2
  60. package/src/MathUtils.js +2 -1
  61. package/src/ParticleEmitter.js +1 -1
  62. package/src/Physics.js +270 -60
  63. package/src/Scene.js +1 -1
  64. package/src/Shaders.js +20 -20
  65. package/src/Tilemap.js +1 -1
  66. package/src/UI.js +1 -1
  67. package/src/components/Behaviour.js +2 -2
  68. package/src/components/BoxCollider.js +7 -9
  69. package/src/components/BoxColliderDebug.js +3 -4
  70. package/src/components/CircleCollider.js +7 -9
  71. package/src/components/CircleColliderDebug.js +3 -2
  72. package/src/components/Collider.js +13 -3
  73. package/src/components/GameObject.js +2 -2
  74. package/src/components/PolygonCollider.js +55 -0
  75. package/src/components/RigidBody.js +441 -14
  76. package/src/importers/Aseprite.js +2 -2
  77. package/src/importers/ForgeLevel.js +581 -0
  78. package/src/importers/TiledMap.js +1 -1
  79. package/src/managers/EventManager.js +1 -1
  80. package/src/managers/Gamepad.js +126 -0
  81. package/src/managers/InputManager.js +129 -3
  82. package/src/managers/NetworkManager.js +2 -2
  83. package/src/managers/RenderStats.js +1 -1
  84. package/src/managers/TextureManager.js +1 -1
  85. package/src/physics/AABB.js +207 -0
  86. package/src/physics/Body.js +862 -0
  87. package/src/physics/BodyType.js +16 -0
  88. package/src/physics/BroadPhase.js +641 -0
  89. package/src/physics/Collision.js +534 -0
  90. package/src/physics/Contact.js +500 -0
  91. package/src/physics/ContactSolver.js +526 -0
  92. package/src/physics/Distance.js +403 -0
  93. package/src/physics/DistanceJoint.js +227 -0
  94. package/src/physics/Fixture.js +346 -0
  95. package/src/physics/Island.js +203 -0
  96. package/src/physics/Joint.js +78 -0
  97. package/src/physics/Math2D.js +573 -0
  98. package/src/physics/RevoluteJoint.js +278 -0
  99. package/src/physics/Settings.js +78 -0
  100. package/src/physics/Shapes.js +549 -0
  101. package/src/physics/TimeOfImpact.js +87 -0
  102. package/src/physics/World.js +731 -0
  103. package/src/physics/index.js +79 -0
@@ -0,0 +1,346 @@
1
+ import AABB from "./AABB.js";
2
+ import { Vec2 } from "./Math2D.js";
3
+
4
+ /**
5
+ * @class FixtureProxy
6
+ * @description The link between a fixture and its entry in the broadphase tree.
7
+ * @private
8
+ */
9
+ class FixtureProxy {
10
+ constructor(fixture, childIndex) {
11
+ this.aabb = new AABB();
12
+ this.fixture = fixture;
13
+ this.childIndex = childIndex;
14
+ this.proxyId = -1;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * @class Fixture
20
+ * @description A shape bound to a body, together with the material properties
21
+ * that decide how contacts behave: density (which feeds the body's mass),
22
+ * friction, restitution (bounciness), the sensor flag, and the collision
23
+ * filter. A body can carry any number of fixtures.
24
+ *
25
+ * Fixtures are created through {@link Body#createFixture}, never directly.
26
+ */
27
+ class Fixture {
28
+ constructor(body, shape, def = {}) {
29
+ this.body = body;
30
+ this.shape = shape;
31
+ this.density = def.density ?? 0;
32
+ this.friction = def.friction ?? 0.2;
33
+ this.restitution = def.restitution ?? 0;
34
+ this.sensor = !!def.isSensor;
35
+ this.userData = def.userData ?? null;
36
+ this.filter = {
37
+ categoryBits: def.filterCategoryBits ?? def.categoryBits ?? 0x0001,
38
+ maskBits: def.filterMaskBits ?? def.maskBits ?? 0xffff,
39
+ groupIndex: def.filterGroupIndex ?? def.groupIndex ?? 0,
40
+ };
41
+
42
+ /** @private */
43
+ this.proxies = [new FixtureProxy(this, 0)];
44
+ /** @private */
45
+ this.next = null;
46
+ }
47
+
48
+ /**
49
+ * @method getType
50
+ * @description Returns the underlying shape type ("circle" or "polygon").
51
+ * @returns {string}
52
+ */
53
+ getType() {
54
+ return this.shape.type;
55
+ }
56
+
57
+ /**
58
+ * @method getShape
59
+ * @description Returns the fixture's shape.
60
+ * @returns {Shape}
61
+ */
62
+ getShape() {
63
+ return this.shape;
64
+ }
65
+
66
+ /**
67
+ * @method getBody
68
+ * @description Returns the body this fixture is attached to.
69
+ * @returns {Body}
70
+ */
71
+ getBody() {
72
+ return this.body;
73
+ }
74
+
75
+ /**
76
+ * @method getNext
77
+ * @description Returns the next fixture on the same body, or null.
78
+ * @returns {Fixture|null}
79
+ */
80
+ getNext() {
81
+ return this.next;
82
+ }
83
+
84
+ /**
85
+ * @method setUserData
86
+ * @description Attaches arbitrary data to the fixture.
87
+ * @param {*} data
88
+ */
89
+ setUserData(data) {
90
+ this.userData = data;
91
+ }
92
+
93
+ /**
94
+ * @method getUserData
95
+ * @description Returns the attached data.
96
+ * @returns {*}
97
+ */
98
+ getUserData() {
99
+ return this.userData;
100
+ }
101
+
102
+ /**
103
+ * @method setSensor
104
+ * @description A sensor still reports contacts but never generates a
105
+ * collision response: the classic trigger volume.
106
+ * @param {boolean} value
107
+ */
108
+ setSensor(value) {
109
+ if (value !== this.sensor) {
110
+ this.body.setAwake(true);
111
+ this.sensor = !!value;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * @method isSensor
117
+ * @description Whether this fixture is a sensor.
118
+ * @returns {boolean}
119
+ */
120
+ isSensor() {
121
+ return this.sensor;
122
+ }
123
+
124
+ /**
125
+ * @method setFilterData
126
+ * @description Replaces the collision filter. Two fixtures collide only when
127
+ * each one's category bit appears in the other's mask (or they share a
128
+ * positive group index).
129
+ * @param {Object} filter - `{ categoryBits, maskBits, groupIndex }`
130
+ */
131
+ setFilterData(filter = {}) {
132
+ this.filter = {
133
+ categoryBits: filter.categoryBits ?? this.filter.categoryBits,
134
+ maskBits: filter.maskBits ?? this.filter.maskBits,
135
+ groupIndex: filter.groupIndex ?? this.filter.groupIndex,
136
+ };
137
+ this.refilter();
138
+ }
139
+
140
+ /**
141
+ * @method getFilterData
142
+ * @description Returns the current collision filter.
143
+ * @returns {Object}
144
+ */
145
+ getFilterData() {
146
+ return this.filter;
147
+ }
148
+
149
+ /**
150
+ * @method getFilterCategoryBits
151
+ * @description Returns the category bits.
152
+ * @returns {number}
153
+ */
154
+ getFilterCategoryBits() {
155
+ return this.filter.categoryBits;
156
+ }
157
+
158
+ /**
159
+ * @method getFilterMaskBits
160
+ * @description Returns the mask bits.
161
+ * @returns {number}
162
+ */
163
+ getFilterMaskBits() {
164
+ return this.filter.maskBits;
165
+ }
166
+
167
+ /**
168
+ * @method getFilterGroupIndex
169
+ * @description Returns the group index.
170
+ * @returns {number}
171
+ */
172
+ getFilterGroupIndex() {
173
+ return this.filter.groupIndex;
174
+ }
175
+
176
+ /**
177
+ * @method refilter
178
+ * @description Re-evaluates existing contacts after a filter change, so a
179
+ * fixture that just stopped colliding with a layer separates immediately
180
+ * instead of on its next move.
181
+ */
182
+ refilter() {
183
+ const world = this.body.world;
184
+ if (!world) return;
185
+
186
+ for (const contact of this.body.contacts) {
187
+ if (contact.fixtureA === this || contact.fixtureB === this) {
188
+ contact.flagForFiltering();
189
+ }
190
+ }
191
+
192
+ for (const proxy of this.proxies) {
193
+ if (proxy.proxyId !== -1) world.broadPhase.touchProxy(proxy.proxyId);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * @method setDensity
199
+ * @description Sets the density. Call {@link Body#resetMassData} afterwards
200
+ * for it to take effect on the body's mass.
201
+ * @param {number} density
202
+ */
203
+ setDensity(density) {
204
+ this.density = density;
205
+ }
206
+
207
+ /**
208
+ * @method getDensity
209
+ * @description Returns the density.
210
+ * @returns {number}
211
+ */
212
+ getDensity() {
213
+ return this.density;
214
+ }
215
+
216
+ /**
217
+ * @method setFriction
218
+ * @description Sets the friction coefficient (0 = ice).
219
+ * @param {number} friction
220
+ */
221
+ setFriction(friction) {
222
+ this.friction = friction;
223
+ }
224
+
225
+ /**
226
+ * @method getFriction
227
+ * @description Returns the friction coefficient.
228
+ * @returns {number}
229
+ */
230
+ getFriction() {
231
+ return this.friction;
232
+ }
233
+
234
+ /**
235
+ * @method setRestitution
236
+ * @description Sets the bounciness (0 = no bounce, 1 = perfectly elastic).
237
+ * @param {number} restitution
238
+ */
239
+ setRestitution(restitution) {
240
+ this.restitution = restitution;
241
+ }
242
+
243
+ /**
244
+ * @method getRestitution
245
+ * @description Returns the bounciness.
246
+ * @returns {number}
247
+ */
248
+ getRestitution() {
249
+ return this.restitution;
250
+ }
251
+
252
+ /**
253
+ * @method testPoint
254
+ * @description True when a world-space point is inside this fixture.
255
+ * @param {Object} p - `{ x, y }` in physics units
256
+ * @returns {boolean}
257
+ */
258
+ testPoint(p) {
259
+ return this.shape.testPoint(this.body.xf, p);
260
+ }
261
+
262
+ /**
263
+ * @method rayCast
264
+ * @description Casts a ray against this fixture's shape.
265
+ * @param {Object} output - Written as `{ fraction, normal }` on a hit
266
+ * @param {Object} input - `{ p1, p2, maxFraction }`
267
+ * @returns {boolean}
268
+ */
269
+ rayCast(output, input) {
270
+ return this.shape.rayCast(output, input, this.body.xf);
271
+ }
272
+
273
+ /**
274
+ * @method getMassData
275
+ * @description Computes this fixture's contribution to the body's mass.
276
+ * @param {Object} [massData]
277
+ * @returns {Object} - `{ mass, center, I }`
278
+ */
279
+ getMassData(massData = { mass: 0, center: new Vec2(), I: 0 }) {
280
+ this.shape.computeMass(massData, this.density);
281
+ return massData;
282
+ }
283
+
284
+ /**
285
+ * @method getAABB
286
+ * @description Returns the fixture's current world AABB.
287
+ * @param {number} [childIndex=0]
288
+ * @returns {AABB}
289
+ */
290
+ getAABB(childIndex = 0) {
291
+ return this.proxies[childIndex].aabb;
292
+ }
293
+
294
+ /**
295
+ * @method createProxies
296
+ * @description Registers this fixture with the broadphase.
297
+ * @param {BroadPhase} broadPhase
298
+ * @param {Transform2} xf
299
+ * @private
300
+ */
301
+ createProxies(broadPhase, xf) {
302
+ for (const proxy of this.proxies) {
303
+ this.shape.computeAABB(proxy.aabb, xf);
304
+ proxy.proxyId = broadPhase.createProxy(proxy.aabb, proxy);
305
+ }
306
+ }
307
+
308
+ /**
309
+ * @method destroyProxies
310
+ * @description Removes this fixture from the broadphase.
311
+ * @param {BroadPhase} broadPhase
312
+ * @private
313
+ */
314
+ destroyProxies(broadPhase) {
315
+ for (const proxy of this.proxies) {
316
+ if (proxy.proxyId !== -1) {
317
+ broadPhase.destroyProxy(proxy.proxyId);
318
+ proxy.proxyId = -1;
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * @method synchronize
325
+ * @description Re-fits the broadphase proxies after the body moved. The AABB
326
+ * spans both the old and the new transform so a fast body's proxy still
327
+ * covers the ground it swept over.
328
+ * @param {BroadPhase} broadPhase
329
+ * @param {Transform2} xf1
330
+ * @param {Transform2} xf2
331
+ * @private
332
+ */
333
+ synchronize(broadPhase, xf1, xf2) {
334
+ for (const proxy of this.proxies) {
335
+ const aabb1 = new AABB();
336
+ const aabb2 = new AABB();
337
+ this.shape.computeAABB(aabb1, xf1);
338
+ this.shape.computeAABB(aabb2, xf2);
339
+ proxy.aabb.combine(aabb1, aabb2);
340
+ const displacement = new Vec2(xf2.p.x - xf1.p.x, xf2.p.y - xf1.p.y);
341
+ broadPhase.moveProxy(proxy.proxyId, proxy.aabb, displacement);
342
+ }
343
+ }
344
+ }
345
+
346
+ export { Fixture, FixtureProxy };
@@ -0,0 +1,203 @@
1
+ import { Vec2 } from "./Math2D.js";
2
+ import Settings from "./Settings.js";
3
+ import ContactSolver from "./ContactSolver.js";
4
+ import { BodyType } from "./BodyType.js";
5
+
6
+ /**
7
+ * @class Island
8
+ * @description A connected group of bodies, everything reachable through
9
+ * touching contacts, solved together. Islands are what make sleeping work:
10
+ * a pile of crates only goes to sleep once *every* body in it has settled, so
11
+ * one crate still rolling keeps the whole pile simulated.
12
+ */
13
+ class Island {
14
+ constructor() {
15
+ this.bodies = [];
16
+ this.contacts = [];
17
+ this.joints = [];
18
+ /** @private */
19
+ this.positions = [];
20
+ /** @private */
21
+ this.velocities = [];
22
+ }
23
+
24
+ /**
25
+ * @method clear
26
+ * @description Empties the island for reuse on the next seed body.
27
+ */
28
+ clear() {
29
+ this.bodies.length = 0;
30
+ this.contacts.length = 0;
31
+ this.joints.length = 0;
32
+ }
33
+
34
+ /**
35
+ * @method addBody
36
+ * @description Adds a body and records its index for the solver.
37
+ * @param {Body} body
38
+ */
39
+ addBody(body) {
40
+ body.islandIndex = this.bodies.length;
41
+ this.bodies.push(body);
42
+ }
43
+
44
+ /**
45
+ * @method addContact
46
+ * @description Adds a touching contact to be solved with this island.
47
+ * @param {Contact} contact
48
+ */
49
+ addContact(contact) {
50
+ this.contacts.push(contact);
51
+ }
52
+
53
+ /**
54
+ * @method addJoint
55
+ * @description Adds a joint to be solved with this island.
56
+ * @param {Joint} joint
57
+ */
58
+ addJoint(joint) {
59
+ this.joints.push(joint);
60
+ }
61
+
62
+ /**
63
+ * @method solve
64
+ * @description Advances the island by one step: integrate velocities, solve
65
+ * contacts, integrate positions, fix leftover overlap, then decide whether
66
+ * the island can go to sleep.
67
+ * @param {Object} step - `{ dt, velocityIterations, positionIterations,
68
+ * warmStarting, velocityThreshold }`
69
+ * @param {Vec2} gravity - World gravity in physics units
70
+ * @param {boolean} allowSleep - Whether sleeping is enabled world-wide
71
+ */
72
+ solve(step, gravity, allowSleep) {
73
+ const h = step.dt;
74
+
75
+ this.positions.length = 0;
76
+ this.velocities.length = 0;
77
+
78
+ for (const body of this.bodies) {
79
+ const c = body.sweep.c.clone();
80
+ const a = body.sweep.a;
81
+ const v = body.linearVelocity.clone();
82
+ let w = body.angularVelocity;
83
+
84
+ body.sweep.c0.copy(body.sweep.c);
85
+ body.sweep.a0 = body.sweep.a;
86
+
87
+ if (body.type === BodyType.DYNAMIC) {
88
+ v.x +=
89
+ h * (body.gravityScale * gravity.x + body.invMass * body.force.x);
90
+ v.y +=
91
+ h * (body.gravityScale * gravity.y + body.invMass * body.force.y);
92
+ w += h * body.invI * body.torque;
93
+
94
+ const linearScale = 1 / (1 + h * body.linearDamping);
95
+ v.x *= linearScale;
96
+ v.y *= linearScale;
97
+ w *= 1 / (1 + h * body.angularDamping);
98
+ }
99
+
100
+ this.positions.push({ c, a });
101
+ this.velocities.push({ v, w });
102
+ }
103
+
104
+ const solver = new ContactSolver({
105
+ contacts: this.contacts,
106
+ positions: this.positions,
107
+ velocities: this.velocities,
108
+ dt: h,
109
+ velocityThreshold: step.velocityThreshold,
110
+ });
111
+
112
+ for (const joint of this.joints) {
113
+ joint.initVelocityConstraints(step, this.positions, this.velocities);
114
+ }
115
+
116
+ solver.initializeVelocityConstraints();
117
+ if (step.warmStarting) solver.warmStart();
118
+
119
+ for (let i = 0; i < step.velocityIterations; i++) {
120
+ for (const joint of this.joints) {
121
+ joint.solveVelocityConstraints(step, this.velocities);
122
+ }
123
+ solver.solveVelocityConstraints();
124
+ }
125
+ solver.storeImpulses();
126
+
127
+ for (let i = 0; i < this.bodies.length; i++) {
128
+ const pos = this.positions[i];
129
+ const vel = this.velocities[i];
130
+
131
+ let translationX = h * vel.v.x;
132
+ let translationY = h * vel.v.y;
133
+ const translationSq =
134
+ translationX * translationX + translationY * translationY;
135
+ if (translationSq > Settings.maxTranslation * Settings.maxTranslation) {
136
+ const ratio = Settings.maxTranslation / Math.sqrt(translationSq);
137
+ vel.v.x *= ratio;
138
+ vel.v.y *= ratio;
139
+ }
140
+
141
+ const rotation = h * vel.w;
142
+ if (rotation * rotation > Settings.maxRotation * Settings.maxRotation) {
143
+ vel.w *= Settings.maxRotation / Math.abs(rotation);
144
+ }
145
+
146
+ pos.c.x += h * vel.v.x;
147
+ pos.c.y += h * vel.v.y;
148
+ pos.a += h * vel.w;
149
+ }
150
+
151
+ let positionSolved = false;
152
+ for (let i = 0; i < step.positionIterations; i++) {
153
+ let jointsOkay = true;
154
+ for (const joint of this.joints) {
155
+ jointsOkay =
156
+ joint.solvePositionConstraints(this.positions) && jointsOkay;
157
+ }
158
+ const contactsOkay = solver.solvePositionConstraints();
159
+ if (jointsOkay && contactsOkay) {
160
+ positionSolved = true;
161
+ break;
162
+ }
163
+ }
164
+
165
+ for (let i = 0; i < this.bodies.length; i++) {
166
+ const body = this.bodies[i];
167
+ body.sweep.c.copy(this.positions[i].c);
168
+ body.sweep.a = this.positions[i].a;
169
+ body.linearVelocity.copy(this.velocities[i].v);
170
+ body.angularVelocity = this.velocities[i].w;
171
+ body.synchronizeTransform();
172
+ }
173
+
174
+ if (!allowSleep) return;
175
+
176
+ let minSleepTime = Number.MAX_VALUE;
177
+ const linTolSqr =
178
+ Settings.linearSleepTolerance * Settings.linearSleepTolerance;
179
+ const angTolSqr =
180
+ Settings.angularSleepTolerance * Settings.angularSleepTolerance;
181
+
182
+ for (const body of this.bodies) {
183
+ if (body.type === BodyType.STATIC) continue;
184
+ if (
185
+ !body.allowSleep ||
186
+ body.angularVelocity * body.angularVelocity > angTolSqr ||
187
+ Vec2.dot(body.linearVelocity, body.linearVelocity) > linTolSqr
188
+ ) {
189
+ body.sleepTime = 0;
190
+ minSleepTime = 0;
191
+ } else {
192
+ body.sleepTime += h;
193
+ minSleepTime = Math.min(minSleepTime, body.sleepTime);
194
+ }
195
+ }
196
+
197
+ if (minSleepTime >= Settings.timeToSleep && positionSolved) {
198
+ for (const body of this.bodies) body.setAwake(false);
199
+ }
200
+ }
201
+ }
202
+
203
+ export default Island;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @description Identifies a concrete {@link Joint} subclass.
3
+ */
4
+ const JointType = Object.freeze({
5
+ DISTANCE: "distance",
6
+ REVOLUTE: "revolute",
7
+ });
8
+
9
+ /**
10
+ * @class Joint
11
+ * @description Base class for a constraint between two bodies. A joint is
12
+ * solved by the same island that solves contacts (see {@link Island}), right
13
+ * alongside them, so a body linked only by a joint (no touching fixtures)
14
+ * still wakes, sleeps and moves together with whatever it is jointed to.
15
+ *
16
+ * Concrete joints ({@link DistanceJoint}, {@link RevoluteJoint}) implement
17
+ * `initVelocityConstraints`, `solveVelocityConstraints` and
18
+ * `solvePositionConstraints`, matching {@link ContactSolver}'s per-step
19
+ * lifecycle.
20
+ * @param {Object} def - `{ type, bodyA, bodyB, collideConnected, userData }`
21
+ */
22
+ class Joint {
23
+ constructor(def) {
24
+ this.type = def.type;
25
+ this.bodyA = def.bodyA;
26
+ this.bodyB = def.bodyB;
27
+ this.collideConnected = def.collideConnected ?? false;
28
+ this.userData = def.userData ?? null;
29
+ /** @private */
30
+ this.islandFlag = false;
31
+ /** @private */
32
+ this.prev = null;
33
+ /** @private */
34
+ this.next = null;
35
+ }
36
+
37
+ /**
38
+ * @method getType
39
+ * @returns {string}
40
+ */
41
+ getType() {
42
+ return this.type;
43
+ }
44
+
45
+ /**
46
+ * @method getBodyA
47
+ * @returns {Body}
48
+ */
49
+ getBodyA() {
50
+ return this.bodyA;
51
+ }
52
+
53
+ /**
54
+ * @method getBodyB
55
+ * @returns {Body}
56
+ */
57
+ getBodyB() {
58
+ return this.bodyB;
59
+ }
60
+
61
+ /**
62
+ * @method getUserData
63
+ * @returns {*}
64
+ */
65
+ getUserData() {
66
+ return this.userData;
67
+ }
68
+
69
+ /**
70
+ * @method setUserData
71
+ * @param {*} data
72
+ */
73
+ setUserData(data) {
74
+ this.userData = data;
75
+ }
76
+ }
77
+
78
+ export { Joint, JointType };