@codexo/exojs-physics 0.13.0 → 0.14.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 (48) 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 +113 -15
  9. package/dist/esm/PhysicsBody.js +224 -21
  10. package/dist/esm/PhysicsBody.js.map +1 -1
  11. package/dist/esm/PhysicsWorld.d.ts +107 -35
  12. package/dist/esm/PhysicsWorld.js +136 -31
  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/PhysicsBinding.d.ts +6 -6
  19. package/dist/esm/binding/PhysicsBinding.js +8 -5
  20. package/dist/esm/binding/PhysicsBinding.js.map +1 -1
  21. package/dist/esm/broadphase/SweepAndPrune.d.ts +1 -0
  22. package/dist/esm/broadphase/SweepAndPrune.js +32 -3
  23. package/dist/esm/broadphase/SweepAndPrune.js.map +1 -1
  24. package/dist/esm/collision/CollisionProxy.d.ts +2 -2
  25. package/dist/esm/collision/narrowphase.js +91 -38
  26. package/dist/esm/collision/narrowphase.js.map +1 -1
  27. package/dist/esm/debug/PhysicsDebugDraw.d.ts +2 -1
  28. package/dist/esm/debug/PhysicsDebugDraw.js +2 -1
  29. package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
  30. package/dist/esm/physicsBuildInfo.js +2 -2
  31. package/dist/esm/public.d.ts +2 -1
  32. package/dist/esm/query/QueryEngine.d.ts +2 -2
  33. package/dist/esm/query/QueryEngine.js +13 -4
  34. package/dist/esm/query/QueryEngine.js.map +1 -1
  35. package/dist/esm/shapes/AnyShape.d.ts +9 -0
  36. package/dist/esm/shapes/CircleShape.d.ts +1 -2
  37. package/dist/esm/shapes/CircleShape.js.map +1 -1
  38. package/dist/esm/shapes/PolygonShape.d.ts +1 -2
  39. package/dist/esm/shapes/PolygonShape.js +45 -17
  40. package/dist/esm/shapes/PolygonShape.js.map +1 -1
  41. package/dist/esm/shapes/index.d.ts +1 -0
  42. package/dist/esm/solver/ContactSolver.d.ts +87 -0
  43. package/dist/esm/solver/ContactSolver.js +483 -0
  44. package/dist/esm/solver/ContactSolver.js.map +1 -0
  45. package/dist/esm/sort.d.ts +17 -0
  46. package/dist/esm/sort.js +54 -0
  47. package/dist/esm/sort.js.map +1 -0
  48. package/package.json +4 -4
@@ -10,14 +10,16 @@ export interface BodyOptions {
10
10
  position?: VectorLike;
11
11
  /** Initial rotation in radians. Default `0`. */
12
12
  angle?: number;
13
- /** Linear damping (applied once dynamics ship). Default `0`. */
13
+ /** Linear damping applied to the velocity each sub-step. Default `0`. */
14
14
  linearDamping?: number;
15
- /** Angular damping (applied once dynamics ship). Default `0`. */
15
+ /** Angular damping applied to the angular velocity each sub-step. Default `0`. */
16
16
  angularDamping?: number;
17
- /** Per-body multiplier on world gravity (applied once dynamics ship). Default `1`. */
17
+ /** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). Default `1`. */
18
18
  gravityScale?: number;
19
19
  /** When `true`, the body never rotates under contacts (infinite rotational inertia). Default `false`. */
20
20
  fixedRotation?: boolean;
21
+ /** Colliders to attach up-front. Each may be a {@link Collider} instance or its {@link ColliderOptions}. */
22
+ colliders?: Array<Collider | ColliderOptions>;
21
23
  }
22
24
  /**
23
25
  * Internal hook the world hands to each body so colliders can be id-allocated
@@ -29,19 +31,20 @@ export interface BodyOwner {
29
31
  }
30
32
  /**
31
33
  * A rigid body: a world transform plus mass properties aggregated from its
32
- * colliders. In this collision/query release a body holds and reports its
33
- * transform and mass but is not integrated it moves only via
34
- * {@link setTransform} (game-driven / kinematic). Forces, impulses and gravity
35
- * integration arrive with the dynamics solver.
34
+ * colliders. Dynamic bodies integrate under gravity, accumulated forces/torque
35
+ * and contact impulses each fixed sub-step; static bodies never move; kinematic
36
+ * bodies move by their velocity only and stay immovable under contacts. Drive a
37
+ * body with {@link applyForce}, {@link applyTorque} and {@link applyImpulse}, or
38
+ * set {@link linearVelocityX}/{@link linearVelocityY}/{@link angularVelocity}
39
+ * directly; reposition it (teleport, no velocity) with {@link setTransform}.
36
40
  */
