@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
@@ -1,21 +1,45 @@
1
1
  import { Signal, Vector } from '@codexo/exojs';
2
2
  import { NativePhysicsBackend } from './backend/NativePhysicsBackend.js';
3
3
  import { BindingRegistry } from './binding/BindingRegistry.js';
4
+ import { Collider } from './Collider.js';
4
5
  import { PhysicsBody } from './PhysicsBody.js';
5
6
  import { QueryEngine } from './query/QueryEngine.js';
6
7
  import { TimeStepper } from './TimeStepper.js';
7
8
 
9
+ /** Gap left between a clamped bullet and the surface it hit (so it does not re-hit from inside). */
10
+ const ccdSkin = 0.05;
8
11
  /**
9
12
  * The collision/query world: owns bodies, colliders, the detection backend,
10
13
  * bindings, the query engine and the fixed-step accumulator. Stepped by the
11
- * caller (commonly from a `Scene.update`), it runs broad- and narrow-phase
12
- * detection, fires immutable contact/sensor events, and writes bound node
13
- * transforms. It holds **no module-level state**, so any number of worlds run
14
- * in isolation (gate I-1).
14
+ * caller (commonly from a `Scene.update`), each fixed sub-step it integrates
15
+ * body velocities, runs broad- and narrow-phase detection, solves contacts and
16
+ * integrates positions, then fires immutable contact/sensor events and writes
17
+ * bound node transforms. It holds **no module-level state**, so any number of
18
+ * worlds run in isolation (gate I-1).
15
19
  *
16
- * This release performs collision detection, sensors, events, queries and
17
- * binding; bodies move only via {@link PhysicsBody.setTransform}. Gravity,
18
- * forces and impulse integration arrive with the dynamics solver.
20
+ * The dynamics are a native, warm-started **TGS-Soft** solver (Box2D-v3 "soft
21
+ * step"): each fixed step runs detection once, then several sub-steps, each
22
+ * integrating gravity over the sub-step and solving contacts with a soft
23
+ * position bias plus a bias-free relax pass; a 2-point block normal solve
24
+ * propagates stack loads, and restitution is a separate final pass. Decoupling
25
+ * stiffness from the iteration count keeps tall towers stable. The detection
26
+ * backend sits behind an internal seam, so the solver is swappable without
27
+ * touching this public surface.
28
+ *
29
+ * **Operating envelope.** The soft solver trades a little accuracy for
30
+ * robustness, so it has a few documented limits — each stays finite/stable and
31
+ * each is pinned by a gate in `dynamics.test.ts`:
32
+ * - **Mass ratio** — resting stacks are slop-accurate up to ~100:1. Beyond that
33
+ * the velocity-capped soft push-out (`maxBiasVelocity`) lets the lighter body
34
+ * settle progressively deeper (≈6px at 500:1, fully through a thin floor by
35
+ * ~5000:1) — always finite, never exploding (SG-MR3).
36
+ * - **No CCD** — detection runs once per fixed step with no swept test, so a
37
+ * body that travels farther than an obstacle's thickness in one step tunnels
38
+ * straight through it (it stays finite). Reliably stopping fast projectiles is
39
+ * a future bullet-mode feature (SG-X5).
40
+ * - **{@link PhysicsWorldOptions.subStepCount}** — the default `4` is
41
+ * load-bearing for tall-stack stability; lowering it below `2` visibly
42
+ * degrades stacking, so do not reduce it for performance.
19
43
  */
