emeraldengine 2.2.1 → 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 (208) hide show
  1. package/README.md +2198 -968
  2. package/dist/types/index.d.ts +75 -32
  3. package/dist/types/src/Animator.d.ts +50 -0
  4. package/dist/types/{BitmapText.d.ts → src/BitmapText.d.ts} +19 -21
  5. package/dist/types/src/Camera.d.ts +122 -0
  6. package/dist/types/src/CameraController.d.ts +107 -0
  7. package/dist/types/src/CanvasText.d.ts +91 -0
  8. package/dist/types/src/CollisionLayers.d.ts +58 -0
  9. package/dist/types/{Color.d.ts → src/Color.d.ts} +6 -6
  10. package/dist/types/src/Coroutine.d.ts +111 -0
  11. package/dist/types/src/DebugOverlay.d.ts +86 -0
  12. package/dist/types/src/Drawable.d.ts +271 -0
  13. package/dist/types/src/Easing.d.ts +22 -0
  14. package/dist/types/src/Emerald.d.ts +420 -0
  15. package/dist/types/src/EmeraldDB.d.ts +159 -0
  16. package/dist/types/{FPSCounter.d.ts → src/FPSCounter.d.ts} +1 -3
  17. package/dist/types/src/GLUtils.d.ts +4 -0
  18. package/dist/types/{Instance.d.ts → src/Instance.d.ts} +37 -15
  19. package/dist/types/{InstancedTexture.d.ts → src/InstancedTexture.d.ts} +75 -23
  20. package/dist/types/src/Interpolator.d.ts +66 -0
  21. package/dist/types/src/Material.d.ts +87 -0
  22. package/dist/types/src/MathUtils.d.ts +81 -0
  23. package/dist/types/src/ParticleEmitter.d.ts +131 -0
  24. package/dist/types/src/Physics.d.ts +337 -0
  25. package/dist/types/src/Pool.d.ts +53 -0
  26. package/dist/types/src/PostEffects.d.ts +68 -0
  27. package/dist/types/src/PostProcessor.d.ts +124 -0
  28. package/dist/types/src/RenderTarget.d.ts +56 -0
  29. package/dist/types/src/Scene.d.ts +62 -0
  30. package/dist/types/src/ScreenEffects.d.ts +111 -0
  31. package/dist/types/src/Serializer.d.ts +86 -0
  32. package/dist/types/src/Shaders.d.ts +2 -0
  33. package/dist/types/{Shapes.d.ts → src/Shapes.d.ts} +4 -6
  34. package/dist/types/src/SpatialGrid.d.ts +50 -0
  35. package/dist/types/src/SpriteBatch.d.ts +89 -0
  36. package/dist/types/src/StateMachine.d.ts +59 -0
  37. package/dist/types/src/Storage.d.ts +89 -0
  38. package/dist/types/{Texture.d.ts → src/Texture.d.ts} +3 -4
  39. package/dist/types/src/TextureAtlas.d.ts +55 -0
  40. package/dist/types/src/Tilemap.d.ts +91 -0
  41. package/dist/types/src/Time.d.ts +53 -0
  42. package/dist/types/src/Timer.d.ts +54 -0
  43. package/dist/types/src/Transform.d.ts +94 -0
  44. package/dist/types/src/Tween.d.ts +81 -0
  45. package/dist/types/src/UI.d.ts +121 -0
  46. package/dist/types/src/components/Behaviour.d.ts +71 -0
  47. package/dist/types/{components → src/components}/BoxCollider.d.ts +14 -14
  48. package/dist/types/src/components/BoxColliderDebug.d.ts +15 -0
  49. package/dist/types/{components → src/components}/CircleCollider.d.ts +14 -12
  50. package/dist/types/src/components/CircleColliderDebug.d.ts +15 -0
  51. package/dist/types/src/components/Collider.d.ts +102 -0
  52. package/dist/types/src/components/GameObject.d.ts +135 -0
  53. package/dist/types/src/components/PolygonCollider.d.ts +33 -0
  54. package/dist/types/src/components/RigidBody.d.ts +456 -0
  55. package/dist/types/src/importers/Aseprite.d.ts +79 -0
  56. package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
  57. package/dist/types/src/importers/TiledMap.d.ts +62 -0
  58. package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
  59. package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
  60. package/dist/types/src/managers/AssetManager.d.ts +116 -0
  61. package/dist/types/src/managers/AudioManager.d.ts +259 -0
  62. package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
  63. package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
  64. package/dist/types/src/managers/GLManager.d.ts +84 -0
  65. package/dist/types/src/managers/GLState.d.ts +37 -0
  66. package/dist/types/src/managers/Gamepad.d.ts +102 -0
  67. package/dist/types/src/managers/IDManager.d.ts +31 -0
  68. package/dist/types/src/managers/InputManager.d.ts +381 -0
  69. package/dist/types/src/managers/NetworkManager.d.ts +93 -0
  70. package/dist/types/src/managers/RenderStats.d.ts +34 -0
  71. package/dist/types/src/managers/SceneManager.d.ts +44 -0
  72. package/dist/types/src/managers/ShaderManager.d.ts +55 -0
  73. package/dist/types/src/managers/TextureManager.d.ts +102 -0
  74. package/dist/types/src/particlesystem/Particle.d.ts +64 -0
  75. package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
  76. package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
  77. package/dist/types/src/physics/AABB.d.ts +92 -0
  78. package/dist/types/src/physics/Body.d.ts +435 -0
  79. package/dist/types/src/physics/BodyType.d.ts +6 -0
  80. package/dist/types/src/physics/BroadPhase.d.ts +210 -0
  81. package/dist/types/src/physics/Collision.d.ts +102 -0
  82. package/dist/types/src/physics/Contact.d.ts +206 -0
  83. package/dist/types/src/physics/ContactSolver.d.ts +108 -0
  84. package/dist/types/src/physics/Distance.d.ts +54 -0
  85. package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
  86. package/dist/types/src/physics/Fixture.d.ts +221 -0
  87. package/dist/types/src/physics/Island.d.ts +52 -0
  88. package/dist/types/src/physics/Joint.d.ts +59 -0
  89. package/dist/types/src/physics/Math2D.d.ts +371 -0
  90. package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
  91. package/dist/types/src/physics/Settings.d.ts +22 -0
  92. package/dist/types/src/physics/Shapes.d.ts +207 -0
  93. package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
  94. package/dist/types/src/physics/World.d.ts +274 -0
  95. package/dist/types/src/physics/index.d.ts +34 -0
  96. package/index.js +78 -0
  97. package/package.json +73 -60
  98. package/src/Animator.js +95 -0
  99. package/src/BitmapText.js +6 -5
  100. package/src/Camera.js +183 -0
  101. package/src/CameraController.js +192 -0
  102. package/src/CanvasText.js +281 -0
  103. package/src/CollisionLayers.js +86 -0
  104. package/src/Color.js +26 -18
  105. package/src/Coroutine.js +259 -0
  106. package/src/DebugOverlay.js +246 -0
  107. package/src/Drawable.js +842 -582
  108. package/src/Easing.js +57 -0
  109. package/src/Emerald.js +1150 -459
  110. package/src/EmeraldDB.js +328 -0
  111. package/src/FPSCounter.js +43 -43
  112. package/src/GLUtils.js +60 -67
  113. package/src/Instance.js +41 -5
  114. package/src/InstancedTexture.js +308 -127
  115. package/src/Interpolator.js +124 -0
  116. package/src/Material.js +202 -0
  117. package/src/MathUtils.js +134 -0
  118. package/src/ParticleEmitter.js +284 -0
  119. package/src/Physics.js +431 -40
  120. package/src/Pool.js +85 -0
  121. package/src/PostEffects.js +296 -0
  122. package/src/PostProcessor.js +304 -0
  123. package/src/RenderTarget.js +134 -0
  124. package/src/Scene.js +115 -83
  125. package/src/ScreenEffects.js +266 -0
  126. package/src/Serializer.js +131 -0
  127. package/src/Shaders.js +150 -165
  128. package/src/Shapes.js +118 -129
  129. package/src/SpatialGrid.js +111 -0
  130. package/src/SpriteBatch.js +299 -0
  131. package/src/StateMachine.js +82 -0
  132. package/src/Storage.js +175 -47
  133. package/src/Texture.js +58 -67
  134. package/src/TextureAtlas.js +96 -0
  135. package/src/Tilemap.js +274 -0
  136. package/src/Time.js +51 -6
  137. package/src/Timer.js +99 -0
  138. package/src/Transform.js +100 -7
  139. package/src/Tween.js +160 -0
  140. package/src/UI.js +394 -0
  141. package/src/components/Behaviour.js +90 -0
  142. package/src/components/BoxCollider.js +29 -12
  143. package/src/components/BoxColliderDebug.js +3 -4
  144. package/src/components/CircleCollider.js +26 -12
  145. package/src/components/CircleColliderDebug.js +25 -24
  146. package/src/components/Collider.js +150 -34
  147. package/src/components/GameObject.js +130 -21
  148. package/src/components/PolygonCollider.js +55 -0
  149. package/src/components/RigidBody.js +556 -8
  150. package/src/importers/Aseprite.js +142 -0
  151. package/src/importers/ForgeLevel.js +581 -0
  152. package/src/importers/TiledMap.js +158 -0
  153. package/src/lights/DirectionalLight.js +6 -15
  154. package/src/lights/PointLight.js +4 -4
  155. package/src/managers/AssetManager.js +239 -0
  156. package/src/managers/AudioManager.js +565 -146
  157. package/src/managers/EventManager.js +488 -477
  158. package/src/managers/GLManager.js +57 -0
  159. package/src/managers/GLState.js +70 -0
  160. package/src/managers/Gamepad.js +126 -0
  161. package/src/managers/IDManager.js +24 -2
  162. package/src/managers/InputManager.js +905 -0
  163. package/src/managers/NetworkManager.js +178 -0
  164. package/src/managers/RenderStats.js +34 -0
  165. package/src/managers/SceneManager.js +30 -0
  166. package/src/managers/ShaderManager.js +0 -2
  167. package/src/managers/TextureManager.js +218 -0
  168. package/src/particlesystem/Particle.js +82 -7
  169. package/src/particlesystem/ParticleSettings.js +21 -3
  170. package/src/particlesystem/Particles.js +80 -31
  171. package/src/physics/AABB.js +207 -0
  172. package/src/physics/Body.js +862 -0
  173. package/src/physics/BodyType.js +16 -0
  174. package/src/physics/BroadPhase.js +641 -0
  175. package/src/physics/Collision.js +534 -0
  176. package/src/physics/Contact.js +500 -0
  177. package/src/physics/ContactSolver.js +526 -0
  178. package/src/physics/Distance.js +403 -0
  179. package/src/physics/DistanceJoint.js +227 -0
  180. package/src/physics/Fixture.js +346 -0
  181. package/src/physics/Island.js +203 -0
  182. package/src/physics/Joint.js +78 -0
  183. package/src/physics/Math2D.js +573 -0
  184. package/src/physics/RevoluteJoint.js +278 -0
  185. package/src/physics/Settings.js +78 -0
  186. package/src/physics/Shapes.js +549 -0
  187. package/src/physics/TimeOfImpact.js +87 -0
  188. package/src/physics/World.js +731 -0
  189. package/src/physics/index.js +79 -0
  190. package/dist/types/Drawable.d.ts +0 -157
  191. package/dist/types/Emerald.d.ts +0 -73
  192. package/dist/types/GLUtils.d.ts +0 -6
  193. package/dist/types/Physics.d.ts +0 -139
  194. package/dist/types/Scene.d.ts +0 -39
  195. package/dist/types/Shaders.d.ts +0 -4
  196. package/dist/types/Storage.d.ts +0 -46
  197. package/dist/types/Time.d.ts +0 -22
  198. package/dist/types/Transform.d.ts +0 -41
  199. package/dist/types/components/BoxColliderDebug.d.ts +0 -19
  200. package/dist/types/components/CircleColliderDebug.d.ts +0 -19
  201. package/dist/types/components/Collider.d.ts +0 -53
  202. package/dist/types/components/GameObject.d.ts +0 -72
  203. package/dist/types/components/RigidBody.d.ts +0 -104
  204. package/dist/types/managers/AudioManager.d.ts +0 -60
  205. package/dist/types/managers/GLManager.d.ts +0 -47
  206. package/dist/types/managers/IDManager.d.ts +0 -21
  207. package/dist/types/managers/SceneManager.d.ts +0 -22
  208. package/dist/types/particlesystem/Particle.d.ts +0 -42
