@flighthq/physics2d 0.3.0-edge.1458.0c01b63

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 (49) hide show
  1. package/dist/colliderTransform.d.ts +10 -0
  2. package/dist/colliderTransform.d.ts.map +1 -0
  3. package/dist/colliderTransform.js +137 -0
  4. package/dist/colliderTransform.js.map +1 -0
  5. package/dist/contract.d.ts +9 -0
  6. package/dist/contract.d.ts.map +1 -0
  7. package/dist/contract.js +9 -0
  8. package/dist/contract.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +9 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/islands.d.ts +38 -0
  14. package/dist/islands.d.ts.map +1 -0
  15. package/dist/islands.js +159 -0
  16. package/dist/islands.js.map +1 -0
  17. package/dist/jointRegistry.d.ts +6 -0
  18. package/dist/jointRegistry.d.ts.map +1 -0
  19. package/dist/jointRegistry.js +78 -0
  20. package/dist/jointRegistry.js.map +1 -0
  21. package/dist/joints.d.ts +39 -0
  22. package/dist/joints.d.ts.map +1 -0
  23. package/dist/joints.js +561 -0
  24. package/dist/joints.js.map +1 -0
  25. package/dist/massProperties.d.ts +4 -0
  26. package/dist/massProperties.d.ts.map +1 -0
  27. package/dist/massProperties.js +146 -0
  28. package/dist/massProperties.js.map +1 -0
  29. package/dist/solver.d.ts +7 -0
  30. package/dist/solver.d.ts.map +1 -0
  31. package/dist/solver.js +129 -0
  32. package/dist/solver.js.map +1 -0
  33. package/dist/step.d.ts +3 -0
  34. package/dist/step.d.ts.map +1 -0
  35. package/dist/step.js +414 -0
  36. package/dist/step.js.map +1 -0
  37. package/dist/world.d.ts +10 -0
  38. package/dist/world.d.ts.map +1 -0
  39. package/dist/world.js +133 -0
  40. package/dist/world.js.map +1 -0
  41. package/package.json +49 -0
  42. package/src/colliderTransform.test.ts +115 -0
  43. package/src/islands.test.ts +262 -0
  44. package/src/jointRegistry.test.ts +205 -0
  45. package/src/joints.test.ts +951 -0
  46. package/src/massProperties.test.ts +169 -0
  47. package/src/solver.test.ts +186 -0
  48. package/src/step.test.ts +745 -0
  49. package/src/world.test.ts +142 -0
