@codexo/exojs-physics 0.13.0 → 0.15.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 (76) hide show
  1. package/README.md +17 -10
  2. package/dist/esm/Collider.d.ts +17 -6
  3. package/dist/esm/Collider.js +28 -6
  4. package/dist/esm/Collider.js.map +1 -1
  5. package/dist/esm/ContactGraph.d.ts +49 -3
  6. package/dist/esm/ContactGraph.js +132 -44
  7. package/dist/esm/ContactGraph.js.map +1 -1
  8. package/dist/esm/PhysicsBody.d.ts +145 -15
  9. package/dist/esm/PhysicsBody.js +282 -21
  10. package/dist/esm/PhysicsBody.js.map +1 -1
  11. package/dist/esm/PhysicsWorld.d.ts +177 -39
  12. package/dist/esm/PhysicsWorld.js +412 -35
  13. package/dist/esm/PhysicsWorld.js.map +1 -1
  14. package/dist/esm/backend/NativePhysicsBackend.d.ts +5 -0
  15. package/dist/esm/backend/NativePhysicsBackend.js +14 -0
  16. package/dist/esm/backend/NativePhysicsBackend.js.map +1 -1
  17. package/dist/esm/backend/PhysicsBackend.d.ts +9 -1
  18. package/dist/esm/binding/BindingRegistry.d.ts +1 -2
  19. package/dist/esm/binding/BindingRegistry.js +2 -2
  20. package/dist/esm/binding/BindingRegistry.js.map +1 -1
  21. package/dist/esm/binding/PhysicsBinding.d.ts +7 -18
  22. package/dist/esm/binding/PhysicsBinding.js +9 -8
  23. package/dist/esm/binding/PhysicsBinding.js.map +1 -1
  24. package/dist/esm/broadphase/SweepAndPrune.d.ts +1 -0
  25. package/dist/esm/broadphase/SweepAndPrune.js +32 -3
  26. package/dist/esm/broadphase/SweepAndPrune.js.map +1 -1
  27. package/dist/esm/collision/CollisionProxy.d.ts +2 -2
  28. package/dist/esm/collision/narrowphase.js +91 -38
  29. package/dist/esm/collision/narrowphase.js.map +1 -1
  30. package/dist/esm/debug/PhysicsDebugDraw.d.ts +8 -1
  31. package/dist/esm/debug/PhysicsDebugDraw.js +26 -2
  32. package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
  33. package/dist/esm/index.js +7 -0
  34. package/dist/esm/index.js.map +1 -1
  35. package/dist/esm/joints/DistanceJoint.d.ts +71 -0
  36. package/dist/esm/joints/DistanceJoint.js +176 -0
  37. package/dist/esm/joints/DistanceJoint.js.map +1 -0
  38. package/dist/esm/joints/Joint.d.ts +25 -0
  39. package/dist/esm/joints/Joint.js +24 -0
  40. package/dist/esm/joints/Joint.js.map +1 -0
  41. package/dist/esm/joints/MouseJoint.d.ts +57 -0
  42. package/dist/esm/joints/MouseJoint.js +137 -0
  43. package/dist/esm/joints/MouseJoint.js.map +1 -0
  44. package/dist/esm/joints/PrismaticJoint.d.ts +85 -0
  45. package/dist/esm/joints/PrismaticJoint.js +241 -0
  46. package/dist/esm/joints/PrismaticJoint.js.map +1 -0
  47. package/dist/esm/joints/RevoluteJoint.d.ts +81 -0
  48. package/dist/esm/joints/RevoluteJoint.js +217 -0
  49. package/dist/esm/joints/RevoluteJoint.js.map +1 -0
  50. package/dist/esm/joints/WeldJoint.d.ts +61 -0
  51. package/dist/esm/joints/WeldJoint.js +159 -0
  52. package/dist/esm/joints/WeldJoint.js.map +1 -0
  53. package/dist/esm/joints/WheelJoint.d.ts +92 -0
  54. package/dist/esm/joints/WheelJoint.js +256 -0
  55. package/dist/esm/joints/WheelJoint.js.map +1 -0
  56. package/dist/esm/math.js +15 -1
  57. package/dist/esm/math.js.map +1 -1
  58. package/dist/esm/physicsBuildInfo.js +2 -2
  59. package/dist/esm/public.d.ts +9 -2
  60. package/dist/esm/query/QueryEngine.d.ts +2 -2
  61. package/dist/esm/query/QueryEngine.js +13 -4
  62. package/dist/esm/query/QueryEngine.js.map +1 -1
  63. package/dist/esm/shapes/AnyShape.d.ts +9 -0
  64. package/dist/esm/shapes/CircleShape.d.ts +1 -2
  65. package/dist/esm/shapes/CircleShape.js.map +1 -1
  66. package/dist/esm/shapes/PolygonShape.d.ts +1 -2
  67. package/dist/esm/shapes/PolygonShape.js +45 -17
  68. package/dist/esm/shapes/PolygonShape.js.map +1 -1
  69. package/dist/esm/shapes/index.d.ts +1 -0
  70. package/dist/esm/solver/ContactSolver.d.ts +87 -0
  71. package/dist/esm/solver/ContactSolver.js +490 -0
  72. package/dist/esm/solver/ContactSolver.js.map +1 -0
  73. package/dist/esm/sort.d.ts +17 -0
  74. package/dist/esm/sort.js +54 -0
  75. package/dist/esm/sort.js.map +1 -0
  76. package/package.json +3 -3