20
44
  class PhysicsWorld {
21
45
  /** Fires when two solid colliders begin touching. Argument is an immutable snapshot. */
@@ -26,32 +50,60 @@ class PhysicsWorld {
26
50
  onSensorEnter = new Signal();
27
51
  /** Fires when a collider leaves a sensor. */
28
52
  onSensorExit = new Signal();
29
- /** World gravity (px/s², +Y down). Stored until dynamics ship. */
53
+ /** World gravity (px/s², +Y down). Integrated each sub-step. */
30
54
  gravity;
31
55
  /** The fixed-step accumulator. */
32
56
  timeStepper;
33
- /** Whether bound nodes interpolate between sub-steps (no effect until dynamics). */
34
- interpolation;
35
- /** Solver velocity iterations (stored for forward-compat). */
36
- velocityIterations;
37
- /** Solver position iterations (stored for forward-compat). */
38
- positionIterations;
57
+ /** TGS-Soft sub-steps per fixed step. */
58
+ subStepCount;
59
+ /** Soft-contact stiffness in Hz. */
60
+ contactHertz;
61
+ /** Soft-contact damping ratio. */
62
+ dampingRatio;
63
+ /** Whether resting bodies are put to sleep. */
64
+ enableSleeping;
65
+ /** Linear sleep threshold (px/s). */
66
+ sleepLinearVelocity;
67
+ /** Angular sleep threshold (rad/s). */
68
+ sleepAngularVelocity;
69
+ /** Seconds below the thresholds before a body sleeps. */
70
+ timeToSleep;
39
71
  _backend = new NativePhysicsBackend();
40
72
  _bodies = [];
41
73
  _colliders = [];
74
+ _joints = [];
42
75
  _bindings = new BindingRegistry();
43
76
  _query;
44
77
  _commands = [];
78
+ /** Pooled union-find parent array for the per-step island pass (reused; sized to the body count). */
79
+ _islandParent = [];
80
+ /** Pooled per-island minimum sleep time, indexed by union-find root. */
81
+ _islandMinSleep = [];
82
+ /** Pooled ray-hit buffer + origin/direction for the CCD swept test. */
83
+ _ccdHits = [];
84
+ _ccdOrigin = { x: 0, y: 0 };
85
+ _ccdDir = { x: 0, y: 0 };
45
86
  _nextBodyId = 1;
46
87
  _nextColliderId = 1;
47
88
  _dispatching = false;
48
89
  _destroyed = false;
49
90
  constructor(options = {}) {
50
91
  this.gravity = new Vector(options.gravity?.x ?? 0, options.gravity?.y ?? 0);
51
- this.timeStepper = new TimeStepper({ fixedDelta: options.fixedDelta, maxSubSteps: options.maxSubSteps });
52
- this.interpolation = options.interpolation ?? true;
53
- this.velocityIterations = options.velocityIterations ?? 8;
54
- this.positionIterations = options.positionIterations ?? 3;
92
+ this.timeStepper = new TimeStepper({
93
+ ...(options.fixedDelta !== undefined && { fixedDelta: options.fixedDelta }),
94
+ ...(options.maxSubSteps !== undefined && { maxSubSteps: options.maxSubSteps }),
95
+ });
96
+ const subStepCount = options.subStepCount ?? 4;
97
+ if (!Number.isInteger(subStepCount) || subStepCount < 1) {
98
+ throw new RangeError(`PhysicsWorld: subStepCount must be an integer ≥ 1, received ${subStepCount}.`);
99
+ }
100
+ this.subStepCount = subStepCount;
101
+ this.contactHertz = options.contactHertz ?? 30;
102
+ this.dampingRatio = options.dampingRatio ?? 10;
103
+ this.enableSleeping = options.enableSleeping ?? true;
104
+ this.sleepLinearVelocity = options.sleepLinearVelocity ?? 5;
105
+ this.sleepAngularVelocity = options.sleepAngularVelocity ?? 0.06;
106
+ this.timeToSleep = options.timeToSleep ?? 0.5;
55
107
  this._query = new QueryEngine(this._colliders);
56
108
  }
57
109
  /** Live bodies (read-only view). */
@@ -63,10 +115,24 @@ class PhysicsWorld {
63
115
  return this._colliders;
64
116
  }
65
117
  // ── lifecycle ──────────────────────────────────────────────────────────
66
- /** Create a body. Safe to call inside an event callback (deferred to end of step). */
67
- createBody(options) {
118
+ /**
119
+ * Add a body to the world: allocates the body and its collider ids, registers
120
+ * the colliders, computes the mass model and tracks the body for stepping.
121
+ * Construct the body freely first (`new PhysicsBody({ … })`), then add it.
122
+ * Safe to call inside an event callback — the body push is deferred to the end
123
+ * of the step, exactly like collider registration. Returns the body.
124
+ *
125
+ * @throws if the body has already been added to a world.
126
+ */
127
+ add(body) {
68
128
  this._assertAlive();
69
- const body = new PhysicsBody(this, this._nextBodyId++, options);
129
+ if (body.attached) {
130
+ throw new Error('PhysicsWorld.add: this body has already been added to a world.');
131
+ }
132
+ // Allocate the id + link/register colliders + aggregate mass now (matches the
133
+ // old createBody, which allocated the id synchronously); only the body-list
134
+ // push is deferred so it is safe inside an event dispatch.
135
+ body._attachToWorld(this, this._nextBodyId++);
70
136
  this._defer(() => {
71
137
  if (!body.destroyed) {
72
138
  this._bodies.push(body);
@@ -74,10 +140,34 @@ class PhysicsWorld {
74
140
  });
75
141
  return body;
76
142
  }
77
- /** Sugar: an explicit static body carrying a single collider. The body is addressable via `collider.body`. */
78
- createStaticCollider(options) {
79
- const body = this.createBody({ type: 'static', position: options.position, angle: options.angle });
80
- return body.createCollider(options);
143
+ /**
144
+ * Convenience: create a body carrying a single collider, add it to the world
145
+ * and bind it to `node` in one call. The node tracks `body.position` after each
146
+ * step. Returns the body. Equivalent to `new PhysicsBody(...)` + `add` + `bind`.
147
+ */
148
+ attach(node, options) {
149
+ const body = new PhysicsBody({
150
+ ...(options.type !== undefined && { type: options.type }),
151
+ ...(options.position !== undefined && { position: options.position }),
152
+ ...(options.angle !== undefined && { angle: options.angle }),
153
+ ...(options.gravityScale !== undefined && { gravityScale: options.gravityScale }),
154
+ ...(options.fixedRotation !== undefined && { fixedRotation: options.fixedRotation }),
155
+ colliders: [
156
+ new Collider({
157
+ shape: options.shape,
158
+ ...(options.offset !== undefined && { offset: options.offset }),
159
+ ...(options.rotation !== undefined && { rotation: options.rotation }),
160
+ ...(options.density !== undefined && { density: options.density }),
161
+ ...(options.friction !== undefined && { friction: options.friction }),
162
+ ...(options.restitution !== undefined && { restitution: options.restitution }),
163
+ ...(options.isSensor !== undefined && { isSensor: options.isSensor }),
164
+ ...(options.filter !== undefined && { filter: options.filter }),
165
+ }),
166
+ ],
167
+ });
168
+ this.add(body);
169
+ this.bind(body, node);
170
+ return body;
81
171
  }
82
172
  /** Destroy a body and its colliders. Deferred when called inside a callback. */
83
173
  destroyBody(body) {
@@ -87,22 +177,115 @@ class PhysicsWorld {
87
177
  destroyCollider(collider) {
88
178
  this._defer(() => this._removeCollider(collider));
89
179
  }
180
+ /** Live joints (read-only view). */
181
+ get joints() {
182
+ return this._joints;
183
+ }
184
+ /**
185
+ * Add a constraint joint. Construct it first (`new DistanceJoint({ … })`),
186
+ * then add it. Wakes both bodies; safe inside a callback (registration is
187
+ * deferred). Returns the joint.
188
+ */
189
+ addJoint(joint) {
190
+ this._assertAlive();
191
+ joint.bodyA.wake();
192
+ joint.bodyB.wake();
193
+ this._defer(() => {
194
+ if (!this._joints.includes(joint)) {
195
+ this._joints.push(joint);
196
+ }
197
+ });
198
+ return joint;
199
+ }
200
+ /** Remove a joint, waking both bodies so they respond to the lost constraint. Deferred when called inside a callback. */
201
+ removeJoint(joint) {
202
+ joint.bodyA.wake();
203
+ joint.bodyB.wake();
204
+ this._defer(() => {
205
+ const index = this._joints.indexOf(joint);
206
+ if (index !== -1) {
207
+ this._joints.splice(index, 1);
208
+ }
209
+ });
210
+ }
90
211
  // ── stepping ───────────────────────────────────────────────────────────
91
212
  /**
92
- * Advance the world by `frameDeltaSeconds`. Accumulates into fixed sub-steps,
93
- * runs detection, dispatches events, then writes bound node transforms.
213
+ * Advance the world by `frameDeltaSeconds`. Accumulates into fixed steps; each
214
+ * fixed step runs detection once, then a TGS-Soft sub-step loop (integrate
215
+ * gravity, solve contacts with a soft bias, integrate positions, relax) and a
216
+ * restitution pass, then writes the accumulated motion into each body. Finally
217
+ * dispatches events and writes bound node transforms.
94
218
  */
95
219
  step(frameDeltaSeconds) {
96
220
  this._assertAlive();
97
221
  const steps = this.timeStepper.advance(frameDeltaSeconds);
98
222
  if (steps > 0) {
99
- // Without dynamics, geometry is unchanged across sub-steps, so a single
100
- // detection pass per frame suffices; the dynamics solver will run per
101
- // sub-step here.
102
- for (const body of this._bodies) {
103
- body.synchronizeColliders();
223
+ const subStepCount = this.subStepCount;
224
+ const h = this.timeStepper.fixedDelta / subStepCount;
225
+ const gravityX = this.gravity.x;
226
+ const gravityY = this.gravity.y;
227
+ const contactHertz = this.contactHertz;
228
+ const dampingRatio = this.dampingRatio;
229
+ const hasJoints = this._joints.length > 0;
230
+ const hasBullets = this._hasBullets();
231
+ for (let step = 0; step < steps; step++) {
232
+ // Detection runs once per fixed step (collider geometry is already current
233
+ // from the previous frame's finalize / attach / setTransform). TGS-Soft
234
+ // reuses the manifolds across the sub-steps below.
235
+ this._backend.detect(this._colliders);
236
+ // Sleep decision runs after detection (islands need the current contact
237
+ // set) and before the solver (so sleeping contacts are skipped, and a
238
+ // sleeping island touched by an awake body is woken first).
239
+ if (this.enableSleeping) {
240
+ this._updateSleeping(this.timeStepper.fixedDelta);
241
+ }
242
+ this._backend.prepareSolve(h, contactHertz, dampingRatio);
243
+ if (hasJoints) {
244
+ this._prepareJoints(h);
245
+ }
246
+ if (hasBullets) {
247
+ this._recordBulletPositions();
248
+ }
249
+ for (let subStep = 0; subStep < subStepCount; subStep++) {
250
+ // Integrate gravity/forces over the sub-step (forces persist across
251
+ // sub-steps; cleared once per frame by `_finalizePosition`).
252
+ for (const body of this._bodies) {
253
+ body._integrateVelocity(h, gravityX, gravityY);
254
+ }
255
+ // Warm-start every sub-step (Box2D-v3 soft step): the relax pass leaves
256
+ // each contact's normal velocity at zero, so re-applying the
257
+ // accumulated impulse re-balances exactly this sub-step's gravity — the
258
+ // impulse converges to the per-sub-step load (m·h·g), not the per-frame
259
+ // load, which is what keeps tall stacks from pumping energy.
260
+ this._backend.warmStart();
261
+ if (hasJoints) {
262
+ this._warmStartJoints();
263
+ }
264
+ // Main soft-bias velocity solve, integrate positions (accumulating
265
+ // per-body delta), then the bias-free relax pass. Joints solve right
266
+ // after the contacts in each pass (contacts are the stiffer constraint).
267
+ this._backend.solveVelocities(true);
268
+ if (hasJoints) {
269
+ this._solveJoints(true);
270
+ }
271
+ for (const body of this._bodies) {
272
+ body._integratePosition(h);
273
+ }
274
+ this._backend.solveVelocities(false);
275
+ if (hasJoints) {
276
+ this._solveJoints(false);
277
+ }
278
+ }
279
+ // Separate restitution pass, then write the accumulated delta into each
280
+ // body's transform and re-sync collider geometry.
281
+ this._backend.applyRestitution();
282
+ for (const body of this._bodies) {
283
+ body._finalizePosition();
284
+ }
285
+ if (hasBullets) {
286
+ this._advanceBullets();
287
+ }
104
288
  }
105
- this._backend.detect(this._colliders);
106
289
  this._dispatchEvents();
107
290
  }
108
291
  this._bindings.sync();
@@ -110,8 +293,8 @@ class PhysicsWorld {
110
293
  }
111
294
  // ── binding ────────────────────────────────────────────────────────────
112
295
  /** Link a body to a scene node; the node tracks the body after each step. */
113
- bind(body, node, options) {
114
- return this._bindings.bind(body, node, options);
296
+ bind(body, node) {
297
+ return this._bindings.bind(body, node);
115
298
  }
116
299
  /** Remove a body↔node link. */
117
300
  unbind(body) {
@@ -153,6 +336,7 @@ class PhysicsWorld {
153
336
  }
154
337
  this._bodies.length = 0;
155
338
  this._colliders.length = 0;
339
+ this._joints.length = 0;
156
340
  this._commands.length = 0;
157
341
  this._bindings.clear();
158
342
  this._backend.destroy();
@@ -194,6 +378,199 @@ class PhysicsWorld {
194
378
  }
195
379
  this._dispatching = false;
196
380
  }
381
+ /**
382
+ * Accumulate per-body sleep timers and put/keep islands of resting bodies
383
+ * asleep so a stack sleeps and wakes as one unit. An island is a connected
384
+ * component of dynamic bodies joined by touching solid contacts (static and
385
+ * kinematic bodies are boundaries, not nodes); it sleeps once every member has
386
+ * stayed below the sleep thresholds for `timeToSleep`, and wakes the instant
387
+ * any member does (e.g. an awake body merges into it via a new contact).
388
+ * Deterministic: union-find roots break ties by lower index and the contact
389
+ * set is id-sorted.
390
+ */
391
+ _updateSleeping(dt) {
392
+ const bodies = this._bodies;
393
+ const count = bodies.length;
394
+ const parent = this._islandParent;
395
+ const minSleep = this._islandMinSleep;
396
+ // Assign dense indices, reset the union-find, and accumulate sleep timers for
397
+ // awake dynamic bodies (a sleeping body's timer stays frozen ≥ timeToSleep).
398
+ for (let i = 0; i < count; i++) {
399
+ const body = bodies[i];
400
+ body._islandIndex = i;
401
+ parent[i] = i;
402
+ minSleep[i] = Infinity;
403
+ if (body.type === 'dynamic' && !body.isSleeping) {
404
+ body._accumulateSleepTime(dt, this.sleepLinearVelocity, this.sleepAngularVelocity);
405
+ }
406
+ }
407
+ parent.length = count;
408
+ minSleep.length = count;
409
+ // Union dynamic↔dynamic solid contacts into islands.
410
+ for (const contact of this._backend.contactGraph.solidContacts) {
411
+ const bodyA = contact.a.body;
412
+ const bodyB = contact.b.body;
413
+ if (bodyA.type === 'dynamic' && bodyB.type === 'dynamic') {
414
+ this._union(bodyA._islandIndex, bodyB._islandIndex);
415
+ }
416
+ }
417
+ // Joints couple their two bodies into the same island (sleep/wake together).
418
+ for (const joint of this._joints) {
419
+ const bodyA = joint.bodyA;
420
+ const bodyB = joint.bodyB;
421
+ if (joint.enabled && bodyA.type === 'dynamic' && bodyB.type === 'dynamic') {
422
+ this._union(bodyA._islandIndex, bodyB._islandIndex);
423
+ }
424
+ }
425
+ // Per-island minimum sleep time over its dynamic members.
426
+ for (let i = 0; i < count; i++) {
427
+ const body = bodies[i];
428
+ if (body.type === 'dynamic') {
429
+ const root = this._find(i);
430
+ if (body._sleepTime < minSleep[root]) {
431
+ minSleep[root] = body._sleepTime;
432
+ }
433
+ }
434
+ }
435
+ // Sleep an island iff every member has rested for `timeToSleep`; otherwise
436
+ // wake it (which also wakes any member dragged awake by a fresh contact).
437
+ const timeToSleep = this.timeToSleep;
438
+ for (let i = 0; i < count; i++) {
439
+ const body = bodies[i];
440
+ if (body.type === 'dynamic') {
441
+ body._setSleeping(minSleep[this._find(i)] >= timeToSleep);
442
+ }
443
+ }
444
+ }
445
+ /** Union-find union by lower index (deterministic roots). */
446
+ _union(a, b) {
447
+ const rootA = this._find(a);
448
+ const rootB = this._find(b);
449
+ if (rootA < rootB) {
450
+ this._islandParent[rootB] = rootA;
451
+ }
452
+ else if (rootB < rootA) {
453
+ this._islandParent[rootA] = rootB;
454
+ }
455
+ }
456
+ /** Union-find find with path halving. */
457
+ _find(index) {
458
+ const parent = this._islandParent;
459
+ while (parent[index] !== index) {
460
+ const grandparent = parent[parent[index]];
461
+ parent[index] = grandparent;
462
+ index = grandparent;
463
+ }
464
+ return index;
465
+ }
466
+ /** Build each joint's per-frame constraint data (once per fixed step). */
467
+ _prepareJoints(h) {
468
+ for (const joint of this._joints) {
469
+ joint._prepare(h);
470
+ }
471
+ }
472
+ /** Re-apply each joint's accumulated impulse (each sub-step). */
473
+ _warmStartJoints() {
474
+ for (const joint of this._joints) {
475
+ joint._warmStart();
476
+ }
477
+ }
478
+ /** One joint velocity pass (each sub-step, after the contacts). */
479
+ _solveJoints(useBias) {
480
+ for (const joint of this._joints) {
481
+ joint._solve(useBias);
482
+ }
483
+ }
484
+ /** Whether any dynamic body is flagged for continuous collision (bullet mode). */
485
+ _hasBullets() {
486
+ for (const body of this._bodies) {
487
+ if (body.isBullet && body.type === 'dynamic') {
488
+ return true;
489
+ }
490
+ }
491
+ return false;
492
+ }
493
+ /** Snapshot each bullet's centre of mass at the start of the fixed step (the swept-test origin). */
494
+ _recordBulletPositions() {
495
+ for (const body of this._bodies) {
496
+ if (body.isBullet && body.type === 'dynamic') {
497
+ body._ccdPrevX = body.worldCenterOfMassX;
498
+ body._ccdPrevY = body.worldCenterOfMassY;
499
+ }
500
+ }
501
+ }
502
+ /**
503
+ * Sweep each bullet's centre of mass along this fixed step's motion against every
504
+ * other body's colliders; if it would cross one, clamp the body just short of the
505
+ * surface and resolve the impact about the surface normal (a slide for a non-bouncy
506
+ * body, an elastic reflection as restitution → 1) so it cannot tunnel. Sweeps the
507
+ * centre point — good for small/point-like projectiles; a full swept-shape TOI for
508
+ * large fast bodies is backlog (raise sub-steps or thicken geometry meanwhile).
509
+ */
510
+ _advanceBullets() {
511
+ for (const body of this._bodies) {
512
+ if (!body.isBullet || body.type !== 'dynamic' || body.isSleeping) {
513
+ continue;
514
+ }
515
+ const newX = body.worldCenterOfMassX;
516
+ const newY = body.worldCenterOfMassY;
517
+ let dirX = newX - body._ccdPrevX;
518
+ let dirY = newY - body._ccdPrevY;
519
+ const distance = Math.hypot(dirX, dirY);
520
+ if (distance < 1e-6) {
521
+ continue;
522
+ }
523
+ dirX /= distance;
524
+ dirY /= distance;
525
+ this._ccdOrigin.x = body._ccdPrevX;
526
+ this._ccdOrigin.y = body._ccdPrevY;
527
+ this._ccdDir.x = dirX;
528
+ this._ccdDir.y = dirY;
529
+ const hits = this._query.rayCastAll(this._ccdOrigin, this._ccdDir, undefined, this._ccdHits, distance);
530
+ let blocked = null;
531
+ for (const hit of hits) {
532
+ // Sweep against every other body (static, kinematic, dynamic); sensors never
533
+ // block. Hits are distance-sorted, so the first match is the nearest surface.
534
+ if (hit.body !== body && !hit.collider.isSensor) {
535
+ blocked = hit;
536
+ break;
537
+ }
538
+ }
539
+ if (blocked === null) {
540
+ continue;
541
+ }
542
+ // Clamp the CoM just short of the surface (a pure translation — the rotation
543
+ // is already applied), then resolve the impact about the surface normal.
544
+ const clampDistance = Math.max(0, blocked.distance - ccdSkin);
545
+ const deltaX = body._ccdPrevX + dirX * clampDistance - newX;
546
+ const deltaY = body._ccdPrevY + dirY * clampDistance - newY;
547
+ this._ccdOrigin.x = body.x + deltaX;
548
+ this._ccdOrigin.y = body.y + deltaY;
549
+ body.setTransform(this._ccdOrigin, body.angle);
550
+ // Reflect about the true surface normal: a slide for a non-bouncy body
551
+ // (restitution 0), an elastic bounce as restitution → 1. The body's own
552
+ // restitution combines (max) with the surface's, matching the contact solver.
553
+ const nx = blocked.normal.x;
554
+ const ny = blocked.normal.y;
555
+ const vn = body.linearVelocityX * nx + body.linearVelocityY * ny;
556
+ if (vn < 0) {
557
+ const restitution = vn < -1 ? Math.max(this._bulletRestitution(body), blocked.collider.restitution) : 0;
558
+ const impulse = -(1 + restitution) * vn;
559
+ body.linearVelocityX += impulse * nx;
560
+ body.linearVelocityY += impulse * ny;
561
+ }
562
+ }
563
+ }
564
+ /** The highest restitution among a body's colliders (its CCD bounce factor). */
565
+ _bulletRestitution(body) {
566
+ let restitution = 0;
567
+ for (const collider of body.colliders) {
568
+ if (collider.restitution > restitution) {
569
+ restitution = collider.restitution;
570
+ }
571
+ }
572
+ return restitution;
573
+ }
197
574
  /** Run `command` now, or queue it when inside an event dispatch (deferred to end of step). */
198
575
  _defer(command) {
199
576
  if (this._dispatching) {
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicsWorld.js","sources":["../../../src/PhysicsWorld.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PhysicsWorld.js","sources":["../../../src/PhysicsWorld.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -11,9 +11,14 @@ import type { PhysicsBackend } from './PhysicsBackend';
11
11
  export declare class NativePhysicsBackend implements PhysicsBackend {
12
12
  readonly contactGraph: ContactGraph;
13
13
  private readonly _broadPhase;
14
+ private readonly _solver;
14
15
  private readonly _pairs;
15
16
  get candidatePairs(): readonly CandidatePair[];
16
17
  detect(colliders: readonly Collider[]): void;
18
+ prepareSolve(h: number, contactHertz: number, dampingRatio: number): void;
19
+ warmStart(): void;
20
+ solveVelocities(useBias: boolean): void;
21
+ applyRestitution(): void;
17
22
  removeCollider(collider: Collider): void;
18
23
  destroy(): void;
19
24
  }
@@ -1,5 +1,6 @@
1
1
  import { SweepAndPrune } from '../broadphase/SweepAndPrune.js';
2
2
  import { ContactGraph } from '../ContactGraph.js';
3
+ import { ContactSolver } from '../solver/ContactSolver.js';
3
4
 
4
5
  /**
5
6
  * The native, dependency-free backend: a {@link BroadPhase} (sweep-and-prune in
@@ -10,6 +11,7 @@ import { ContactGraph } from '../ContactGraph.js';
10
11
  class NativePhysicsBackend {
11
12
  contactGraph = new ContactGraph();
12
13
  _broadPhase = new SweepAndPrune();
14
+ _solver = new ContactSolver();
13
15
  _pairs = [];
14
16
  get candidatePairs() {
15
17
  return this._pairs;
@@ -18,6 +20,18 @@ class NativePhysicsBackend {
18
20
  this._broadPhase.computePairs(colliders, this._pairs);
19
21
  this.contactGraph.update(this._pairs);
20
22
  }
23
+ prepareSolve(h, contactHertz, dampingRatio) {
24
+ this._solver.prepare(this.contactGraph.solidContacts, h, contactHertz, dampingRatio);
25
+ }
26
+ warmStart() {
27
+ this._solver.warmStart();
28
+ }
29
+ solveVelocities(useBias) {
30
+ this._solver.solveVelocities(useBias);
31
+ }
32
+ applyRestitution() {
33
+ this._solver.applyRestitution();
34
+ }
21
35
  removeCollider(collider) {
22
36
  this.contactGraph.removeCollider(collider);
23
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NativePhysicsBackend.js","sources":["../../../../src/backend/NativePhysicsBackend.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAMA;;;;;AAKG;MACU,oBAAoB,CAAA;AACf,IAAA,YAAY,GAAG,IAAI,YAAY,EAAE;AAEhC,IAAA,WAAW,GAAe,IAAI,aAAa,EAAE;IAC7C,MAAM,GAAoB,EAAE;AAE7C,IAAA,IAAW,cAAc,GAAA;QACvB,OAAO,IAAI,CAAC,MAAM;IACpB;AAEO,IAAA,MAAM,CAAC,SAA8B,EAAA;QAC1C,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACrD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC;AAEO,IAAA,cAAc,CAAC,QAAkB,EAAA;AACtC,QAAA,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC;IAC5C;IAEO,OAAO,GAAA;AACZ,QAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;IACxB;AACD;;;;"}
1
+ {"version":3,"file":"NativePhysicsBackend.js","sources":["../../../../src/backend/NativePhysicsBackend.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAOA;;;;;AAKG;MACU,oBAAoB,CAAA;AACf,IAAA,YAAY,GAAG,IAAI,YAAY,EAAE;AAEhC,IAAA,WAAW,GAAe,IAAI,aAAa,EAAE;AAC7C,IAAA,OAAO,GAAG,IAAI,aAAa,EAAE;IAC7B,MAAM,GAAoB,EAAE;AAE7C,IAAA,IAAW,cAAc,GAAA;QACvB,OAAO,IAAI,CAAC,MAAM;IACpB;AAEO,IAAA,MAAM,CAAC,SAA8B,EAAA;QAC1C,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACrD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC;AAEO,IAAA,YAAY,CAAC,CAAS,EAAE,YAAoB,EAAE,YAAoB,EAAA;AACvE,QAAA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC;IACtF;IAEO,SAAS,GAAA;AACd,QAAA,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;IAC1B;AAEO,IAAA,eAAe,CAAC,OAAgB,EAAA;AACrC,QAAA,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC;IACvC;IAEO,gBAAgB,GAAA;AACrB,QAAA,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE;IACjC;AAEO,IAAA,cAAc,CAAC,QAAkB,EAAA;AACtC,QAAA,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC;IAC5C;IAEO,OAAO,GAAA;AACZ,QAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;IACxB;AACD;;;;"}