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