package/dist/step.js ADDED
@@ -0,0 +1,414 @@
1
+ import { collideContactManifold, createCollisionContactManifold } from '@flighthq/collision/contract';
2
+ import { updatePhysics2DColliderWorldShape, writePhysics2DColliderBounds } from './colliderTransform';
3
+ import { isRigidBody2DPairAwake, updatePhysics2DSleep } from './islands';
4
+ import { relativeNormalVelocity, solvePhysics2DContactsOnce, warmStartPhysics2DContacts } from './solver';
5
+ import { findPhysics2DBody, isPhysics2DPairOrdered } from './world';
6
+ // Refreshes every collider's world shape and republishes its bounds to the broadphase index.
7
+ function updatePhysics2DBroadphase(world) {
8
+ for (const body of world.bodies) {
9
+ let minX = Infinity;
10
+ let minY = Infinity;
11
+ let maxX = -Infinity;
12
+ let maxY = -Infinity;
13
+ for (const collider of body.colliders) {
14
+ updatePhysics2DColliderWorldShape(collider, body);
15
+ writePhysics2DColliderBounds(collider, boundsScratch);
16
+ if (boundsScratch.minX < minX)
17
+ minX = boundsScratch.minX;
18
+ if (boundsScratch.minY < minY)
19
+ minY = boundsScratch.minY;
20
+ if (boundsScratch.maxX > maxX)
21
+ maxX = boundsScratch.maxX;
22
+ if (boundsScratch.maxY > maxY)
23
+ maxY = boundsScratch.maxY;
24
+ }
25
+ if (minX > maxX) {
26
+ // No collider produced bounds, so there is nothing to index. Withdraw rather than skip: the id
27
+ // may have been indexed on a previous step, and a stale AABB keeps generating pairs for a body
28
+ // this step has already decided not to collide.
29
+ world.index.removeSpatialObject(body.index);
30
+ continue;
31
+ }
32
+ // Bounds this package declines to hand to the broadphase — a physics judgement, kept as
33
+ // defence in depth rather than as a substitute for the index's own bound.
34
+ //
35
+ // `@flighthq/spatial` now bounds its own insert cost (non-finite bounds are declined with a
36
+ // sentinel, oversized ones go to a flat overflow list), so this is no longer what stands between a
37
+ // diverging body and a hung caller. What it still expresses is a rigid-body world's own opinion:
38
+ // a body that is non-finite, or ten million units across, has diverged by any measure this
39
+ // simulation cares about, and continuing to collide it wastes narrow-phase work on a result
40
+ // already meaningless. Skipping it stops that one body colliding and lets the rest of the world
41
+ // keep simulating.
42
+ //
43
+ // Keeping it also keeps the two packages honest about ownership: the cost bound is the index's,
44
+ // and this is a divergence filter that happens to share its shape.
45
+ if (!Number.isFinite(minX) ||
46
+ !Number.isFinite(minY) ||
47
+ !Number.isFinite(maxX) ||
48
+ !Number.isFinite(maxY) ||
49
+ maxX - minX > MAX_SIMULATED_EXTENT ||
50
+ maxY - minY > MAX_SIMULATED_EXTENT) {
51
+ // Withdraw the body from the index instead of merely skipping the update. Skipping left
52
+ // whatever AABB it had last step in place, so a body this filter had declared diverged went on
53
+ // producing broadphase pairs and holding live contacts from its last valid pose — the opposite
54
+ // of the "stops colliding" this comment claims. Removal is a no-op for an id never indexed.
55
+ world.index.removeSpatialObject(body.index);
56
+ continue;
57
+ }
58
+ bodyBounds.minX = minX;
59
+ bodyBounds.minY = minY;
60
+ bodyBounds.maxX = maxX;
61
+ bodyBounds.maxY = maxY;
62
+ world.index.updateSpatialObject(body.index, bodyBounds);
63
+ }
64
+ }
65
+ // Builds this step's contact set from the broadphase pairs, preserving each surviving contact's cached
66
+ // impulses.
67
+ //
68
+ // TWO ORDERINGS ARE ENFORCED HERE, and they are different obligations:
69
+ //
70
+ // 1. Each PAIR is ordered by body index before the narrow phase is called, because collision resolves
71
+ // contact points on the reference shape and ties toward its first argument. Reversed arguments move
72
+ // the points and renumber their feature ids, which discards the warm-start cache.
73
+ // 2. The contact LIST is sorted, because a sequential-impulse solver is order-dependent by
74
+ // construction — each impulse is applied against the velocities the previous ones left behind — and
75
+ // `querySpatialPairs` walks a Map of Sets, so its order follows insertion and movement history.
76
+ //
77
+ // Neither substitutes for the other: the first fixes contact identity, the second fixes solve order.
78
+ // A determinism harness that shuffles only insertion order would pass with the first one broken.
79
+ function buildPhysics2DContacts(world) {
80
+ world.index.querySpatialPairs(pairScratch);
81
+ world.events.began.length = 0;
82
+ world.events.ended.length = 0;
83
+ for (const contact of world.contacts)
84
+ contact.touching = false;
85
+ for (const pair of pairScratch) {
86
+ const first = findPhysics2DBody(world, pair.a);
87
+ const second = findPhysics2DBody(world, pair.b);
88
+ if (first === null || second === null)
89
+ continue;
90
+ // Two bodies that cannot both move have no constraint to SOLVE, and skipping them keeps the
91
+ // solver's body list free of pairs whose every impulse would be multiplied by zero. But a sensor
92
+ // is reported, never resolved — the solver already skips sensor contacts — so applying this test
93
+ // before any collider is inspected silently deleted every sensor overlap between two immovable
94
+ // bodies. A static trigger volume over static scenery is an ordinary thing to build, and it
95
+ // reported nothing at all. Immovable pairs are still skipped, unless one of them senses.
96
+ const bothImmovable = first.inverseMass === 0 && second.inverseMass === 0;
97
+ if (bothImmovable && !hasSensorCollider(first) && !hasSensorCollider(second)) {
98
+ continue;
99
+ }
100
+ // A jointed pair almost always overlaps at the anchor, and resolving that contact fights the
101
+ // constraint holding them together, so a joint suppresses it unless the caller asks otherwise.
102
+ if (isPhysics2DPairJointSuppressed(world, first.index, second.index))
103
+ continue;
104
+ const ordered = isPhysics2DPairOrdered(first, second);
105
+ const bodyA = ordered ? first : second;
106
+ const bodyB = ordered ? second : first;
107
+ for (let i = 0; i < bodyA.colliders.length; i++) {
108
+ for (let j = 0; j < bodyB.colliders.length; j++) {
109
+ const colliderA = bodyA.colliders[i];
110
+ const colliderB = bodyB.colliders[j];
111
+ const sensorPair = colliderA.sensor || colliderB.sensor;
112
+ // The immovable test belongs here, not on the bodies. Owning one sensor anywhere does not make
113
+ // a body's other colliders reportable: a static body carrying a trigger volume plus ordinary
114
+ // scenery would otherwise emit solid-vs-solid contacts against other static scenery, which
115
+ // nothing can ever resolve. Sensors are reported and never resolved, so a sensor pair is the
116
+ // only pair worth keeping between two bodies that cannot move.
117
+ if (bothImmovable && !sensorPair)
118
+ continue;
119
+ if (!collideContactManifold(colliderA.world, colliderB.world, manifoldScratch))
120
+ continue;
121
+ mergePhysics2DContact(world, bodyA.index, bodyB.index, i, j, manifoldScratch, sensorPair, (colliderA.material.friction + colliderB.material.friction) / 2, Math.max(colliderA.material.restitution, colliderB.material.restitution));
122
+ }
123
+ }
124
+ }
125
+ // Contact events are read off the cache's own transitions rather than tracked beside it: the cache
126
+ // already knows which pairs are touching, so a pair gaining an entry IS the begin and losing one IS the
127
+ // end. An ended contact is reported for the step it leaves, then dropped.
128
+ for (let i = world.contacts.length - 1; i >= 0; i--) {
129
+ const contact = world.contacts[i];
130
+ if (!contact.touching) {
131
+ world.events.ended.push(contact);
132
+ world.contacts.splice(i, 1);
133
+ }
134
+ }
135
+ world.contacts.sort(comparePhysics2DContacts);
136
+ }
137
+ // Writes this step's manifold into the persistent contact for the pair, creating it if new, and carries
138
+ // each point's converged impulses across by FEATURE ID rather than by slot. Matching by slot would hand
139
+ // a point the impulse of whatever happened to occupy that array position last step, which is a different
140
+ // contact feature the moment the manifold's point count or order changes.
141
+ function mergePhysics2DContact(world, bodyA, bodyB, colliderA, colliderB, manifold, sensor, friction, restitution) {
142
+ let contact = null;
143
+ let created = false;
144
+ for (const existing of world.contacts) {
145
+ if (existing.bodyA === bodyA &&
146
+ existing.bodyB === bodyB &&
147
+ existing.colliderA === colliderA &&
148
+ existing.colliderB === colliderB) {
149
+ contact = existing;
150
+ break;
151
+ }
152
+ }
153
+ if (contact === null) {
154
+ created = true;
155
+ contact = {
156
+ bodyA,
157
+ bodyB,
158
+ colliderA,
159
+ colliderB,
160
+ normalX: 0,
161
+ normalY: 0,
162
+ pointCount: 0,
163
+ points: [createPhysics2DContactPoint(), createPhysics2DContactPoint()],
164
+ friction,
165
+ restitution,
166
+ sensor,
167
+ touching: true,
168
+ };
169
+ world.contacts.push(contact);
170
+ }
171
+ if (created)
172
+ world.events.began.push(contact);
173
+ contact.normalX = manifold.normalX;
174
+ contact.normalY = manifold.normalY;
175
+ contact.friction = friction;
176
+ contact.restitution = restitution;
177
+ contact.sensor = sensor;
178
+ contact.touching = true;
179
+ for (let i = 0; i < manifold.pointCount; i++) {
180
+ const source = manifold.points[i];
181
+ const target = contact.points[i];
182
+ let normalImpulse = 0;
183
+ let tangentImpulse = 0;
184
+ for (let j = 0; j < contact.pointCount; j++) {
185
+ if (contact.points[j].featureId === source.featureId) {
186
+ normalImpulse = contact.points[j].normalImpulse;
187
+ tangentImpulse = contact.points[j].tangentImpulse;
188
+ break;
189
+ }
190
+ }
191
+ target.x = source.x;
192
+ target.y = source.y;
193
+ target.depth = source.depth;
194
+ target.featureId = source.featureId;
195
+ target.normalImpulse = normalImpulse;
196
+ target.tangentImpulse = tangentImpulse;
197
+ }
198
+ contact.pointCount = manifold.pointCount;
199
+ }
200
+ // Rebuilds every contact's lever arms, effective masses, and velocity bias for this step's geometry.
201
+ // These are recomputed rather than cached because they depend on the bodies' current positions, which
202
+ // the previous step moved.
203
+ function preparePhysics2DConstraints(world, dt) {
204
+ const config = world.config;
205
+ for (const contact of world.contacts) {
206
+ if (contact.sensor)
207
+ continue;
208
+ const bodyA = findPhysics2DBody(world, contact.bodyA);
209
+ const bodyB = findPhysics2DBody(world, contact.bodyB);
210
+ if (bodyA === null || bodyB === null)
211
+ continue;
212
+ const centerAX = bodyA.x + bodyA.centerX * Math.cos(bodyA.angle) - bodyA.centerY * Math.sin(bodyA.angle);
213
+ const centerAY = bodyA.y + bodyA.centerX * Math.sin(bodyA.angle) + bodyA.centerY * Math.cos(bodyA.angle);
214
+ const centerBX = bodyB.x + bodyB.centerX * Math.cos(bodyB.angle) - bodyB.centerY * Math.sin(bodyB.angle);
215
+ const centerBY = bodyB.y + bodyB.centerX * Math.sin(bodyB.angle) + bodyB.centerY * Math.cos(bodyB.angle);
216
+ const normalX = contact.normalX;
217
+ const normalY = contact.normalY;
218
+ const tangentX = -normalY;
219
+ const tangentY = normalX;
220
+ for (let i = 0; i < contact.pointCount; i++) {
221
+ const point = contact.points[i];
222
+ point.rAX = point.x - centerAX;
223
+ point.rAY = point.y - centerAY;
224
+ point.rBX = point.x - centerBX;
225
+ point.rBY = point.y - centerBY;
226
+ point.normalMass = effectiveMass(bodyA, bodyB, point.rAX, point.rAY, point.rBX, point.rBY, normalX, normalY);
227
+ point.tangentMass = effectiveMass(bodyA, bodyB, point.rAX, point.rAY, point.rBX, point.rBY, tangentX, tangentY);
228
+ // Penetration recovery, softened by a slop the solver deliberately leaves unresolved so a resting
229
+ // contact is not fighting a target of exactly zero overlap every step.
230
+ const excess = point.depth - config.penetrationSlop;
231
+ point.bias = excess > 0 ? -(config.positionCorrection / dt) * excess : 0;
232
+ // Restitution is dropped below a threshold approach speed. Without that, a ball bounces forever at
233
+ // ever smaller amplitudes and never comes to rest.
234
+ const approach = relativeNormalVelocity(bodyA, bodyB, point, normalX, normalY);
235
+ if (approach < -config.restitutionThreshold)
236
+ point.bias += contact.restitution * approach;
237
+ }
238
+ }
239
+ }
240
+ // The constraint's effective mass along `axis`: the inverse of how much the pair's velocity at the
241
+ // contact point changes per unit impulse. The angular terms are the lever arm crossed with the axis,
242
+ // which is the entire reason a contact point can produce torque — with only a minimum-translation vector
243
+ // and no point, both terms vanish and a box slides down a slope without ever tipping.
244
+ function effectiveMass(bodyA, bodyB, rAX, rAY, rBX, rBY, axisX, axisY) {
245
+ const crossA = rAX * axisY - rAY * axisX;
246
+ const crossB = rBX * axisY - rBY * axisX;
247
+ const total = bodyA.inverseMass +
248
+ bodyB.inverseMass +
249
+ bodyA.inverseInertia * crossA * crossA +
250
+ bodyB.inverseInertia * crossB * crossB;
251
+ return total > 0 ? 1 / total : 0;
252
+ }
253
+ // Advances the simulation by `dt` seconds. Everything the step does, it does because the caller asked:
254
+ // there is no implicit accumulation, no fixed-timestep loop hidden inside, and no allocation once the
255
+ // world's bodies and contacts exist.
256
+ //
257
+ // The order of the phases is not arbitrary. World shapes must be current before the broadphase sees
258
+ // their bounds; the contact set must be built before impulses can warm-start from it; velocities are
259
+ // solved before positions are integrated, so the integration moves bodies that have already had their
260
+ // constraints applied rather than moving them and correcting afterwards.
261
+ export function stepPhysics2D(world, dt) {
262
+ if (!(dt > 0))
263
+ return;
264
+ updatePhysics2DBroadphase(world);
265
+ buildPhysics2DContacts(world);
266
+ const bodies = world.bodies;
267
+ const config = world.config;
268
+ // Sleep is decided HERE — after the contact set is current, before anything integrates. The placement
269
+ // is what makes every wake transition cost zero steps. A body woken by a force, by a new neighbour, or
270
+ // by the caller writing a velocity is awake in time to be integrated by this same step; deciding after
271
+ // integration instead would skip it once and move it a step late.
272
+ updatePhysics2DSleep(world, dt);
273
+ for (const body of bodies) {
274
+ if (body.type !== 'dynamic' || body.sleeping)
275
+ continue;
276
+ body.velocityX += (body.forceX * body.inverseMass + world.gravityX * body.gravityScale) * dt;
277
+ body.velocityY += (body.forceY * body.inverseMass + world.gravityY * body.gravityScale) * dt;
278
+ body.angularVelocity += body.torque * body.inverseInertia * dt;
279
+ // Damping is applied as a multiplicative decay rather than a subtracted force so it stays stable at
280
+ // any timestep: a force-shaped damping term large enough to matter can reverse the velocity it is
281
+ // damping when dt is big.
282
+ body.velocityX /= 1 + body.linearDamping * dt;
283
+ body.velocityY /= 1 + body.linearDamping * dt;
284
+ body.angularVelocity /= 1 + body.angularDamping * dt;
285
+ }
286
+ preparePhysics2DConstraints(world, dt);
287
+ for (const joint of world.joints) {
288
+ if (!isPhysics2DJointAwake(world, joint))
289
+ continue;
290
+ world.jointSolvers.get(joint.kind)?.prepare(world, joint, dt);
291
+ }
292
+ // Joints warm-start alongside contacts, which is what the impulse block on Physics2DJoint has always
293
+ // been documented to be for. Each kind reapplies its own converged impulse, because the block is
294
+ // deliberately untyped and only the kind knows what its numbers mean. With warm starting off the
295
+ // accumulators are cleared instead, so a world told not to use the cache does not quietly keep
296
+ // seeding from it — the previous code left them growing whether the flag was set or not.
297
+ if (config.warmStarting)
298
+ warmStartPhysics2DContacts(world);
299
+ // Warm starting is decided per KIND as well as per world, because it is a capability and not just a
300
+ // preference. A kind that declares no warmStart is never reapplying its accumulator — the mouse joint
301
+ // omits it deliberately, since a target that moves between steps invalidates the previous impulse —
302
+ // so that accumulator has to be cleared even when the world is warm starting. Keying only on the
303
+ // world flag left the mouse's stale impulse live: after zeroing a body's velocity and moving the
304
+ // target onto it, the next step still produced motion, contradicting the cold-start contract on the
305
+ // type. An impulse that is never reapplied must be cleared, or it is neither warm nor cold.
306
+ for (const joint of world.joints) {
307
+ const solver = world.jointSolvers.get(joint.kind);
308
+ if (solver === undefined)
309
+ continue;
310
+ // A joint between two sleeping ends must not warm-start: reapplying its impulse hands a sleeper
311
+ // velocity it will never integrate, and the next step's stillness test reads that as motion.
312
+ if (!isPhysics2DJointAwake(world, joint))
313
+ continue;
314
+ if (config.warmStarting && solver.warmStart !== undefined) {
315
+ solver.warmStart(world, joint);
316
+ }
317
+ else {
318
+ solver.clearAccumulatedImpulses?.(joint);
319
+ }
320
+ }
321
+ // Joints and contacts share one solve list and one iteration count. Solving them in separate passes
322
+ // would let each undo the other's correction — a hinge under load creeps if the contacts beneath it get
323
+ // a whole pass to themselves between joint iterations.
324
+ for (let iteration = 0; iteration < config.velocityIterations; iteration++) {
325
+ for (const joint of world.joints) {
326
+ if (!isPhysics2DJointAwake(world, joint))
327
+ continue;
328
+ world.jointSolvers.get(joint.kind)?.solve(world, joint);
329
+ }
330
+ solvePhysics2DContactsOnce(world);
331
+ }
332
+ // The sleeping skip here is a COST saving, not a behavioural one, and the distinction is worth having
333
+ // in writing: a sleeping body's velocity is zeroed when it falls asleep and nothing can hand it more
334
+ // (any awake neighbour puts it in an awake island before this point), so integrating it would move it
335
+ // by exactly zero. What the skip buys is that a settled thousand-body pile costs no integration work
336
+ // at all, which is the entire reason sleep exists. Removing it changes no observable result.
337
+ for (const body of bodies) {
338
+ if (body.type === 'static' || body.sleeping)
339
+ continue;
340
+ body.x += body.velocityX * dt;
341
+ body.y += body.velocityY * dt;
342
+ body.angle += body.angularVelocity * dt;
343
+ }
344
+ for (const body of bodies) {
345
+ body.forceX = 0;
346
+ body.forceY = 0;
347
+ body.torque = 0;
348
+ }
349
+ }
350
+ function createPhysics2DContactPoint() {
351
+ return {
352
+ x: 0,
353
+ y: 0,
354
+ depth: 0,
355
+ featureId: 0,
356
+ rAX: 0,
357
+ rAY: 0,
358
+ rBX: 0,
359
+ rBY: 0,
360
+ normalImpulse: 0,
361
+ tangentImpulse: 0,
362
+ normalMass: 0,
363
+ tangentMass: 0,
364
+ bias: 0,
365
+ };
366
+ }
367
+ // Whether a joint still has an end the solver can move. Mirrors the contact-side test in the solver:
368
+ // two sleeping ends, or a sleeper anchored to static scenery, constrain nothing this step.
369
+ function isPhysics2DJointAwake(world, joint) {
370
+ const bodyA = findPhysics2DBody(world, joint.bodyA);
371
+ const bodyB = findPhysics2DBody(world, joint.bodyB);
372
+ if (bodyA === null || bodyB === null)
373
+ return false;
374
+ return isRigidBody2DPairAwake(bodyA, bodyB);
375
+ }
376
+ // Whether any of the body's colliders senses rather than collides. Cheap enough to ask per pair: a
377
+ // body carries a handful of colliders, and the alternative is inspecting every collider pairing.
378
+ function hasSensorCollider(body) {
379
+ for (const collider of body.colliders) {
380
+ if (collider.sensor)
381
+ return true;
382
+ }
383
+ return false;
384
+ }
385
+ // Total order over contacts, by the four identities that define one. Every field is a persistent index,
386
+ // so the order is stable across steps and independent of the broadphase's history.
387
+ function comparePhysics2DContacts(left, right) {
388
+ if (left.bodyA !== right.bodyA)
389
+ return left.bodyA - right.bodyA;
390
+ if (left.bodyB !== right.bodyB)
391
+ return left.bodyB - right.bodyB;
392
+ if (left.colliderA !== right.colliderA)
393
+ return left.colliderA - right.colliderA;
394
+ return left.colliderB - right.colliderB;
395
+ }
396
+ // The widest body this world still treats as simulating. Named for what it bounds — the simulation's
397
+ // tolerance for divergence — not for the index, which bounds its own insert cost independently.
398
+ const MAX_SIMULATED_EXTENT = 1e7;
399
+ const boundsScratch = { minX: 0, minY: 0, maxX: 0, maxY: 0 };
400
+ const bodyBounds = { minX: 0, minY: 0, maxX: 0, maxY: 0 };
401
+ const pairScratch = [];
402
+ const manifoldScratch = createCollisionContactManifold();
403
+ // Whether a joint between these two bodies suppresses their contact.
404
+ function isPhysics2DPairJointSuppressed(world, first, second) {
405
+ for (const joint of world.joints) {
406
+ if (joint.collideConnected)
407
+ continue;
408
+ if ((joint.bodyA === first && joint.bodyB === second) || (joint.bodyA === second && joint.bodyB === first)) {
409
+ return true;
410
+ }
411
+ }
412
+ return false;
413
+ }
414
+ //# sourceMappingURL=step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CollisionShape, Physics2DCollider, Physics2DMaterial, Physics2DSolverConfig, Physics2DWorld, RigidBody2D, SpatialIndexBackend } from '@flighthq/types/contract';
2
+ export declare function addPhysics2DBody(world: Physics2DWorld, body: RigidBody2D): RigidBody2D;
3
+ export declare function createPhysics2DCollider(local: CollisionShape, material: Physics2DMaterial, sensor?: boolean): Physics2DCollider;
4
+ export declare function createPhysics2DSolverConfig(): Physics2DSolverConfig;
5
+ export declare function createPhysics2DWorld(gravityX?: number, gravityY?: number, index?: SpatialIndexBackend): Physics2DWorld;
6
+ export declare function createRigidBody2D(type: RigidBody2D['type'], x: number, y: number, angle?: number): RigidBody2D;
7
+ export declare function findPhysics2DBody(world: Readonly<Physics2DWorld>, index: number): RigidBody2D | null;
8
+ export declare function isPhysics2DPairOrdered(a: Readonly<RigidBody2D>, b: Readonly<RigidBody2D>): boolean;
9
+ export declare function removePhysics2DBody(world: Physics2DWorld, body: Readonly<RigidBody2D>): boolean;
10
+ //# sourceMappingURL=world.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AASlC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW,CAKtF;AAID,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,UAAQ,GACb,iBAAiB,CAEnB;AAMD,wBAAgB,2BAA2B,IAAI,qBAAqB,CAcnE;AAKD,wBAAgB,oBAAoB,CAAC,QAAQ,SAAI,EAAE,QAAQ,SAAQ,EAAE,KAAK,CAAC,EAAE,mBAAmB,GAAG,cAAc,CAahH;AAKD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,WAAW,CA0BzG;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKpG;AAcD,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAElG;AAKD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAgB/F"}
package/dist/world.js ADDED
@@ -0,0 +1,133 @@
1
+ import { createUniformGridSpatialBackend } from '@flighthq/spatial/contract';
2
+ import { createPhysics2DColliderWorldShape } from './colliderTransform';
3
+ import { updateRigidBody2DMassData } from './massProperties';
4
+ // Adds `body` to `world`, assigning it the persistent index every contact is keyed and ordered by, and
5
+ // returns it. The index comes from a monotonic counter rather than the array position, so removing a
6
+ // body can never hand its identity to a later one — a stale contact would otherwise be revived against
7
+ // whichever body inherited the slot, warm-starting it with a force that belonged to something else.
8
+ export function addPhysics2DBody(world, body) {
9
+ body.index = world.nextBodyIndex++;
10
+ world.bodies.push(body);
11
+ updateRigidBody2DMassData(body);
12
+ return body;
13
+ }
14
+ // Creates a collider from a LOCAL-space shape, allocating the world-space shape it will be transformed
15
+ // into. Both shapes exist for the collider's lifetime; the step rewrites the world one in place.
16
+ export function createPhysics2DCollider(local, material, sensor = false) {
17
+ return { local, world: createPhysics2DColliderWorldShape(local), material, sensor };
18
+ }
19
+ // The default solver tuning. Ten velocity iterations and three position iterations is the range every
20
+ // sequential-impulse engine converges on for game-scale stacks; the slop and correction factor are what
21
+ // stop a resting contact from either twitching against a target of exactly zero overlap or exploding
22
+ // outward when a deep overlap is corrected all at once.
23
+ export function createPhysics2DSolverConfig() {
24
+ return {
25
+ // Box2D's long-standing defaults: still below 0.01 m/s and 2 deg/s, asleep after half a second.
26
+ allowSleeping: true,
27
+ sleepLinearThreshold: 0.01,
28
+ sleepAngularThreshold: (2 * Math.PI) / 180,
29
+ timeToSleep: 0.5,
30
+ velocityIterations: 10,
31
+ positionIterations: 3,
32
+ penetrationSlop: 0.005,
33
+ positionCorrection: 0.2,
34
+ restitutionThreshold: 1,
35
+ warmStarting: true,
36
+ };
37
+ }
38
+ // Creates an empty world. `index` defaults to a uniform grid; pass one to swap the broadphase structure
39
+ // without this package knowing which it got — `SpatialIndexBackend` is already that seam, so physics
40
+ // adds no second one over it.
41
+ export function createPhysics2DWorld(gravityX = 0, gravityY = -9.81, index) {
42
+ return {
43
+ bodies: [],
44
+ contacts: [],
45
+ joints: [],
46
+ jointSolvers: new Map(),
47
+ events: { began: [], ended: [] },
48
+ index: index ?? createUniformGridSpatialBackend(1),
49
+ config: createPhysics2DSolverConfig(),
50
+ gravityX,
51
+ gravityY,
52
+ nextBodyIndex: 0,
53
+ };
54
+ }
55
+ // Creates a rigid body at rest. Mass properties stay zero until the body is added to a world, which
56
+ // derives them from the colliders — a body's mass is never assigned, only derived, so it cannot
57
+ // disagree with its shape.
58
+ export function createRigidBody2D(type, x, y, angle = 0) {
59
+ return {
60
+ index: -1,
61
+ type,
62
+ x,
63
+ y,
64
+ angle,
65
+ velocityX: 0,
66
+ velocityY: 0,
67
+ angularVelocity: 0,
68
+ forceX: 0,
69
+ forceY: 0,
70
+ torque: 0,
71
+ mass: 0,
72
+ inverseMass: 0,
73
+ inertia: 0,
74
+ inverseInertia: 0,
75
+ centerX: 0,
76
+ centerY: 0,
77
+ linearDamping: 0,
78
+ angularDamping: 0,
79
+ gravityScale: 1,
80
+ sleeping: false,
81
+ sleepTimer: 0,
82
+ colliders: [],
83
+ };
84
+ }
85
+ // The body carrying `index`, or null when the world no longer holds it. Contacts store body indices
86
+ // rather than references so a contact can outlive one step without pinning a removed body alive; this is
87
+ // the lookup that turns one back into the other.
88
+ export function findPhysics2DBody(world, index) {
89
+ for (const body of world.bodies) {
90
+ if (body.index === index)
91
+ return body;
92
+ }
93
+ return null;
94
+ }
95
+ // The canonical order of a body pair: lower index first. Every contact in the world is created through
96
+ // this, which is what discharges the ordering obligation `@flighthq/collision` cannot.
97
+ //
98
+ // Collision resolves contact points on the reference shape's surface and, for two shapes of the same
99
+ // kind, ties toward its first argument — so passing a pair the other way round moves the points to the
100
+ // opposite surface and renumbers their feature ids. Broadphase pair order follows insertion and movement
101
+ // history, so without a canonical order the warm-start cache silently resets whenever a body is added
102
+ // mid-simulation. The order has to come from persistent identity rather than geometry, because any order
103
+ // derived from coordinates flips the moment those coordinates cross.
104
+ //
105
+ // It returns a boolean rather than sorting in place so the caller keeps both the ordered pair and the
106
+ // knowledge of whether it was reversed, which the collider indices must follow.
107
+ export function isPhysics2DPairOrdered(a, b) {
108
+ return a.index <= b.index;
109
+ }
110
+ // Removes `body` from `world`, along with every contact naming it. Contacts are dropped rather than
111
+ // kept, because a contact whose body is gone has no constraint to solve and its cached impulse belongs
112
+ // to a pair that no longer exists.
113
+ export function removePhysics2DBody(world, body) {
114
+ const at = world.bodies.indexOf(body);
115
+ if (at < 0)
116
+ return false;
117
+ world.bodies.splice(at, 1);
118
+ world.index.removeSpatialObject(body.index);
119
+ for (let i = world.contacts.length - 1; i >= 0; i--) {
120
+ const contact = world.contacts[i];
121
+ if (contact.bodyA === body.index || contact.bodyB === body.index)
122
+ world.contacts.splice(i, 1);
123
+ }
124
+ // Joints naming the removed body go with it: a constraint with one end missing has nothing to solve
125
+ // against, and leaving it would let a later body inheriting the index be silently constrained by it.
126
+ for (let i = world.joints.length - 1; i >= 0; i--) {
127
+ const joint = world.joints[i];
128
+ if (joint.bodyA === body.index || joint.bodyB === body.index)
129
+ world.joints.splice(i, 1);
130
+ }
131
+ return true;
132
+ }
133
+ //# sourceMappingURL=world.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world.js","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@flighthq/physics2d",
3
+ "version": "0.3.0-edge.1458.0c01b63",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/flighthq/flight.git",
7
+ "directory": "packages/physics2d"
8
+ },
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "./contract": {
18
+ "types": "./dist/contract.d.ts",
19
+ "default": "./dist/contract.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "src/**/*.test.ts",
25
+ "!dist/**/*.test.js",
26
+ "!dist/**/*.test.d.ts",
27
+ "!dist/**/*.test.js.map",
28
+ "!dist/**/*.test.d.ts.map"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsc -b",
32
+ "clean": "tsc -b --clean",
33
+ "test": "vitest run --config vitest.config.ts",
34
+ "test:watch": "vitest --watch --config vitest.config.ts",
35
+ "prepack": "npm run clean && npm run clean:dist && npm run build",
36
+ "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
37
+ },
38
+ "dependencies": {
39
+ "@flighthq/collision": "0.3.0-edge.1458.0c01b63",
40
+ "@flighthq/math": "0.3.0-edge.1458.0c01b63",
41
+ "@flighthq/spatial": "0.3.0-edge.1458.0c01b63",
42
+ "@flighthq/types": "0.3.0-edge.1458.0c01b63"
43
+ },
44
+ "devDependencies": {
45
+ "typescript": "^5.3.0"
46
+ },
47
+ "description": "2D rigid-body dynamics — deterministic sequential-impulse solver over collision manifolds and a spatial broadphase, with explicit stepping and no hidden per-frame allocation",
48
+ "sideEffects": false
49
+ }