@@ -0,0 +1,490 @@
1
+ /** Relative normal speed (px/s) below which a contact is treated as resting (no restitution). */
2
+ /**
3
+ * Penetration allowance (px) the soft bias leaves uncorrected. The narrow phase
4
+ * only produces a manifold while the colliders overlap, so pushing penetration
5
+ * fully to zero lets a resting contact wink out for a frame (free-fall, then
6
+ * re-detect) — a periodic energy spike. Leaving a small slop keeps the contact
7
+ * persistently overlapping and the warm-start cache alive.
8
+ */
9
+ const slop = 0.25;
10
+ /**
11
+ * Cap on the soft-constraint push-out velocity (px/s). Bounds how fast the bias
12
+ * resolves deep penetration so a large overlap cannot fling bodies apart; the
13
+ * Box2D-v3 analogue is `contactSpeed = 3·lengthUnit`, retuned for ExoJS pixels.
14
+ */
15
+ const maxBiasVelocity = 4;
16
+ /** Reject the 2-point block solve when the contact matrix is worse-conditioned than this (fall back to sequential). */
17
+ const maxConditionNumber = 1000;
18
+ /**
19
+ * Per-contact velocity constraint (1–2 points), computed once per **frame** in
20
+ * {@link ContactSolver.prepare} and reused across all sub-steps and passes.
21
+ * Pooled and reused across frames, so steady-state stepping allocates nothing.
22
+ */
23
+ class ContactConstraint {
24
+ record;
25
+ bodyA;
26
+ bodyB;
27
+ nx = 0;
28
+ ny = 0;
29
+ tx = 0;
30
+ ty = 0;
31
+ friction = 0;
32
+ restitution = 0;
33
+ pointCount = 0;
34
+ // Soft-constraint factors (Box2D-v3 "soft step"), derived once per frame from
35
+ // contactHertz/dampingRatio and the sub-step `h`. Shared by both points.
36
+ biasRate = 0;
37
+ massScale = 1;
38
+ impulseScale = 0;
39
+ // Per-point contact arms at frame start (relative to each body's centre of mass).
40
+ rAx = [0, 0];
41
+ rAy = [0, 0];
42
+ rBx = [0, 0];
43
+ rBy = [0, 0];
44
+ // Per-point arms rotated by the live sub-step rotation (refreshed each pass by
45
+ // {@link ContactSolver._updateArms}); the solve reads these so a rotating body's
46
+ // contact torque tracks its current orientation.
47
+ rotAx = [0, 0];
48
+ rotAy = [0, 0];
49
+ rotBx = [0, 0];
50
+ rotBy = [0, 0];
51
+ normalMass = [0, 0];
52
+ tangentMass = [0, 0];
53
+ /** Contact separation at frame start (= −penetration; negative when overlapping). */
54
+ baseSeparation = [0, 0];
55
+ /** Relative normal velocity at frame start (the impact speed the restitution pass keys off). */
56
+ relativeVelocity = [0, 0];
57
+ /** Push-out target normal velocity for the current pass (set per pass from the live separation). */
58
+ velocityBias = [0, 0];
59
+ // 2-point block: the contact matrix `K` and its inverse (set only when the
60
+ // manifold has two points and `K` is well-conditioned; else sequential).
61
+ block = false;
62
+ k11 = 0;
63
+ k12 = 0;
64
+ k22 = 0;
65
+ invK11 = 0;
66
+ invK12 = 0;
67
+ invK22 = 0;
68
+ }
69
+ /**
70
+ * Native warm-started **TGS-Soft** contact solver (Box2D-v3 "soft step"). Driven
71
+ * by {@link PhysicsWorld} as a sub-stepping loop: detection runs once per frame,
72
+ * then {@link prepare} builds the per-contact constraints (effective masses,
73
+ * frame-start separation + impact velocity, soft factors, and a 2×2 block matrix
74
+ * for two-point manifolds) **once**, and each sub-step runs
75
+ * {@link warmStart} → {@link solveVelocities}(useBias=true) → integrate positions
76
+ * → {@link solveVelocities}(useBias=false) relax. A final {@link applyRestitution}
77
+ * pass adds bounce above the threshold.
78
+ *
79
+ * The position constraint is folded into the velocity solve as a **soft bias**
80
+ * (a damped-spring push-out whose stiffness is decoupled from the iteration
81
+ * count), recomputed each pass from the live per-body delta position/rotation —
82
+ * so there is no separate NGS geometric pass. The contact anchors are rotated by
83
+ * the live sub-step rotation each pass, so a tilting stack's restoring torque is
84
+ * computed against its current orientation (without this the tilt grows instead
85
+ * of being corrected). Two-point manifolds still solve the normal impulses **as a
86
+ * 2×2 block LCP** (Box2D-style), which propagates stack loads far better than
87
+ * solving the points sequentially; the block path carries the soft push-out as
88
+ * its velocity target (hard mass scale), while single-point contacts use the full
89
+ * soft mass/impulse scaling. Accumulated impulses are written back to each
90
+ * {@link ContactRecord} for warm-starting the next frame.
91
+ *
92
+ * Internal to {@link NativePhysicsBackend}; not part of the public surface.
93
+ */
94
+ class ContactSolver {
95
+ _constraints = [];
96
+ _count = 0;
97
+ /**
98
+ * Build the per-contact constraints for this frame from the touching solid
99
+ * contacts. `h` is the sub-step duration (`fixedDelta / subStepCount`); the
100
+ * soft factors are derived from it together with `contactHertz`/`dampingRatio`.
101
+ * Runs once per frame (detection is not repeated per sub-step).
102
+ */
103
+ prepare(contacts, h, contactHertz, dampingRatio) {
104
+ this._count = 0;
105
+ // Box2D-v3 soft-constraint factors from a damped spring (hertz, zeta) at the
106
+ // sub-step `h`: omega = 2πf; a1 = 2ζ + hω; a2 = hω·a1; a3 = 1/(1+a2).
107
+ const omega = 2 * Math.PI * contactHertz;
108
+ const a1 = 2 * dampingRatio + h * omega;
109
+ const a2 = h * omega * a1;
110
+ const a3 = 1 / (1 + a2);
111
+ const biasRate = contactHertz > 0 ? omega / a1 : 0;
112
+ const massScale = contactHertz > 0 ? a2 * a3 : 1;
113
+ const impulseScale = contactHertz > 0 ? a3 : 0;
114
+ for (const contact of contacts) {
115
+ const manifold = contact.manifold;
116
+ const pointCount = manifold.pointCount;
117
+ if (pointCount === 0) {
118
+ continue;
119
+ }
120
+ const bodyA = contact.a.body;
121
+ const bodyB = contact.b.body;
122
+ // Skip contacts where either body is asleep: a sleeping island's solid
123
+ // contacts are all sleeping↔sleeping or sleeping↔static (both at rest), so
124
+ // there is nothing to solve. A sleeping body touched by an awake one is
125
+ // woken (island merge) before this runs, so it is never skipped wrongly.
126
+ if (bodyA.isSleeping || bodyB.isSleeping) {
127
+ continue;
128
+ }
129
+ const constraint = this._acquire();
130
+ const nx = manifold.normalX;
131
+ const ny = manifold.normalY;
132
+ const tx = -ny;
133
+ const ty = nx;
134
+ constraint.record = contact;
135
+ constraint.bodyA = bodyA;
136
+ constraint.bodyB = bodyB;
137
+ constraint.nx = nx;
138
+ constraint.ny = ny;
139
+ constraint.tx = tx;
140
+ constraint.ty = ty;
141
+ constraint.friction = Math.sqrt(contact.a.friction * contact.b.friction);
142
+ constraint.restitution = Math.max(contact.a.restitution, contact.b.restitution);
143
+ constraint.pointCount = pointCount;
144
+ constraint.block = false;
145
+ constraint.biasRate = biasRate;
146
+ constraint.massScale = massScale;
147
+ constraint.impulseScale = impulseScale;
148
+ const mA = bodyA.invMass;
149
+ const mB = bodyB.invMass;
150
+ const iA = bodyA.invInertia;
151
+ const iB = bodyB.invInertia;
152
+ const comAx = bodyA.worldCenterOfMassX;
153
+ const comAy = bodyA.worldCenterOfMassY;
154
+ const comBx = bodyB.worldCenterOfMassX;
155
+ const comBy = bodyB.worldCenterOfMassY;
156
+ for (let i = 0; i < pointCount; i++) {
157
+ // i in 0..pointCount-1 and pointCount ≤ 2, so the manifold point exists.
158
+ const point = i === 0 ? manifold.points[0] : manifold.points[1];
159
+ const rAx = point.x - comAx;
160
+ const rAy = point.y - comAy;
161
+ const rBx = point.x - comBx;
162
+ const rBy = point.y - comBy;
163
+ constraint.rAx[i] = rAx;
164
+ constraint.rAy[i] = rAy;
165
+ constraint.rBx[i] = rBx;
166
+ constraint.rBy[i] = rBy;
167
+ // Frame start: no accumulated rotation yet, so the live arms equal the base arms.
168
+ constraint.rotAx[i] = rAx;
169
+ constraint.rotAy[i] = rAy;
170
+ constraint.rotBx[i] = rBx;
171
+ constraint.rotBy[i] = rBy;
172
+ const rnA = rAx * ny - rAy * nx;
173
+ const rnB = rBx * ny - rBy * nx;
174
+ const kn = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
175
+ const rtA = rAx * ty - rAy * tx;
176
+ const rtB = rBx * ty - rBy * tx;
177
+ const kt = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
178
+ constraint.normalMass[i] = kn > 0 ? 1 / kn : 0;
179
+ constraint.tangentMass[i] = kt > 0 ? 1 / kt : 0;
180
+ constraint.baseSeparation[i] = -point.penetration;
181
+ constraint.velocityBias[i] = 0;
182
+ // Frame-start relative normal velocity (the true impact speed, captured
183
+ // before this frame's gravity since prepare runs ahead of the sub-step
184
+ // loop) — keys the restitution pass so a resting contact does not
185
+ // perpetually micro-bounce off the per-step gravity increment.
186
+ constraint.relativeVelocity[i] = normalVelocity(bodyA, bodyB, rAx, rAy, rBx, rBy, nx, ny);
187
+ }
188
+ if (pointCount === 2) {
189
+ const rn1A = n(constraint.rAx, 0) * ny - n(constraint.rAy, 0) * nx;
190
+ const rn1B = n(constraint.rBx, 0) * ny - n(constraint.rBy, 0) * nx;
191
+ const rn2A = n(constraint.rAx, 1) * ny - n(constraint.rAy, 1) * nx;
192
+ const rn2B = n(constraint.rBx, 1) * ny - n(constraint.rBy, 1) * nx;
193
+ const k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
194
+ const k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
195
+ const k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
196
+ const det = k11 * k22 - k12 * k12;
197
+ // Only block-solve when `K` is well-conditioned (parallel-ish contacts
198
+ // produce a near-singular matrix → fall back to sequential).
199
+ if (det > 0 && k11 * k11 < maxConditionNumber * det) {
200
+ const invDet = 1 / det;
201
+ constraint.k11 = k11;
202
+ constraint.k12 = k12;
203
+ constraint.k22 = k22;
204
+ constraint.invK11 = invDet * k22;
205
+ constraint.invK12 = -invDet * k12;
206
+ constraint.invK22 = invDet * k11;
207
+ constraint.block = true;
208
+ }
209
+ }
210
+ }
211
+ }
212
+ /** Re-apply the cached impulses from the previous frame (warm-starting); runs each sub-step. */
213
+ warmStart() {
214
+ for (let ci = 0; ci < this._count; ci++) {
215
+ const constraint = this._at(ci);
216
+ const bodyA = constraint.bodyA;
217
+ const bodyB = constraint.bodyB;
218
+ this._updateArms(constraint);
219
+ for (let i = 0; i < constraint.pointCount; i++) {
220
+ const normalImpulse = n(constraint.record.normalImpulse, i);
221
+ const tangentImpulse = n(constraint.record.tangentImpulse, i);
222
+ const jx = normalImpulse * constraint.nx + tangentImpulse * constraint.tx;
223
+ const jy = normalImpulse * constraint.ny + tangentImpulse * constraint.ty;
224
+ applyImpulse(bodyA, bodyB, n(constraint.rotAx, i), n(constraint.rotAy, i), n(constraint.rotBx, i), n(constraint.rotBy, i), jx, jy);
225
+ }
226
+ }
227
+ }
228
+ /**
229
+ * One velocity pass over every contact: the normal constraint (block when
230
+ * possible) then friction (Coulomb cone). With `useBias` the normal solve
231
+ * carries the soft push-out bias (the main pass, recomputed from the live
232
+ * separation); without it the relax pass drives the normal velocity to zero so
233
+ * the bias velocity does not remain in the bodies as injected energy.
234
+ */
235
+ solveVelocities(useBias) {
236
+ for (let ci = 0; ci < this._count; ci++) {
237
+ this._solveVelocityContact(this._at(ci), useBias);
238
+ }
239
+ }
240
+ /**
241
+ * Restitution pass, run once after the sub-step loop. For each loaded point
242
+ * whose frame-start impact speed exceeded the threshold, add the impulse that
243
+ * brings the post-solve normal velocity to `−restitution·impactSpeed`. Kept
244
+ * separate from the main solve so resting contacts (impact below threshold) do
245
+ * not micro-bounce.
246
+ */
247
+ applyRestitution() {
248
+ for (let ci = 0; ci < this._count; ci++) {
249
+ const constraint = this._at(ci);
250
+ if (constraint.restitution === 0) {
251
+ continue;
252
+ }
253
+ const bodyA = constraint.bodyA;
254
+ const bodyB = constraint.bodyB;
255
+ const nx = constraint.nx;
256
+ const ny = constraint.ny;
257
+ this._updateArms(constraint);
258
+ for (let i = 0; i < constraint.pointCount; i++) {
259
+ const relativeVelocity = n(constraint.relativeVelocity, i);
260
+ // Only points that carried load (normalImpulse > 0) and were struck
261
+ // above the resting threshold bounce.
262
+ if (relativeVelocity > -1 || n(constraint.record.normalImpulse, i) <= 0) {
263
+ continue;
264
+ }
265
+ const rAx = n(constraint.rotAx, i);
266
+ const rAy = n(constraint.rotAy, i);
267
+ const rBx = n(constraint.rotBx, i);
268
+ const rBy = n(constraint.rotBy, i);
269
+ const vn = normalVelocity(bodyA, bodyB, rAx, rAy, rBx, rBy, nx, ny);
270
+ const oldNormal = n(constraint.record.normalImpulse, i);
271
+ const newNormal = Math.max(0, oldNormal - n(constraint.normalMass, i) * (vn + constraint.restitution * relativeVelocity));
272
+ const deltaNormal = newNormal - oldNormal;
273
+ constraint.record.normalImpulse[i] = newNormal;
274
+ applyImpulse(bodyA, bodyB, rAx, rAy, rBx, rBy, deltaNormal * nx, deltaNormal * ny);
275
+ }
276
+ }
277
+ }
278
+ /** Refresh the live (rotated) contact arms from each body's accumulated sub-step rotation. */
279
+ _updateArms(constraint) {
280
+ const cosA = constraint.bodyA._deltaCos;
281
+ const sinA = constraint.bodyA._deltaSin;
282
+ const cosB = constraint.bodyB._deltaCos;
283
+ const sinB = constraint.bodyB._deltaSin;
284
+ for (let i = 0; i < constraint.pointCount; i++) {
285
+ const rAx = n(constraint.rAx, i);
286
+ const rAy = n(constraint.rAy, i);
287
+ const rBx = n(constraint.rBx, i);
288
+ const rBy = n(constraint.rBy, i);
289
+ constraint.rotAx[i] = rAx * cosA - rAy * sinA;
290
+ constraint.rotAy[i] = rAx * sinA + rAy * cosA;
291
+ constraint.rotBx[i] = rBx * cosB - rBy * sinB;
292
+ constraint.rotBy[i] = rBx * sinB + rBy * cosB;
293
+ }
294
+ }
295
+ _solveVelocityContact(constraint, useBias) {
296
+ this._updateArms(constraint);
297
+ // Recompute the per-point push-out target from the live separation (folds the
298
+ // position constraint into the velocity solve as a soft bias). With useBias
299
+ // off (relax pass) the target is zero — the plain hard normal solve.
300
+ for (let i = 0; i < constraint.pointCount; i++) {
301
+ // Push out only the penetration beyond the slop, capped — leaving the slop
302
+ // keeps the contact overlapping so the narrow phase does not drop it.
303
+ const excess = -currentSeparation(constraint, i) - slop;
304
+ constraint.velocityBias[i] = useBias && excess > 0 ? Math.min(constraint.biasRate * excess, maxBiasVelocity) : 0;
305
+ }
306
+ // Normal before friction (Box2D-v3 order): friction's Coulomb cone clamps to
307
+ // `μ·normalImpulse`, so it must see this pass's freshly-solved normal impulse —
308
+ // solving friction first uses last pass's cone and lets stacks creep laterally.
309
+ if (constraint.block) {
310
+ this._solveNormalBlock(constraint);
311
+ }
312
+ else {
313
+ this._solveNormalSequential(constraint, useBias);
314
+ }
315
+ this._solveFriction(constraint);
316
+ }
317
+ /** Per-point friction: clamp the accumulated tangent impulse to the Coulomb cone `±μ·normalImpulse`. */
318
+ _solveFriction(constraint) {
319
+ const bodyA = constraint.bodyA;
320
+ const bodyB = constraint.bodyB;
321
+ for (let i = 0; i < constraint.pointCount; i++) {
322
+ const rAx = n(constraint.rotAx, i);
323
+ const rAy = n(constraint.rotAy, i);
324
+ const rBx = n(constraint.rotBx, i);
325
+ const rBy = n(constraint.rotBy, i);
326
+ const vtX = bodyB.linearVelocityX - bodyB.angularVelocity * rBy - (bodyA.linearVelocityX - bodyA.angularVelocity * rAy);
327
+ const vtY = bodyB.linearVelocityY + bodyB.angularVelocity * rBx - (bodyA.linearVelocityY + bodyA.angularVelocity * rAx);
328
+ const vt = vtX * constraint.tx + vtY * constraint.ty;
329
+ const maxFriction = constraint.friction * n(constraint.record.normalImpulse, i);
330
+ const oldTangent = n(constraint.record.tangentImpulse, i);
331
+ const newTangent = clamp(oldTangent - n(constraint.tangentMass, i) * vt, -maxFriction, maxFriction);
332
+ const deltaTangent = newTangent - oldTangent;
333
+ constraint.record.tangentImpulse[i] = newTangent;
334
+ applyImpulse(bodyA, bodyB, rAx, rAy, rBx, rBy, deltaTangent * constraint.tx, deltaTangent * constraint.ty);
335
+ }
336
+ }
337
+ /**
338
+ * Single-point (or ill-conditioned) soft normal solve, accumulated and clamped
339
+ * ≥ 0. The Box2D-v3 incremental form: with the soft bias active the impulse is
340
+ * `−normalMass·massScale·(vn − bias) − impulseScale·accumulated`, which both
341
+ * pushes out the penetration and bleeds a little stored impulse (the damped
342
+ * spring). The relax pass passes `useBias=false`, collapsing it to the hard
343
+ * `−normalMass·vn` (no bias, full mass, no impulse decay).
344
+ */
345
+ _solveNormalSequential(constraint, useBias) {
346
+ const bodyA = constraint.bodyA;
347
+ const bodyB = constraint.bodyB;
348
+ const nx = constraint.nx;
349
+ const ny = constraint.ny;
350
+ const massScale = useBias ? constraint.massScale : 1;
351
+ const impulseScale = useBias ? constraint.impulseScale : 0;
352
+ for (let i = 0; i < constraint.pointCount; i++) {
353
+ const rAx = n(constraint.rotAx, i);
354
+ const rAy = n(constraint.rotAy, i);
355
+ const rBx = n(constraint.rotBx, i);
356
+ const rBy = n(constraint.rotBy, i);
357
+ const vn = normalVelocity(bodyA, bodyB, rAx, rAy, rBx, rBy, nx, ny);
358
+ const oldNormal = n(constraint.record.normalImpulse, i);
359
+ const impulse = -n(constraint.normalMass, i) * massScale * (vn - n(constraint.velocityBias, i)) - impulseScale * oldNormal;
360
+ const newNormal = Math.max(0, oldNormal + impulse);
361
+ const deltaNormal = newNormal - oldNormal;
362
+ constraint.record.normalImpulse[i] = newNormal;
363
+ applyImpulse(bodyA, bodyB, rAx, rAy, rBx, rBy, deltaNormal * nx, deltaNormal * ny);
364
+ }
365
+ }
366
+ /**
367
+ * Two-point block normal solve (Box2D LCP): find both new normal impulses
368
+ * `x ≥ 0` so the post-solve normal velocities equal the push-out targets
369
+ * (`velocityBias`, zero in the relax pass) and are complementary, trying the
370
+ * four corners (both active, one active, none). The block path carries the
371
+ * soft push-out as its target but solves with a hard mass scale.
372
+ */
373
+ _solveNormalBlock(constraint) {
374
+ const bodyA = constraint.bodyA;
375
+ const bodyB = constraint.bodyB;
376
+ const nx = constraint.nx;
377
+ const ny = constraint.ny;
378
+ const a1 = n(constraint.record.normalImpulse, 0);
379
+ const a2 = n(constraint.record.normalImpulse, 1);
380
+ const vn1 = normalVelocity(bodyA, bodyB, n(constraint.rotAx, 0), n(constraint.rotAy, 0), n(constraint.rotBx, 0), n(constraint.rotBy, 0), nx, ny);
381
+ const vn2 = normalVelocity(bodyA, bodyB, n(constraint.rotAx, 1), n(constraint.rotAy, 1), n(constraint.rotBx, 1), n(constraint.rotBy, 1), nx, ny);
382
+ // Residual at the current impulse: b = (vn − bias) − K·a.
383
+ const bx = vn1 - n(constraint.velocityBias, 0) - (constraint.k11 * a1 + constraint.k12 * a2);
384
+ const by = vn2 - n(constraint.velocityBias, 1) - (constraint.k12 * a1 + constraint.k22 * a2);
385
+ // Case 1 — both points active: x = −K⁻¹·b.
386
+ let x1 = -(constraint.invK11 * bx + constraint.invK12 * by);
387
+ let x2 = -(constraint.invK12 * bx + constraint.invK22 * by);
388
+ if (x1 >= 0 && x2 >= 0) {
389
+ this._applyBlock(constraint, x1 - a1, x2 - a2);
390
+ constraint.record.normalImpulse[0] = x1;
391
+ constraint.record.normalImpulse[1] = x2;
392
+ return;
393
+ }
394
+ // Case 2 — only point 1 active (x2 = 0).
395
+ x1 = -n(constraint.normalMass, 0) * bx;
396
+ x2 = 0;
397
+ if (x1 >= 0 && constraint.k12 * x1 + by >= 0) {
398
+ this._applyBlock(constraint, x1 - a1, x2 - a2);
399
+ constraint.record.normalImpulse[0] = x1;
400
+ constraint.record.normalImpulse[1] = x2;
401
+ return;
402
+ }
403
+ // Case 3 — only point 2 active (x1 = 0).
404
+ x1 = 0;
405
+ x2 = -n(constraint.normalMass, 1) * by;
406
+ if (x2 >= 0 && constraint.k12 * x2 + bx >= 0) {
407
+ this._applyBlock(constraint, x1 - a1, x2 - a2);
408
+ constraint.record.normalImpulse[0] = x1;
409
+ constraint.record.normalImpulse[1] = x2;
410
+ return;
411
+ }
412
+ // Case 4 — neither active (separating). Only valid when both residuals are non-negative.
413
+ if (bx >= 0 && by >= 0) {
414
+ this._applyBlock(constraint, -a1, -a2);
415
+ constraint.record.normalImpulse[0] = 0;
416
+ constraint.record.normalImpulse[1] = 0;
417
+ }
418
+ }
419
+ /** Apply the two-point block impulse deltas `(d1, d2)` along the normal at both contact points. */
420
+ _applyBlock(constraint, d1, d2) {
421
+ const bodyA = constraint.bodyA;
422
+ const bodyB = constraint.bodyB;
423
+ const nx = constraint.nx;
424
+ const ny = constraint.ny;
425
+ applyImpulse(bodyA, bodyB, n(constraint.rotAx, 0), n(constraint.rotAy, 0), n(constraint.rotBx, 0), n(constraint.rotBy, 0), d1 * nx, d1 * ny);
426
+ applyImpulse(bodyA, bodyB, n(constraint.rotAx, 1), n(constraint.rotAy, 1), n(constraint.rotBx, 1), n(constraint.rotBy, 1), d2 * nx, d2 * ny);
427
+ }
428
+ _acquire() {
429
+ if (this._count === this._constraints.length) {
430
+ this._constraints.push(new ContactConstraint());
431
+ }
432
+ return this._at(this._count++);
433
+ }
434
+ /**
435
+ * Pooled constraint at `ci`. Every caller indexes within `0..this._count-1`
436
+ * and `_count` never exceeds the pool length, so the entry always exists; the
437
+ * throw is unreachable and only discharges `noUncheckedIndexedAccess` without a
438
+ * cast or non-null assertion.
439
+ */
440
+ _at(ci) {
441
+ const constraint = this._constraints[ci];
442
+ if (constraint === undefined) {
443
+ throw new RangeError(`ContactSolver: constraint pool index ${ci} out of range.`);
444
+ }
445
+ return constraint;
446
+ }
447
+ }
448
+ /**
449
+ * Live contact separation at point `i`, recomputed from each body's accumulated
450
+ * delta position plus the rotation-induced shift of the (rotated) anchor since
451
+ * frame start, projected onto the normal. Negative when overlapping. This is what
452
+ * folds the position constraint into the velocity solve without a separate
453
+ * geometric pass or re-running detection per sub-step.
454
+ */
455
+ const currentSeparation = (constraint, i) => {
456
+ const bodyA = constraint.bodyA;
457
+ const bodyB = constraint.bodyB;
458
+ // Anchor displacement since frame start = linear delta + (rotated arm − base arm).
459
+ const dispAx = bodyA._deltaPosX + n(constraint.rotAx, i) - n(constraint.rAx, i);
460
+ const dispAy = bodyA._deltaPosY + n(constraint.rotAy, i) - n(constraint.rAy, i);
461
+ const dispBx = bodyB._deltaPosX + n(constraint.rotBx, i) - n(constraint.rBx, i);
462
+ const dispBy = bodyB._deltaPosY + n(constraint.rotBy, i) - n(constraint.rBy, i);
463
+ return n(constraint.baseSeparation, i) + (dispBx - dispAx) * constraint.nx + (dispBy - dispAy) * constraint.ny;
464
+ };
465
+ /** Relative normal velocity at a contact point: `dot(vB + ωB×rB − vA − ωA×rA, n)`. */
466
+ const normalVelocity = (bodyA, bodyB, rAx, rAy, rBx, rBy, nx, ny) => {
467
+ const dvx = bodyB.linearVelocityX - bodyB.angularVelocity * rBy - (bodyA.linearVelocityX - bodyA.angularVelocity * rAy);
468
+ const dvy = bodyB.linearVelocityY + bodyB.angularVelocity * rBx - (bodyA.linearVelocityY + bodyA.angularVelocity * rAx);
469
+ return dvx * nx + dvy * ny;
470
+ };
471
+ /** Apply impulse `(jx, jy)` to B and its negation to A about their contact arms. */
472
+ const applyImpulse = (bodyA, bodyB, rAx, rAy, rBx, rBy, jx, jy) => {
473
+ bodyA.linearVelocityX -= jx * bodyA.invMass;
474
+ bodyA.linearVelocityY -= jy * bodyA.invMass;
475
+ bodyA.angularVelocity -= (rAx * jy - rAy * jx) * bodyA.invInertia;
476
+ bodyB.linearVelocityX += jx * bodyB.invMass;
477
+ bodyB.linearVelocityY += jy * bodyB.invMass;
478
+ bodyB.angularVelocity += (rBx * jy - rBy * jx) * bodyB.invInertia;
479
+ };
480
+ const clamp = (value, low, high) => Math.min(Math.max(value, low), high);
481
+ /**
482
+ * In-bounds read of a fixed-size (length-2) per-point scratch array. Every
483
+ * caller indexes within `0..pointCount-1` (pointCount ≤ 2), so the element
484
+ * always exists; the `0` fallback only discharges `noUncheckedIndexedAccess`
485
+ * for the unreachable case and keeps the `??` out of caller complexity.
486
+ */
487
+ const n = (arr, i) => arr[i] ?? 0;
488
+
489
+ export { ContactSolver };
490
+ //# sourceMappingURL=ContactSolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContactSolver.js","sources":["../../../../src/solver/ContactSolver.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * In-place heap sort — deterministic, O(n log n) regardless of input order, and
3
+ * allocation-free. `Array.prototype.sort` allocates an internal temp buffer in
4
+ * V8's TimSort for arrays larger than ~10 elements; the broad-phase and contact
5
+ * sorts run over ~1,000 elements every step, so that temp buffer is per-step
6
+ * garbage. Heap sort sorts in place with only a constant number of locals.
7
+ *
8
+ * Heap sort is not stable, but every physics comparator (`byMinX`, `byPairId`,
9
+ * `byRecordPair`, `byColliderPair`, `bySensorPair`) breaks ties on collider id,
10
+ * so no two elements ever compare equal — the ordering is total and therefore
11
+ * bit-identical to the `Array.prototype.sort` it replaces (gate SG-D1, replay
12
+ * determinism). Do not use this with a comparator that can return 0 for distinct
13
+ * elements; the result order would then differ from a stable sort.
14
+ *
15
+ * @internal
16
+ */
17
+ export declare function sortInPlace<T>(array: T[], compare: (a: T, b: T) => number): void;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * In-place heap sort — deterministic, O(n log n) regardless of input order, and
3
+ * allocation-free. `Array.prototype.sort` allocates an internal temp buffer in
4
+ * V8's TimSort for arrays larger than ~10 elements; the broad-phase and contact
5
+ * sorts run over ~1,000 elements every step, so that temp buffer is per-step
6
+ * garbage. Heap sort sorts in place with only a constant number of locals.
7
+ *
8
+ * Heap sort is not stable, but every physics comparator (`byMinX`, `byPairId`,
9
+ * `byRecordPair`, `byColliderPair`, `bySensorPair`) breaks ties on collider id,
10
+ * so no two elements ever compare equal — the ordering is total and therefore
11
+ * bit-identical to the `Array.prototype.sort` it replaces (gate SG-D1, replay
12
+ * determinism). Do not use this with a comparator that can return 0 for distinct
13
+ * elements; the result order would then differ from a stable sort.
14
+ *
15
+ * @internal
16
+ */
17
+ function sortInPlace(array, compare) {
18
+ const n = array.length;
19
+ // Heapify: turn the array into a max-heap bottom-up.
20
+ for (let i = (n >> 1) - 1; i >= 0; i--) {
21
+ siftDown(array, i, n, compare);
22
+ }
23
+ // Repeatedly move the max (root) to the sorted tail, then restore the heap.
24
+ for (let end = n - 1; end > 0; end--) {
25
+ const root = array[0];
26
+ array[0] = array[end];
27
+ array[end] = root;
28
+ siftDown(array, 0, end, compare);
29
+ }
30
+ }
31
+ function siftDown(array, start, end, compare) {
32
+ let parent = start;
33
+ for (;;) {
34
+ let child = parent * 2 + 1;
35
+ if (child >= end) {
36
+ break;
37
+ }
38
+ // Pick the larger of the two children.
39
+ if (child + 1 < end && compare(array[child], array[child + 1]) < 0) {
40
+ child++;
41
+ }
42
+ // Parent already dominates the larger child — heap property restored.
43
+ if (compare(array[parent], array[child]) >= 0) {
44
+ break;
45
+ }
46
+ const tmp = array[parent];
47
+ array[parent] = array[child];
48
+ array[child] = tmp;
49
+ parent = child;
50
+ }
51
+ }
52
+
53
+ export { sortInPlace };
54
+ //# sourceMappingURL=sort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.js","sources":["../../../src/sort.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;AAeG;AACG,SAAU,WAAW,CAAI,KAAU,EAAE,OAA+B,EAAA;AACxE,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM;;AAGtB,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QACtC,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAChC;;AAGA,IAAA,KAAK,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AACpC,QAAA,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE;QACtB,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAE;AACtB,QAAA,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI;QACjB,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC;IAClC;AACF;AAEA,SAAS,QAAQ,CAAI,KAAU,EAAE,KAAa,EAAE,GAAW,EAAE,OAA+B,EAAA;IAC1F,IAAI,MAAM,GAAG,KAAK;AAElB,IAAA,SAAS;AACP,QAAA,IAAI,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC;AAE1B,QAAA,IAAI,KAAK,IAAI,GAAG,EAAE;YAChB;QACF;;QAGA,IAAI,KAAK,GAAG,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAE,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAE,CAAC,GAAG,CAAC,EAAE;AACpE,YAAA,KAAK,EAAE;QACT;;AAGA,QAAA,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAE,EAAE,KAAK,CAAC,KAAK,CAAE,CAAC,IAAI,CAAC,EAAE;YAC/C;QACF;AAEA,QAAA,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAE;QAC1B,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAE;AAC7B,QAAA,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG;QAClB,MAAM,GAAG,KAAK;IAChB;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexo/exojs-physics",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Native 2D collision, query and sensor runtime for ExoJS.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,10 +31,10 @@
31
31
  "LICENSE"
32
32
  ],
33
33
  "peerDependencies": {
34
- "@codexo/exojs": "0.13.x"
34
+ "@codexo/exojs": "0.15.x"
35
35
  },
36
36
  "devDependencies": {
37
- "@codexo/exojs": "0.13.0",
37
+ "@codexo/exojs": "0.15.0",
38
38
  "@codexo/exojs-config": "0.0.0"
39
39
  },
40
40
  "license": "MIT",