@@ -0,0 +1,500 @@
1
+ import {
2
+ Manifold,
3
+ WorldManifold,
4
+ collideCircles,
5
+ collidePolygonAndCircle,
6
+ collidePolygons,
7
+ } from "./Collision.js";
8
+ import { ShapeType } from "./Shapes.js";
9
+ import { testOverlap } from "./Distance.js";
10
+ import { BodyType } from "./BodyType.js";
11
+
12
+ /**
13
+ * @function mixFriction
14
+ * @description Combines two friction coefficients (geometric mean), so a slick
15
+ * body sliding on a rough one lands somewhere in between.
16
+ * @private
17
+ */
18
+ function mixFriction(a, b) {
19
+ return Math.sqrt(a * b);
20
+ }
21
+
22
+ /**
23
+ * @function mixRestitution
24
+ * @description Combines two restitutions: the bouncier surface wins, which is
25
+ * what players expect from a trampoline on concrete.
26
+ * @private
27
+ */
28
+ function mixRestitution(a, b) {
29
+ return a > b ? a : b;
30
+ }
31
+
32
+ /**
33
+ * @function shouldCollide
34
+ * @description Applies the collision filter to a fixture pair. A positive
35
+ * shared group index always collides, a negative one never does; otherwise each
36
+ * fixture's category must appear in the other's mask.
37
+ * @param {Fixture} fixtureA
38
+ * @param {Fixture} fixtureB
39
+ * @returns {boolean}
40
+ */
41
+ function shouldCollide(fixtureA, fixtureB) {
42
+ const filterA = fixtureA.filter;
43
+ const filterB = fixtureB.filter;
44
+
45
+ if (filterA.groupIndex === filterB.groupIndex && filterA.groupIndex !== 0) {
46
+ return filterA.groupIndex > 0;
47
+ }
48
+
49
+ return (
50
+ (filterA.maskBits & filterB.categoryBits) !== 0 &&
51
+ (filterB.maskBits & filterA.categoryBits) !== 0
52
+ );
53
+ }
54
+
55
+ /**
56
+ * @class Contact
57
+ * @description A potential or actual touch between two fixtures. The broadphase
58
+ * creates one as soon as two AABBs overlap; `touching` only becomes true once
59
+ * the narrowphase finds real contact points. Contacts persist across steps,
60
+ * which is what lets the solver warm-start from last frame's impulses.
61
+ */
62
+ class Contact {
63
+ constructor(fixtureA, fixtureB) {
64
+ this.fixtureA = fixtureA;
65
+ this.fixtureB = fixtureB;
66
+ this.manifold = new Manifold();
67
+ this.friction = mixFriction(fixtureA.friction, fixtureB.friction);
68
+ this.restitution = mixRestitution(
69
+ fixtureA.restitution,
70
+ fixtureB.restitution
71
+ );
72
+ this.tangentSpeed = 0;
73
+
74
+ /** @private */
75
+ this.touching = false;
76
+ /** @private */
77
+ this.enabled = true;
78
+ /** @private */
79
+ this.filterFlag = false;
80
+ /** @private */
81
+ this.islandFlag = false;
82
+ /** @private */
83
+ this.toiFlag = false;
84
+ /** @private */
85
+ this.toi = 1;
86
+ /** @private */
87
+ this._index = -1;
88
+ }
89
+
90
+ /**
91
+ * @method create
92
+ * @description Builds a contact for a fixture pair, normalizing the order so
93
+ * mixed polygon/circle pairs always arrive as (polygon, circle): the one
94
+ * ordering the narrowphase implements.
95
+ * @param {Fixture} fixtureA
96
+ * @param {Fixture} fixtureB
97
+ * @returns {Contact}
98
+ */
99
+ static create(fixtureA, fixtureB) {
100
+ if (
101
+ fixtureA.shape.type === ShapeType.CIRCLE &&
102
+ fixtureB.shape.type === ShapeType.POLYGON
103
+ ) {
104
+ return new Contact(fixtureB, fixtureA);
105
+ }
106
+ return new Contact(fixtureA, fixtureB);
107
+ }
108
+
109
+ /**
110
+ * @method getManifold
111
+ * @description Returns the local-space manifold.
112
+ * @returns {Manifold}
113
+ */
114
+ getManifold() {
115
+ return this.manifold;
116
+ }
117
+
118
+ /**
119
+ * @method getWorldManifold
120
+ * @description Returns the contact in world space: the normal (pointing from
121
+ * fixture A's body towards fixture B's), the contact points, and the
122
+ * separation at each point.
123
+ * @param {WorldManifold} [worldManifold] - Optional object to fill
124
+ * @returns {WorldManifold}
125
+ */
126
+ getWorldManifold(worldManifold = new WorldManifold()) {
127
+ return worldManifold.initialize(
128
+ this.manifold,
129
+ this.fixtureA.body.xf,
130
+ this.fixtureA.shape.radius,
131
+ this.fixtureB.body.xf,
132
+ this.fixtureB.shape.radius
133
+ );
134
+ }
135
+
136
+ /**
137
+ * @method isTouching
138
+ * @description Whether the fixtures are actually in contact this step.
139
+ * @returns {boolean}
140
+ */
141
+ isTouching() {
142
+ return this.touching;
143
+ }
144
+
145
+ /**
146
+ * @method setEnabled
147
+ * @description Enables or disables the collision response for this contact.
148
+ * Disabling only lasts for the current step (useful from a pre-solve
149
+ * callback to build one-way platforms).
150
+ * @param {boolean} value
151
+ */
152
+ setEnabled(value) {
153
+ this.enabled = !!value;
154
+ }
155
+
156
+ /**
157
+ * @method isEnabled
158
+ * @description Whether the collision response is enabled.
159
+ * @returns {boolean}
160
+ */
161
+ isEnabled() {
162
+ return this.enabled;
163
+ }
164
+
165
+ /**
166
+ * @method getFixtureA
167
+ * @description Returns the first fixture.
168
+ * @returns {Fixture}
169
+ */
170
+ getFixtureA() {
171
+ return this.fixtureA;
172
+ }
173
+
174
+ /**
175
+ * @method getFixtureB
176
+ * @description Returns the second fixture.
177
+ * @returns {Fixture}
178
+ */
179
+ getFixtureB() {
180
+ return this.fixtureB;
181
+ }
182
+
183
+ /**
184
+ * @method getFriction
185
+ * @description Returns the mixed friction used by the solver.
186
+ * @returns {number}
187
+ */
188
+ getFriction() {
189
+ return this.friction;
190
+ }
191
+
192
+ /**
193
+ * @method setFriction
194
+ * @description Overrides the mixed friction for this contact.
195
+ * @param {number} friction
196
+ */
197
+ setFriction(friction) {
198
+ this.friction = friction;
199
+ }
200
+
201
+ /**
202
+ * @method resetFriction
203
+ * @description Restores the friction mixed from the two fixtures.
204
+ */
205
+ resetFriction() {
206
+ this.friction = mixFriction(this.fixtureA.friction, this.fixtureB.friction);
207
+ }
208
+
209
+ /**
210
+ * @method getRestitution
211
+ * @description Returns the mixed restitution used by the solver.
212
+ * @returns {number}
213
+ */
214
+ getRestitution() {
215
+ return this.restitution;
216
+ }
217
+
218
+ /**
219
+ * @method setRestitution
220
+ * @description Overrides the mixed restitution for this contact.
221
+ * @param {number} restitution
222
+ */
223
+ setRestitution(restitution) {
224
+ this.restitution = restitution;
225
+ }
226
+
227
+ /**
228
+ * @method resetRestitution
229
+ * @description Restores the restitution mixed from the two fixtures.
230
+ */
231
+ resetRestitution() {
232
+ this.restitution = mixRestitution(
233
+ this.fixtureA.restitution,
234
+ this.fixtureB.restitution
235
+ );
236
+ }
237
+
238
+ /**
239
+ * @method flagForFiltering
240
+ * @description Marks the contact so the next step re-checks whether these two
241
+ * fixtures are still allowed to collide.
242
+ */
243
+ flagForFiltering() {
244
+ this.filterFlag = true;
245
+ }
246
+
247
+ /**
248
+ * @method evaluate
249
+ * @description Runs the narrowphase for this fixture pair into `manifold`.
250
+ * @param {Manifold} manifold
251
+ * @param {Transform2} xfA
252
+ * @param {Transform2} xfB
253
+ * @private
254
+ */
255
+ evaluate(manifold, xfA, xfB) {
256
+ const shapeA = this.fixtureA.shape;
257
+ const shapeB = this.fixtureB.shape;
258
+
259
+ if (shapeA.type === ShapeType.CIRCLE) {
260
+ collideCircles(manifold, shapeA, xfA, shapeB, xfB);
261
+ } else if (shapeB.type === ShapeType.CIRCLE) {
262
+ collidePolygonAndCircle(manifold, shapeA, xfA, shapeB, xfB);
263
+ } else {
264
+ collidePolygons(manifold, shapeA, xfA, shapeB, xfB);
265
+ }
266
+ }
267
+
268
+ /**
269
+ * @method update
270
+ * @description Re-runs the narrowphase, carries last step's impulses over to
271
+ * matching contact points (warm starting), and fires begin/end contact
272
+ * events on the world when the touching state flips.
273
+ * @param {World} world - The owning world, used to dispatch events
274
+ */
275
+ update(world) {
276
+ const oldPoints = [];
277
+ for (let i = 0; i < this.manifold.pointCount; i++) {
278
+ oldPoints.push({
279
+ id: this.manifold.points[i].id,
280
+ normalImpulse: this.manifold.points[i].normalImpulse,
281
+ tangentImpulse: this.manifold.points[i].tangentImpulse,
282
+ });
283
+ }
284
+
285
+ const wasTouching = this.touching;
286
+ let touching = false;
287
+ this.enabled = true;
288
+
289
+ const bodyA = this.fixtureA.body;
290
+ const bodyB = this.fixtureB.body;
291
+ const sensor = this.fixtureA.sensor || this.fixtureB.sensor;
292
+
293
+ if (sensor) {
294
+ touching = testOverlap(
295
+ this.fixtureA.shape,
296
+ bodyA.xf,
297
+ this.fixtureB.shape,
298
+ bodyB.xf
299
+ );
300
+ this.manifold.pointCount = 0;
301
+ } else {
302
+ this.evaluate(this.manifold, bodyA.xf, bodyB.xf);
303
+ touching = this.manifold.pointCount > 0;
304
+
305
+ for (let i = 0; i < this.manifold.pointCount; i++) {
306
+ const point = this.manifold.points[i];
307
+ point.normalImpulse = 0;
308
+ point.tangentImpulse = 0;
309
+ for (const old of oldPoints) {
310
+ if (old.id === point.id) {
311
+ point.normalImpulse = old.normalImpulse;
312
+ point.tangentImpulse = old.tangentImpulse;
313
+ break;
314
+ }
315
+ }
316
+ }
317
+
318
+ if (touching !== wasTouching) {
319
+ bodyA.setAwake(true);
320
+ bodyB.setAwake(true);
321
+ }
322
+ }
323
+
324
+ this.touching = touching;
325
+
326
+ if (!wasTouching && touching) world.dispatch("begin-contact", this);
327
+ if (wasTouching && !touching) world.dispatch("end-contact", this);
328
+ if (!sensor && touching) world.dispatch("pre-solve", this, this.manifold);
329
+ }
330
+ }
331
+
332
+ /**
333
+ * @class ContactManager
334
+ * @description Owns the world's contact list: creates contacts from broadphase
335
+ * pairs, drops them once the AABBs stop overlapping, and refreshes the ones
336
+ * that remain each step.
337
+ */
338
+ class ContactManager {
339
+ constructor(world) {
340
+ this.world = world;
341
+ this.contacts = [];
342
+ }
343
+
344
+ /**
345
+ * @method addPair
346
+ * @description Creates a contact for a new broadphase pair, unless the two
347
+ * fixtures share a body, already have a contact, or the filter rejects them.
348
+ * @param {FixtureProxy} proxyA
349
+ * @param {FixtureProxy} proxyB
350
+ */
351
+ addPair(proxyA, proxyB) {
352
+ const fixtureA = proxyA.fixture;
353
+ const fixtureB = proxyB.fixture;
354
+ const bodyA = fixtureA.body;
355
+ const bodyB = fixtureB.body;
356
+
357
+ if (bodyA === bodyB) return;
358
+
359
+ if (bodyA.type !== BodyType.DYNAMIC && bodyB.type !== BodyType.DYNAMIC) {
360
+ return;
361
+ }
362
+
363
+ for (const contact of bodyB.contacts) {
364
+ if (
365
+ (contact.fixtureA === fixtureA && contact.fixtureB === fixtureB) ||
366
+ (contact.fixtureA === fixtureB && contact.fixtureB === fixtureA)
367
+ ) {
368
+ return;
369
+ }
370
+ }
371
+
372
+ for (const joint of bodyA.joints) {
373
+ if (
374
+ !joint.collideConnected &&
375
+ (joint.bodyA === bodyB || joint.bodyB === bodyB)
376
+ ) {
377
+ return;
378
+ }
379
+ }
380
+
381
+ if (
382
+ this.world.contactFilter &&
383
+ !this.world.contactFilter(fixtureA, fixtureB)
384
+ ) {
385
+ return;
386
+ }
387
+ if (!shouldCollide(fixtureA, fixtureB)) return;
388
+
389
+ const contact = Contact.create(fixtureA, fixtureB);
390
+ contact._index = this.contacts.length;
391
+ this.contacts.push(contact);
392
+ bodyA.contacts.push(contact);
393
+ bodyB.contacts.push(contact);
394
+ }
395
+
396
+ /**
397
+ * @method findNewContacts
398
+ * @description Turns this step's broadphase movement into new contacts.
399
+ */
400
+ findNewContacts() {
401
+ this.world.broadPhase.updatePairs((proxyA, proxyB) =>
402
+ this.addPair(proxyA, proxyB)
403
+ );
404
+ }
405
+
406
+ /**
407
+ * @method destroy
408
+ * @description Removes a contact, firing end-contact if it was touching.
409
+ * @param {Contact} contact
410
+ */
411
+ destroy(contact) {
412
+ const bodyA = contact.fixtureA.body;
413
+ const bodyB = contact.fixtureB.body;
414
+
415
+ if (contact.touching) {
416
+ this.world.dispatch("end-contact", contact);
417
+ bodyA.setAwake(true);
418
+ bodyB.setAwake(true);
419
+ }
420
+
421
+ const index = contact._index;
422
+ if (index >= 0 && this.contacts[index] === contact) {
423
+ const last = this.contacts.pop();
424
+ if (last !== contact) {
425
+ this.contacts[index] = last;
426
+ last._index = index;
427
+ }
428
+ contact._index = -1;
429
+ }
430
+
431
+ removeFrom(bodyA.contacts, contact);
432
+ removeFrom(bodyB.contacts, contact);
433
+ }
434
+
435
+ /**
436
+ * @method collide
437
+ * @description Refreshes every contact: drops the ones whose AABBs no longer
438
+ * overlap or whose filters changed, and re-runs the narrowphase on the rest.
439
+ */
440
+ collide() {
441
+ for (let i = this.contacts.length - 1; i >= 0; i--) {
442
+ const contact = this.contacts[i];
443
+ const fixtureA = contact.fixtureA;
444
+ const fixtureB = contact.fixtureB;
445
+ const bodyA = fixtureA.body;
446
+ const bodyB = fixtureB.body;
447
+
448
+ if (contact.filterFlag) {
449
+ if (
450
+ bodyA.type !== BodyType.DYNAMIC &&
451
+ bodyB.type !== BodyType.DYNAMIC
452
+ ) {
453
+ this.destroy(contact);
454
+ continue;
455
+ }
456
+ if (
457
+ this.world.contactFilter &&
458
+ !this.world.contactFilter(fixtureA, fixtureB)
459
+ ) {
460
+ this.destroy(contact);
461
+ continue;
462
+ }
463
+ if (!shouldCollide(fixtureA, fixtureB)) {
464
+ this.destroy(contact);
465
+ continue;
466
+ }
467
+ contact.filterFlag = false;
468
+ }
469
+
470
+ const activeA = bodyA.awake && bodyA.type !== BodyType.STATIC;
471
+ const activeB = bodyB.awake && bodyB.type !== BodyType.STATIC;
472
+ if (!activeA && !activeB) continue;
473
+
474
+ const proxyIdA = fixtureA.proxies[0].proxyId;
475
+ const proxyIdB = fixtureB.proxies[0].proxyId;
476
+ if (!this.world.broadPhase.testOverlap(proxyIdA, proxyIdB)) {
477
+ this.destroy(contact);
478
+ continue;
479
+ }
480
+
481
+ contact.update(this.world);
482
+ }
483
+ }
484
+ }
485
+
486
+ /**
487
+ * @function removeFrom
488
+ * @description Removes an item from an array in place (order is irrelevant for
489
+ * contact lists).
490
+ * @private
491
+ */
492
+ function removeFrom(array, item) {
493
+ const index = array.indexOf(item);
494
+ if (index >= 0) {
495
+ const last = array.pop();
496
+ if (index < array.length) array[index] = last;
497
+ }
498
+ }
499
+
500
+ export { Contact, ContactManager, shouldCollide, mixFriction, mixRestitution };