37
41
  export declare class PhysicsBody {
38
- readonly id: number;
39
42
  readonly type: BodyType;
40
- /** Linear damping (inert until dynamics ship). */
43
+ /** Linear damping applied to the velocity each sub-step. */
41
44
  linearDamping: number;
42
- /** Angular damping (inert until dynamics ship). */
45
+ /** Angular damping applied to the angular velocity each sub-step. */
43
46
  angularDamping: number;
44
- /** Per-body gravity multiplier (inert until dynamics ship). */
47
+ /** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). */
45
48
  gravityScale: number;
46
49
  /** When `true`, rotational inertia is treated as infinite. */
47
50
  fixedRotation: boolean;
@@ -53,14 +56,39 @@ export declare class PhysicsBody {
53
56
  inertia: number;
54
57
  /** Inverse rotational inertia (`0` = no angular response). */
55
58
  invInertia: number;
56
- private readonly _owner;
59
+ /** Linear velocity X in px/s. */
60
+ linearVelocityX: number;
61
+ /** Linear velocity Y in px/s. */
62
+ linearVelocityY: number;
63
+ /** Angular velocity in rad/s. */
64
+ angularVelocity: number;
65
+ /** @internal — Delta position X accumulated across the frame's sub-steps by the TGS integrator; written into the transform once per frame by {@link _finalizePosition}. */
66
+ _deltaPosX: number;
67
+ /** @internal — Delta position Y accumulated across the frame's sub-steps by the TGS integrator. */
68
+ _deltaPosY: number;
69
+ /** @internal — Delta rotation (radians) accumulated across the frame's sub-steps by the TGS integrator. */
70
+ _deltaAngle: number;
71
+ /** @internal — `cos(_deltaAngle)`, cached so the solver can rotate the contact anchors by the live sub-step rotation without a per-contact trig call. */
72
+ _deltaCos: number;
73
+ /** @internal — `sin(_deltaAngle)`, cached alongside {@link _deltaCos}. */
74
+ _deltaSin: number;
75
+ private _forceX;
76
+ private _forceY;
77
+ private _torque;
78
+ private _id;
79
+ private _owner;
80
+ private _attached;
57
81
  private readonly _transform;
58
82
  private readonly _colliders;
59
83
  private _comX;
60
84
  private _comY;
61
85
  private _massReady;
62
86
  private _destroyed;
63
- constructor(owner: BodyOwner, id: number, options?: BodyOptions);
87
+ constructor(options?: BodyOptions);
88
+ /** Stable id, assigned when the body joins a world via `world.add()`; `-1` until then. */
89
+ get id(): number;
90
+ /** `true` once the body has been added to a world (guards against double-add). */
91
+ get attached(): boolean;
64
92
  /** World X. */
65
93
  get x(): number;
66
94
  /** World Y. */
@@ -85,8 +113,15 @@ export declare class PhysicsBody {
85
113
  get isMassReady(): boolean;
86
114
  /** `true` after the owning world has destroyed this body. */
87
115
  get destroyed(): boolean;
88
- /** Attach a new collider, recomputing mass and synchronising world geometry. */
89
- createCollider(options: ColliderOptions): Collider;
116
+ /**
117
+ * Attach a collider to this body. Accepts a {@link Collider} instance or its
118
+ * {@link ColliderOptions} (a convenience that constructs the collider for you).
119
+ * When the body is already in a world, the collider is id-allocated, registered,
120
+ * the mass model is recomputed and the world geometry synchronised immediately;
121
+ * on a free-standing body the collider is simply held until `world.add()`.
122
+ * Returns the collider.
123
+ */
124
+ addCollider(collider: Collider | ColliderOptions): Collider;
90
125
  /**
91
126
  * Set the body's world transform. Resets the body's cached collider geometry
92
127
  * immediately so subsequent queries see the new placement. Returns `this`.
@@ -94,8 +129,71 @@ export declare class PhysicsBody {
94
129
  setTransform(position: VectorLike, angle?: number): this;
95
130
  /** Refresh every collider's world geometry from the current transform. */
96
131
  synchronizeColliders(): void;
132
+ /** World-space centre of mass X (body origin + rotated local centre of mass). */
133
+ get worldCenterOfMassX(): number;
134
+ /** World-space centre of mass Y. */
135
+ get worldCenterOfMassY(): number;
136
+ /**
137
+ * Accumulate a world-space force at the centre of mass; integrated on the next
138
+ * sub-step and then cleared. No-op on static/kinematic bodies. Returns `this`.
139
+ */
140
+ applyForce(forceX: number, forceY: number): this;
141
+ /**
142
+ * Accumulate a torque; integrated on the next sub-step and then cleared. No-op
143
+ * on static/kinematic bodies (and fixed-rotation bodies). Returns `this`.
144
+ */
145
+ applyTorque(torque: number): this;
146
+ /**
147
+ * Apply an instantaneous world-space impulse at `(pointX, pointY)` (world space;
148
+ * defaults to the centre of mass), changing velocity immediately. No-op on
149
+ * static/kinematic bodies (infinite mass). Returns `this`.
150
+ */
151
+ applyImpulse(impulseX: number, impulseY: number, pointX?: number, pointY?: number): this;
152
+ /**
153
+ * @internal — integrate velocity from gravity, accumulated forces/torque and
154
+ * damping over the sub-step `h`. No-op for static/kinematic (infinite mass
155
+ * keeps their velocity solver-driven only). Called once per TGS sub-step, so
156
+ * gravity/forces are applied with `h` each sub-step (`N·h = dt`, same total
157
+ * impulse, but the small-step position error scales with `h²`). The
158
+ * force/torque accumulators are **not** cleared here — they are consumed by
159
+ * every sub-step and cleared once per frame by {@link _finalizePosition}.
160
+ */
161
+ _integrateVelocity(h: number, gravityX: number, gravityY: number): void;
162
+ /**
163
+ * @internal — accumulate this sub-step's velocity into the per-frame delta
164
+ * position/rotation (TGS sub-stepping). The transform itself is **not** moved
165
+ * here; {@link _finalizePosition} writes the accumulated delta once per frame.
166
+ * Tracking the delta (rather than moving the transform each sub-step) lets the
167
+ * solver recompute contact separation from it without re-running detection or
168
+ * re-syncing collider geometry per sub-step. Static bodies never move.
169
+ */
170
+ _integratePosition(h: number): void;
171
+ /**
172
+ * @internal — apply the frame's accumulated delta position/rotation to the
173
+ * transform (rotating about the centre of mass), re-sync collider geometry and
174
+ * clear the force/torque accumulators. Called once per frame after the
175
+ * sub-step loop. Static bodies never move; the force clear still runs (forces
176
+ * are a no-op on infinite mass but the accumulator is reset for consistency).
177
+ */
178
+ _finalizePosition(): void;
179
+ /** Clear the per-frame TGS delta accumulators (position, rotation and its cached cos/sin). */
180
+ private _resetDelta;
97
181
  /** Internal: detach a collider (called by the world during destruction). */
98
182
  _removeCollider(collider: Collider): void;
183
+ /**
184
+ * @internal — join `owner`'s world with the allocated `id`. Allocates ids for
185
+ * and registers every held collider, then aggregates the mass model and
186
+ * synchronises world geometry. Called once by {@link PhysicsWorld.add}.
187
+ *
188
+ * Ordering matters and mirrors the per-collider create path exactly: ids and
189
+ * the body link go on first, then a single mass recompute over the full
190
+ * collider set (so the centre of mass / inertia aggregate is correct), then
191
+ * `synchronize` over every collider (the cached world geometry the broad/narrow
192
+ * phase reads), then world registration last. Recomputing mass before all
193
+ * colliders are linked, or syncing before the mass model exists, would feed the
194
+ * solver a stale CoM and produce subtle integration bugs.
195
+ */
196
+ _attachToWorld(owner: BodyOwner, id: number): void;
99
197
  /** Internal: mark destroyed (called by the world). */
100
198
  _markDestroyed(): void;
101
199
  /** Recompute mass, centre of mass and rotational inertia from the colliders. */
@@ -4,19 +4,20 @@ import { createTransform, setTransform, applyTransform } from './math.js';
4
4
 
5
5
  /**
6
6
  * A rigid body: a world transform plus mass properties aggregated from its
7
- * colliders. In this collision/query release a body holds and reports its
8
- * transform and mass but is not integrated it moves only via
9
- * {@link setTransform} (game-driven / kinematic). Forces, impulses and gravity
10
- * integration arrive with the dynamics solver.
7
+ * colliders. Dynamic bodies integrate under gravity, accumulated forces/torque
8
+ * and contact impulses each fixed sub-step; static bodies never move; kinematic
9
+ * bodies move by their velocity only and stay immovable under contacts. Drive a
10
+ * body with {@link applyForce}, {@link applyTorque} and {@link applyImpulse}, or
11
+ * set {@link linearVelocityX}/{@link linearVelocityY}/{@link angularVelocity}
12
+ * directly; reposition it (teleport, no velocity) with {@link setTransform}.
11
13
  */
12
14
  class PhysicsBody {
13
- id;
14
15
  type;
15
- /** Linear damping (inert until dynamics ship). */
16
+ /** Linear damping applied to the velocity each sub-step. */
16
17
  linearDamping;
17
- /** Angular damping (inert until dynamics ship). */
18
+ /** Angular damping applied to the angular velocity each sub-step. */
18
19
  angularDamping;
19
- /** Per-body gravity multiplier (inert until dynamics ship). */
20
+ /** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). */
20
21
  gravityScale;
21
22
  /** When `true`, rotational inertia is treated as infinite. */
22
23
  fixedRotation;
@@ -28,22 +29,57 @@ class PhysicsBody {
28
29
  inertia = 0;
29
30
  /** Inverse rotational inertia (`0` = no angular response). */
30
31
  invInertia = 0;
31
- _owner;
32
+ /** Linear velocity X in px/s. */
33
+ linearVelocityX = 0;
34
+ /** Linear velocity Y in px/s. */
35
+ linearVelocityY = 0;
36
+ /** Angular velocity in rad/s. */
37
+ angularVelocity = 0;
38
+ /** @internal — Delta position X accumulated across the frame's sub-steps by the TGS integrator; written into the transform once per frame by {@link _finalizePosition}. */
39
+ _deltaPosX = 0;
40
+ /** @internal — Delta position Y accumulated across the frame's sub-steps by the TGS integrator. */
41
+ _deltaPosY = 0;
42
+ /** @internal — Delta rotation (radians) accumulated across the frame's sub-steps by the TGS integrator. */
43
+ _deltaAngle = 0;
44
+ /** @internal — `cos(_deltaAngle)`, cached so the solver can rotate the contact anchors by the live sub-step rotation without a per-contact trig call. */
45
+ _deltaCos = 1;
46
+ /** @internal — `sin(_deltaAngle)`, cached alongside {@link _deltaCos}. */
47
+ _deltaSin = 0;
48
+ _forceX = 0;
49
+ _forceY = 0;
50
+ _torque = 0;
51
+ _id = -1;
52
+ _owner = null;
53
+ _attached = false;
32
54
  _transform;
33
55
  _colliders = [];
34
56
  _comX = 0;
35
57
  _comY = 0;
36
58
  _massReady = false;
37
59
  _destroyed = false;
38
- constructor(owner, id, options = {}) {
39
- this.id = id;
60
+ constructor(options = {}) {
40
61
  this.type = options.type ?? 'dynamic';
41
- this._owner = owner;
42
62
  this._transform = createTransform(options.position?.x ?? 0, options.position?.y ?? 0, options.angle ?? 0);
43
63
  this.linearDamping = options.linearDamping ?? 0;
44
64
  this.angularDamping = options.angularDamping ?? 0;
45
65
  this.gravityScale = options.gravityScale ?? 1;
46
66
  this.fixedRotation = options.fixedRotation ?? false;
67
+ // Build up-front colliders now (no id/world registration until the body
68
+ // joins a world via `world.add()`). They sit in `_colliders` unsynchronised;
69
+ // `_attachToWorld` assigns ids, registers them and computes the mass model.
70
+ if (options.colliders) {
71
+ for (const entry of options.colliders) {
72
+ this._colliders.push(entry instanceof Collider ? entry : new Collider(entry));
73
+ }
74
+ }
75
+ }
76
+ /** Stable id, assigned when the body joins a world via `world.add()`; `-1` until then. */
77
+ get id() {
78
+ return this._id;
79
+ }
80
+ /** `true` once the body has been added to a world (guards against double-add). */
81
+ get attached() {
82
+ return this._attached;
47
83
  }
48
84
  /** World X. */
49
85
  get x() {
@@ -89,19 +125,32 @@ class PhysicsBody {
89
125
  get destroyed() {
90
126
  return this._destroyed;
91
127
  }
92
- /** Attach a new collider, recomputing mass and synchronising world geometry. */
93
- createCollider(options) {
128
+ /**
129
+ * Attach a collider to this body. Accepts a {@link Collider} instance or its
130
+ * {@link ColliderOptions} (a convenience that constructs the collider for you).
131
+ * When the body is already in a world, the collider is id-allocated, registered,
132
+ * the mass model is recomputed and the world geometry synchronised immediately;
133
+ * on a free-standing body the collider is simply held until `world.add()`.
134
+ * Returns the collider.
135
+ */
136
+ addCollider(collider) {
94
137
  if (this._destroyed) {
95
- throw new Error('PhysicsBody: cannot create a collider on a destroyed body.');
138
+ throw new Error('PhysicsBody: cannot add a collider to a destroyed body.');
96
139
  }
97
140
  // Collider imports PhysicsBody type-only (erased), so this value import is
98
141
  // one-directional — no runtime cycle.
99
- const collider = new Collider(this._owner._allocateColliderId(), this, options);
100
- this._colliders.push(collider);
101
- this._recomputeMass();
102
- collider.synchronize(this._transform);
103
- this._owner._registerCollider(collider);
104
- return collider;
142
+ const instance = collider instanceof Collider ? collider : new Collider(collider);
143
+ this._colliders.push(instance);
144
+ // Before the body joins a world there is no owner to allocate ids / register
145
+ // with; `_attachToWorld` does that (and the mass/sync pass) for every held
146
+ // collider. Once attached, mirror the world's create order exactly.
147
+ if (this._attached && this._owner) {
148
+ instance._attach(this, this._owner._allocateColliderId());
149
+ this._recomputeMass();
150
+ instance.synchronize(this._transform);
151
+ this._owner._registerCollider(instance);
152
+ }
153
+ return instance;
105
154
  }
106
155
  /**
107
156
  * Set the body's world transform. Resets the body's cached collider geometry
@@ -123,6 +172,129 @@ class PhysicsBody {
123
172
  collider.synchronize(this._transform);
124
173
  }
125
174
  }
175
+ /** World-space centre of mass X (body origin + rotated local centre of mass). */
176
+ get worldCenterOfMassX() {
177
+ return this._transform.x + this._transform.cos * this._comX - this._transform.sin * this._comY;
178
+ }
179
+ /** World-space centre of mass Y. */
180
+ get worldCenterOfMassY() {
181
+ return this._transform.y + this._transform.sin * this._comX + this._transform.cos * this._comY;
182
+ }
183
+ /**
184
+ * Accumulate a world-space force at the centre of mass; integrated on the next
185
+ * sub-step and then cleared. No-op on static/kinematic bodies. Returns `this`.
186
+ */
187
+ applyForce(forceX, forceY) {
188
+ this._forceX += forceX;
189
+ this._forceY += forceY;
190
+ return this;
191
+ }
192
+ /**
193
+ * Accumulate a torque; integrated on the next sub-step and then cleared. No-op
194
+ * on static/kinematic bodies (and fixed-rotation bodies). Returns `this`.
195
+ */
196
+ applyTorque(torque) {
197
+ this._torque += torque;
198
+ return this;
199
+ }
200
+ /**
201
+ * Apply an instantaneous world-space impulse at `(pointX, pointY)` (world space;
202
+ * defaults to the centre of mass), changing velocity immediately. No-op on
203
+ * static/kinematic bodies (infinite mass). Returns `this`.
204
+ */
205
+ applyImpulse(impulseX, impulseY, pointX, pointY) {
206
+ if (this.invMass === 0) {
207
+ return this;
208
+ }
209
+ this.linearVelocityX += impulseX * this.invMass;
210
+ this.linearVelocityY += impulseY * this.invMass;
211
+ if (pointX !== undefined && pointY !== undefined && this.invInertia !== 0) {
212
+ const rx = pointX - this.worldCenterOfMassX;
213
+ const ry = pointY - this.worldCenterOfMassY;
214
+ this.angularVelocity += (rx * impulseY - ry * impulseX) * this.invInertia;
215
+ }
216
+ return this;
217
+ }
218
+ /**
219
+ * @internal — integrate velocity from gravity, accumulated forces/torque and
220
+ * damping over the sub-step `h`. No-op for static/kinematic (infinite mass
221
+ * keeps their velocity solver-driven only). Called once per TGS sub-step, so
222
+ * gravity/forces are applied with `h` each sub-step (`N·h = dt`, same total
223
+ * impulse, but the small-step position error scales with `h²`). The
224
+ * force/torque accumulators are **not** cleared here — they are consumed by
225
+ * every sub-step and cleared once per frame by {@link _finalizePosition}.
226
+ */
227
+ _integrateVelocity(h, gravityX, gravityY) {
228
+ if (this.invMass === 0) {
229
+ return;
230
+ }
231
+ this.linearVelocityX += (gravityX * this.gravityScale + this._forceX * this.invMass) * h;
232
+ this.linearVelocityY += (gravityY * this.gravityScale + this._forceY * this.invMass) * h;
233
+ this.angularVelocity += this._torque * this.invInertia * h;
234
+ // Exponential damping (no-op when damping is 0).
235
+ this.linearVelocityX /= 1 + h * this.linearDamping;
236
+ this.linearVelocityY /= 1 + h * this.linearDamping;
237
+ this.angularVelocity /= 1 + h * this.angularDamping;
238
+ }
239
+ /**
240
+ * @internal — accumulate this sub-step's velocity into the per-frame delta
241
+ * position/rotation (TGS sub-stepping). The transform itself is **not** moved
242
+ * here; {@link _finalizePosition} writes the accumulated delta once per frame.
243
+ * Tracking the delta (rather than moving the transform each sub-step) lets the
244
+ * solver recompute contact separation from it without re-running detection or
245
+ * re-syncing collider geometry per sub-step. Static bodies never move.
246
+ */
247
+ _integratePosition(h) {
248
+ if (this.type === 'static') {
249
+ return;
250
+ }
251
+ this._deltaPosX += this.linearVelocityX * h;
252
+ this._deltaPosY += this.linearVelocityY * h;
253
+ this._deltaAngle += this.angularVelocity * h;
254
+ // Cache the rotation so the solver can rotate the contact anchors by the
255
+ // live sub-step rotation (TGS): without it the anchors stay frozen at frame
256
+ // start and a tilting tower's restoring torque is mis-computed, so the tilt
257
+ // grows instead of being corrected. Only non-zero rotation pays the trig.
258
+ if (this._deltaAngle !== 0) {
259
+ this._deltaCos = Math.cos(this._deltaAngle);
260
+ this._deltaSin = Math.sin(this._deltaAngle);
261
+ }
262
+ }
263
+ /**
264
+ * @internal — apply the frame's accumulated delta position/rotation to the
265
+ * transform (rotating about the centre of mass), re-sync collider geometry and
266
+ * clear the force/torque accumulators. Called once per frame after the
267
+ * sub-step loop. Static bodies never move; the force clear still runs (forces
268
+ * are a no-op on infinite mass but the accumulator is reset for consistency).
269
+ */
270
+ _finalizePosition() {
271
+ this._forceX = 0;
272
+ this._forceY = 0;
273
+ this._torque = 0;
274
+ if (this.type === 'static' || (this._deltaPosX === 0 && this._deltaPosY === 0 && this._deltaAngle === 0)) {
275
+ this._resetDelta();
276
+ return;
277
+ }
278
+ const newComX = this.worldCenterOfMassX + this._deltaPosX;
279
+ const newComY = this.worldCenterOfMassY + this._deltaPosY;
280
+ const newAngle = this._transform.angle + this._deltaAngle;
281
+ const cos = Math.cos(newAngle);
282
+ const sin = Math.sin(newAngle);
283
+ // origin = newCoM − R(newAngle)·comLocal (so rotation pivots about the CoM).
284
+ setTransform(this._transform, newComX - (cos * this._comX - sin * this._comY), newComY - (sin * this._comX + cos * this._comY), newAngle);
285
+ this._resetDelta();
286
+ for (const collider of this._colliders) {
287
+ collider.synchronize(this._transform);
288
+ }
289
+ }
290
+ /** Clear the per-frame TGS delta accumulators (position, rotation and its cached cos/sin). */
291
+ _resetDelta() {
292
+ this._deltaPosX = 0;
293
+ this._deltaPosY = 0;
294
+ this._deltaAngle = 0;
295
+ this._deltaCos = 1;
296
+ this._deltaSin = 0;
297
+ }
126
298
  /** Internal: detach a collider (called by the world during destruction). */
127
299
  _removeCollider(collider) {
128
300
  const index = this._colliders.indexOf(collider);
@@ -131,6 +303,37 @@ class PhysicsBody {
131
303
  this._recomputeMass();
132
304
  }
133
305
  }
306
+ /**
307
+ * @internal — join `owner`'s world with the allocated `id`. Allocates ids for
308
+ * and registers every held collider, then aggregates the mass model and
309
+ * synchronises world geometry. Called once by {@link PhysicsWorld.add}.
310
+ *
311
+ * Ordering matters and mirrors the per-collider create path exactly: ids and
312
+ * the body link go on first, then a single mass recompute over the full
313
+ * collider set (so the centre of mass / inertia aggregate is correct), then
314
+ * `synchronize` over every collider (the cached world geometry the broad/narrow
315
+ * phase reads), then world registration last. Recomputing mass before all
316
+ * colliders are linked, or syncing before the mass model exists, would feed the
317
+ * solver a stale CoM and produce subtle integration bugs.
318
+ */
319
+ _attachToWorld(owner, id) {
320
+ if (this._destroyed) {
321
+ throw new Error('PhysicsBody: cannot add a destroyed body to a world.');
322
+ }
323
+ this._owner = owner;
324
+ this._id = id;
325
+ this._attached = true;
326
+ for (const collider of this._colliders) {
327
+ collider._attach(this, owner._allocateColliderId());
328
+ }
329
+ this._recomputeMass();
330
+ for (const collider of this._colliders) {
331
+ collider.synchronize(this._transform);
332
+ }
333
+ for (const collider of this._colliders) {
334
+ owner._registerCollider(collider);
335
+ }
336
+ }
134
337
  /** Internal: mark destroyed (called by the world). */
135
338
  _markDestroyed() {
136
339
  this._destroyed = true;
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicsBody.js","sources":["../../../src/PhysicsBody.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAkCA;;;;;;AAMG;MACU,WAAW,CAAA;AACN,IAAA,EAAE;AACF,IAAA,IAAI;;AAGb,IAAA,aAAa;;AAEb,IAAA,cAAc;;AAEd,IAAA,YAAY;;AAEZ,IAAA,aAAa;;IAGb,IAAI,GAAG,CAAC;;IAER,OAAO,GAAG,CAAC;;IAEX,OAAO,GAAG,CAAC;;IAEX,UAAU,GAAG,CAAC;AAEJ,IAAA,MAAM;AACN,IAAA,UAAU;IACV,UAAU,GAAe,EAAE;IACpC,KAAK,GAAG,CAAC;IACT,KAAK,GAAG,CAAC;IACT,UAAU,GAAG,KAAK;IAClB,UAAU,GAAG,KAAK;AAE1B,IAAA,WAAA,CAAmB,KAAgB,EAAE,EAAU,EAAE,UAAuB,EAAE,EAAA;AACxE,QAAA,IAAI,CAAC,EAAE,GAAG,EAAE;QACZ,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS;AACrC,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;QACnB,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QACzG,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC;QAC/C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC;QACjD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC;QAC7C,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,KAAK;IACrD;;AAGA,IAAA,IAAW,CAAC,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B;;AAGA,IAAA,IAAW,CAAC,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B;;AAGA,IAAA,IAAW,KAAK,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK;IAC9B;;AAGA,IAAA,IAAW,QAAQ,GAAA;AACjB,QAAA,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACzD;;AAGA,IAAA,IAAW,SAAS,GAAA;QAClB,OAAO,IAAI,CAAC,UAAU;IACxB;;AAGA,IAAA,IAAW,SAAS,GAAA;QAClB,OAAO,IAAI,CAAC,UAAU;IACxB;;AAGA,IAAA,IAAW,aAAa,GAAA;QACtB,OAAO,IAAI,CAAC,KAAK;IACnB;;AAGA,IAAA,IAAW,aAAa,GAAA;QACtB,OAAO,IAAI,CAAC,KAAK;IACnB;AAEA;;;;AAIG;AACH,IAAA,IAAW,WAAW,GAAA;QACpB,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU;IACnD;;AAGA,IAAA,IAAW,SAAS,GAAA;QAClB,OAAO,IAAI,CAAC,UAAU;IACxB;;AAGO,IAAA,cAAc,CAAC,OAAwB,EAAA;AAC5C,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC;QAC/E;;;AAIA,QAAA,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC;AAE/E,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;AACrC,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC;AAEvC,QAAA,OAAO,QAAQ;IACjB;AAEA;;;AAGG;IACI,YAAY,CAAC,QAAoB,EAAE,KAAA,GAAgB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAA;AAC7E,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC;QAC/D;AAEA,QAAA,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;AAE5D,QAAA,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE;AACtC,YAAA,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;QACvC;AAEA,QAAA,OAAO,IAAI;IACb;;IAGO,oBAAoB,GAAA;AACzB,QAAA,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE;AACtC,YAAA,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;QACvC;IACF;;AAGO,IAAA,eAAe,CAAC,QAAkB,EAAA;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC;AAE/C,QAAA,IAAI,KAAK,KAAK,EAAE,EAAE;YAChB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAChC,IAAI,CAAC,cAAc,EAAE;QACvB;IACF;;IAGO,cAAc,GAAA;AACnB,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI;IACxB;;IAGQ,cAAc,GAAA;AACpB,QAAA,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE;AAC3B,YAAA,IAAI,CAAC,IAAI,GAAG,CAAC;AACb,YAAA,IAAI,CAAC,OAAO,GAAG,CAAC;AAChB,YAAA,IAAI,CAAC,OAAO,GAAG,CAAC;AAChB,YAAA,IAAI,CAAC,UAAU,GAAG,CAAC;AACnB,YAAA,IAAI,CAAC,KAAK,GAAG,CAAC;AACd,YAAA,IAAI,CAAC,KAAK,GAAG,CAAC;AACd,YAAA,IAAI,CAAC,UAAU,GAAG,KAAK;YAEvB;QACF;QAEA,IAAI,IAAI,GAAG,CAAC;QACZ,IAAI,EAAE,GAAG,CAAC;QACV,IAAI,EAAE,GAAG,CAAC;QACV,IAAI,aAAa,GAAG,CAAC;QACrB,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAE5B,QAAA,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE;AACtC,YAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK;YAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI;AAEvC,YAAA,IAAI,CAAC,IAAI,CAAC,EAAE;gBACV;YACF;;AAGA,YAAA,cAAc,CAAC,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC;YAChF,IAAI,IAAI,CAAC;AACT,YAAA,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;AACjB,YAAA,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;;AAEjB,YAAA,aAAa,IAAI,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC,WAAW,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;QACrG;AAEA,QAAA,IAAI,IAAI,GAAG,CAAC,EAAE;YACZ,EAAE,IAAI,IAAI;YACV,EAAE,IAAI,IAAI;QACZ;AAEA,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;AACtC,QAAA,IAAI,CAAC,KAAK,GAAG,EAAE;AACf,QAAA,IAAI,CAAC,KAAK,GAAG,EAAE;;AAEf,QAAA,MAAM,UAAU,GAAG,aAAa,GAAG,IAAI,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE7D,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,UAAU;QAClD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,IAAI,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU;AAC5E,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC;IAC5B;AACD;;;;"}
1
+ {"version":3,"file":"PhysicsBody.js","sources":["../../../src/PhysicsBody.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}