@flighthq/physics3d 0.4.0-edge.1908.751021c
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/dist/broadphase.d.ts +4 -0
- package/dist/broadphase.d.ts.map +1 -0
- package/dist/broadphase.js +158 -0
- package/dist/broadphase.js.map +1 -0
- package/dist/colliderCollision.d.ts +5 -0
- package/dist/colliderCollision.d.ts.map +1 -0
- package/dist/colliderCollision.js +55 -0
- package/dist/colliderCollision.js.map +1 -0
- package/dist/colliderTransform.d.ts +5 -0
- package/dist/colliderTransform.d.ts.map +1 -0
- package/dist/colliderTransform.js +424 -0
- package/dist/colliderTransform.js.map +1 -0
- package/dist/contactIntake.d.ts +5 -0
- package/dist/contactIntake.d.ts.map +1 -0
- package/dist/contactIntake.js +237 -0
- package/dist/contactIntake.js.map +1 -0
- package/dist/contacts.d.ts +4 -0
- package/dist/contacts.d.ts.map +1 -0
- package/dist/contacts.js +64 -0
- package/dist/contacts.js.map +1 -0
- package/dist/continuous.d.ts +5 -0
- package/dist/continuous.d.ts.map +1 -0
- package/dist/continuous.js +829 -0
- package/dist/continuous.js.map +1 -0
- package/dist/contract.d.ts +28 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +28 -0
- package/dist/contract.js.map +1 -0
- package/dist/debugGeometry.d.ts +4 -0
- package/dist/debugGeometry.d.ts.map +1 -0
- package/dist/debugGeometry.js +333 -0
- package/dist/debugGeometry.js.map +1 -0
- package/dist/enablePhysics3DGuards.d.ts +4 -0
- package/dist/enablePhysics3DGuards.d.ts.map +1 -0
- package/dist/enablePhysics3DGuards.js +155 -0
- package/dist/enablePhysics3DGuards.js.map +1 -0
- package/dist/explainPhysics3DCollision.d.ts +3 -0
- package/dist/explainPhysics3DCollision.d.ts.map +1 -0
- package/dist/explainPhysics3DCollision.js +30 -0
- package/dist/explainPhysics3DCollision.js.map +1 -0
- package/dist/explainPhysics3DJoints.d.ts +3 -0
- package/dist/explainPhysics3DJoints.d.ts.map +1 -0
- package/dist/explainPhysics3DJoints.js +32 -0
- package/dist/explainPhysics3DJoints.js.map +1 -0
- package/dist/explainPhysics3DStep.d.ts +3 -0
- package/dist/explainPhysics3DStep.d.ts.map +1 -0
- package/dist/explainPhysics3DStep.js +51 -0
- package/dist/explainPhysics3DStep.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/integrate.d.ts +6 -0
- package/dist/integrate.d.ts.map +1 -0
- package/dist/integrate.js +184 -0
- package/dist/integrate.js.map +1 -0
- package/dist/islands.d.ts +6 -0
- package/dist/islands.d.ts.map +1 -0
- package/dist/islands.js +333 -0
- package/dist/islands.js.map +1 -0
- package/dist/jointBreakage.d.ts +5 -0
- package/dist/jointBreakage.d.ts.map +1 -0
- package/dist/jointBreakage.js +44 -0
- package/dist/jointBreakage.js.map +1 -0
- package/dist/jointCollisionSuppression.d.ts +4 -0
- package/dist/jointCollisionSuppression.d.ts.map +1 -0
- package/dist/jointCollisionSuppression.js +40 -0
- package/dist/jointCollisionSuppression.js.map +1 -0
- package/dist/jointFactories.d.ts +9 -0
- package/dist/jointFactories.d.ts.map +1 -0
- package/dist/jointFactories.js +159 -0
- package/dist/jointFactories.js.map +1 -0
- package/dist/jointMath.d.ts +17 -0
- package/dist/jointMath.d.ts.map +1 -0
- package/dist/jointMath.js +361 -0
- package/dist/jointMath.js.map +1 -0
- package/dist/jointReaction.d.ts +8 -0
- package/dist/jointReaction.d.ts.map +1 -0
- package/dist/jointReaction.js +65 -0
- package/dist/jointReaction.js.map +1 -0
- package/dist/jointRegistry.d.ts +8 -0
- package/dist/jointRegistry.d.ts.map +1 -0
- package/dist/jointRegistry.js +144 -0
- package/dist/jointRegistry.js.map +1 -0
- package/dist/jointRows.d.ts +33 -0
- package/dist/jointRows.d.ts.map +1 -0
- package/dist/jointRows.js +352 -0
- package/dist/jointRows.js.map +1 -0
- package/dist/joints.d.ts +16 -0
- package/dist/joints.d.ts.map +1 -0
- package/dist/joints.js +1060 -0
- package/dist/joints.js.map +1 -0
- package/dist/massProperties.d.ts +13 -0
- package/dist/massProperties.d.ts.map +1 -0
- package/dist/massProperties.js +462 -0
- package/dist/massProperties.js.map +1 -0
- package/dist/material.d.ts +3 -0
- package/dist/material.d.ts.map +1 -0
- package/dist/material.js +13 -0
- package/dist/material.js.map +1 -0
- package/dist/nodeSync.d.ts +3 -0
- package/dist/nodeSync.d.ts.map +1 -0
- package/dist/nodeSync.js +16 -0
- package/dist/nodeSync.js.map +1 -0
- package/dist/ownership.d.ts +8 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/ownership.js +26 -0
- package/dist/ownership.js.map +1 -0
- package/dist/physics3DBroadphasePublication.d.ts +5 -0
- package/dist/physics3DBroadphasePublication.d.ts.map +1 -0
- package/dist/physics3DBroadphasePublication.js +49 -0
- package/dist/physics3DBroadphasePublication.js.map +1 -0
- package/dist/physics3DSpatialIndexingGuards.d.ts +4 -0
- package/dist/physics3DSpatialIndexingGuards.d.ts.map +1 -0
- package/dist/physics3DSpatialIndexingGuards.js +11 -0
- package/dist/physics3DSpatialIndexingGuards.js.map +1 -0
- package/dist/registerBuiltInPhysics3DJointSolvers.d.ts +3 -0
- package/dist/registerBuiltInPhysics3DJointSolvers.d.ts.map +1 -0
- package/dist/registerBuiltInPhysics3DJointSolvers.js +15 -0
- package/dist/registerBuiltInPhysics3DJointSolvers.js.map +1 -0
- package/dist/solver.d.ts +8 -0
- package/dist/solver.d.ts.map +1 -0
- package/dist/solver.js +460 -0
- package/dist/solver.js.map +1 -0
- package/dist/step.d.ts +5 -0
- package/dist/step.d.ts.map +1 -0
- package/dist/step.js +302 -0
- package/dist/step.js.map +1 -0
- package/dist/stepValidation.d.ts +13 -0
- package/dist/stepValidation.d.ts.map +1 -0
- package/dist/stepValidation.js +284 -0
- package/dist/stepValidation.js.map +1 -0
- package/dist/symmetricTensor.d.ts +11 -0
- package/dist/symmetricTensor.d.ts.map +1 -0
- package/dist/symmetricTensor.js +150 -0
- package/dist/symmetricTensor.js.map +1 -0
- package/dist/world.d.ts +27 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +762 -0
- package/dist/world.js.map +1 -0
- package/dist/worldQueries.d.ts +11 -0
- package/dist/worldQueries.d.ts.map +1 -0
- package/dist/worldQueries.js +409 -0
- package/dist/worldQueries.js.map +1 -0
- package/package.json +55 -0
- package/src/broadphase.test.ts +265 -0
- package/src/colliderCollision.test.ts +57 -0
- package/src/colliderTransform.test.ts +221 -0
- package/src/contactIntake.test.ts +370 -0
- package/src/contacts.test.ts +64 -0
- package/src/continuous.test.ts +679 -0
- package/src/debugGeometry.test.ts +288 -0
- package/src/enablePhysics3DGuards.test.ts +206 -0
- package/src/explainPhysics3DCollision.test.ts +78 -0
- package/src/explainPhysics3DJoints.test.ts +101 -0
- package/src/explainPhysics3DStep.test.ts +142 -0
- package/src/integrate.test.ts +279 -0
- package/src/islands.test.ts +384 -0
- package/src/jointBreakage.test.ts +143 -0
- package/src/jointCollisionSuppression.test.ts +94 -0
- package/src/jointFactories.test.ts +244 -0
- package/src/jointMath.test.ts +646 -0
- package/src/jointReaction.test.ts +241 -0
- package/src/jointRegistry.test.ts +229 -0
- package/src/jointRows.test.ts +548 -0
- package/src/joints.test.ts +1066 -0
- package/src/massProperties.test.ts +611 -0
- package/src/material.test.ts +40 -0
- package/src/nodeSync.test.ts +50 -0
- package/src/ownership.test.ts +61 -0
- package/src/physics3DBroadphasePublication.test.ts +63 -0
- package/src/physics3DSpatialIndexingGuards.test.ts +43 -0
- package/src/registerBuiltInPhysics3DJointSolvers.test.ts +51 -0
- package/src/solver.test.ts +567 -0
- package/src/step.test.ts +490 -0
- package/src/stepValidation.test.ts +346 -0
- package/src/stress.test.ts +526 -0
- package/src/symmetricTensor.test.ts +166 -0
- package/src/world.test.ts +1127 -0
- package/src/worldQueries.test.ts +565 -0
package/dist/islands.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { findPhysics3DBody } from './world';
|
|
2
|
+
// Rebuilds deterministic contiguous lists for the awake solve islands.
|
|
3
|
+
//
|
|
4
|
+
// The sleep reduction already owns the union-find graph, so solving consumes that same graph rather
|
|
5
|
+
// than discovering connectivity a second way. Roots are admitted in body order, and bodies, contacts,
|
|
6
|
+
// and joints retain their canonical world-list order inside each root. Disconnected islands therefore
|
|
7
|
+
// cannot perturb one another's iteration order, and sleeping constraints cost no solver scans. Every
|
|
8
|
+
// array and map is world-owned high-water workspace and is cleared and refilled in place.
|
|
9
|
+
//
|
|
10
|
+
// Runs after `updatePhysics3DSleep`, never before: the workspace admits only awake bodies, so building
|
|
11
|
+
// it against an unresolved sleep state would hand the solver islands it is about to put to sleep.
|
|
12
|
+
export function buildPhysics3DSolveIslands(world) {
|
|
13
|
+
physics3DJointResolutionGuard?.(world);
|
|
14
|
+
const roots = world.solveIslandRoots;
|
|
15
|
+
const byRoot = world.solveIslandByRoot;
|
|
16
|
+
const bodyCounts = world.solveIslandBodyCounts;
|
|
17
|
+
const contactCounts = world.solveIslandContactCounts;
|
|
18
|
+
const jointCounts = world.solveIslandJointCounts;
|
|
19
|
+
roots.length = 0;
|
|
20
|
+
byRoot.clear();
|
|
21
|
+
bodyCounts.length = 0;
|
|
22
|
+
contactCounts.length = 0;
|
|
23
|
+
jointCounts.length = 0;
|
|
24
|
+
for (let bodyIndex = 0; bodyIndex < world.bodies.length; bodyIndex += 1) {
|
|
25
|
+
const body = world.bodies[bodyIndex];
|
|
26
|
+
if (body.type === 'static' || body.sleeping)
|
|
27
|
+
continue;
|
|
28
|
+
const root = islandRootOf(world.islandParents, body.index);
|
|
29
|
+
let island = byRoot.get(root);
|
|
30
|
+
if (island === undefined) {
|
|
31
|
+
island = roots.length;
|
|
32
|
+
roots.push(root);
|
|
33
|
+
byRoot.set(root, island);
|
|
34
|
+
bodyCounts.push(0);
|
|
35
|
+
contactCounts.push(0);
|
|
36
|
+
jointCounts.push(0);
|
|
37
|
+
}
|
|
38
|
+
bodyCounts[island] += 1;
|
|
39
|
+
}
|
|
40
|
+
for (let contactIndex = 0; contactIndex < world.contacts.length; contactIndex += 1) {
|
|
41
|
+
const contact = world.contacts[contactIndex];
|
|
42
|
+
if (!contact.enabled || contact.sensor)
|
|
43
|
+
continue;
|
|
44
|
+
const island = solveIslandForPair(world, contact.bodyA, contact.bodyB);
|
|
45
|
+
if (island >= 0)
|
|
46
|
+
contactCounts[island] += 1;
|
|
47
|
+
}
|
|
48
|
+
for (let jointIndex = 0; jointIndex < world.joints.length; jointIndex += 1) {
|
|
49
|
+
const joint = world.joints[jointIndex];
|
|
50
|
+
const solver = world.jointSolvers.get(joint.kind);
|
|
51
|
+
if (solver === undefined || joint.broken)
|
|
52
|
+
continue;
|
|
53
|
+
const island = solver.usesBodyA === false
|
|
54
|
+
? solveIslandForBody(world, joint.bodyB)
|
|
55
|
+
: solveIslandForPair(world, joint.bodyA, joint.bodyB);
|
|
56
|
+
if (island >= 0)
|
|
57
|
+
jointCounts[island] += 1;
|
|
58
|
+
}
|
|
59
|
+
prepareIslandSlices(world.solveIslandBodyStarts, bodyCounts, world.solveIslandCursors);
|
|
60
|
+
prepareIslandSlices(world.solveIslandContactStarts, contactCounts, world.solveIslandCursors);
|
|
61
|
+
prepareIslandSlices(world.solveIslandJointStarts, jointCounts, world.solveIslandCursors);
|
|
62
|
+
world.solveIslandBodyIndices.length = islandItemCount(world.solveIslandBodyStarts, bodyCounts);
|
|
63
|
+
world.solveIslandContactIndices.length = islandItemCount(world.solveIslandContactStarts, contactCounts);
|
|
64
|
+
world.solveIslandJointIndices.length = islandItemCount(world.solveIslandJointStarts, jointCounts);
|
|
65
|
+
copyIslandStarts(world.solveIslandCursors, world.solveIslandBodyStarts);
|
|
66
|
+
for (let i = 0; i < world.bodies.length; i += 1) {
|
|
67
|
+
const body = world.bodies[i];
|
|
68
|
+
if (body.type === 'static' || body.sleeping)
|
|
69
|
+
continue;
|
|
70
|
+
const island = byRoot.get(islandRootOf(world.islandParents, body.index));
|
|
71
|
+
if (island !== undefined) {
|
|
72
|
+
world.solveIslandBodyIndices[world.solveIslandCursors[island]] = i;
|
|
73
|
+
world.solveIslandCursors[island] += 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
copyIslandStarts(world.solveIslandCursors, world.solveIslandContactStarts);
|
|
77
|
+
for (let i = 0; i < world.contacts.length; i += 1) {
|
|
78
|
+
const contact = world.contacts[i];
|
|
79
|
+
if (!contact.enabled || contact.sensor)
|
|
80
|
+
continue;
|
|
81
|
+
const island = solveIslandForPair(world, contact.bodyA, contact.bodyB);
|
|
82
|
+
if (island >= 0) {
|
|
83
|
+
world.solveIslandContactIndices[world.solveIslandCursors[island]] = i;
|
|
84
|
+
world.solveIslandCursors[island] += 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
copyIslandStarts(world.solveIslandCursors, world.solveIslandJointStarts);
|
|
88
|
+
for (let i = 0; i < world.joints.length; i += 1) {
|
|
89
|
+
const joint = world.joints[i];
|
|
90
|
+
const solver = world.jointSolvers.get(joint.kind);
|
|
91
|
+
if (solver === undefined || joint.broken)
|
|
92
|
+
continue;
|
|
93
|
+
const island = solver.usesBodyA === false
|
|
94
|
+
? solveIslandForBody(world, joint.bodyB)
|
|
95
|
+
: solveIslandForPair(world, joint.bodyA, joint.bodyB);
|
|
96
|
+
if (island >= 0) {
|
|
97
|
+
world.solveIslandJointIndices[world.solveIslandCursors[island]] = i;
|
|
98
|
+
world.solveIslandCursors[island] += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Whether a constraint between these two bodies still has anything to solve.
|
|
103
|
+
//
|
|
104
|
+
// A constraint is live only while at least one of its ends can still move this step. Two sleeping
|
|
105
|
+
// bodies, a sleeper against static scenery, or two static bodies all resolve to nothing: every impulse
|
|
106
|
+
// the solver could compute would be applied to a body that is not being integrated.
|
|
107
|
+
//
|
|
108
|
+
// Skipping is not merely an optimisation, and this is the reason sleep needs a solver-side test at all
|
|
109
|
+
// rather than only an integrator-side one. A resting contact usually carries penetration beyond the
|
|
110
|
+
// slop, so the position pass would move a sleeping pair, and the end-of-step stillness test would then
|
|
111
|
+
// read that motion and wake them again. A stack would twitch itself awake every step and never rest.
|
|
112
|
+
export function isRigidBody3DPairAwake(a, b) {
|
|
113
|
+
return isBodyLive(a) || isBodyLive(b);
|
|
114
|
+
}
|
|
115
|
+
// Installs the optional diagnostics seam consulted before unresolved joints are omitted from the solve
|
|
116
|
+
// workspace. Null by default and set only by `enablePhysics3DGuards`.
|
|
117
|
+
export function setPhysics3DJointResolutionGuard(guard) {
|
|
118
|
+
physics3DJointResolutionGuard = guard;
|
|
119
|
+
}
|
|
120
|
+
// Advances every body's sleep state for one step.
|
|
121
|
+
//
|
|
122
|
+
// Sleep is decided per ISLAND, not per body. Two dynamic bodies are in the same island when a contact
|
|
123
|
+
// or a joint connects them, transitively — so a stack, a chain of links, and a pile all settle or wake
|
|
124
|
+
// as one unit. Deciding per body instead produces the visible failure this exists to prevent: a crate
|
|
125
|
+
// that has stopped moving falls asleep while the crate it rests on is still sliding out from under it,
|
|
126
|
+
// and the sleeper hangs in the air until something happens to wake it.
|
|
127
|
+
//
|
|
128
|
+
// Static bodies are excluded entirely. They never move, so they are neither awake nor asleep, and
|
|
129
|
+
// crucially they do NOT join islands: every dynamic body resting on the same ground would otherwise be
|
|
130
|
+
// transitively connected into one world-sized island that can only sleep when the last object in the
|
|
131
|
+
// level stops moving.
|
|
132
|
+
//
|
|
133
|
+
// An island sleeps only once EVERY member has been continuously below both thresholds for
|
|
134
|
+
// `timeToSleep`. Any member exceeding a threshold resets its own timer, and because the island's timer
|
|
135
|
+
// is the minimum across its members, one moving body keeps the whole island awake.
|
|
136
|
+
export function updatePhysics3DSleep(world, dt) {
|
|
137
|
+
const config = world.config;
|
|
138
|
+
const bodies = world.bodies;
|
|
139
|
+
const parents = world.islandParents;
|
|
140
|
+
const islandTimers = world.islandSleepTimers;
|
|
141
|
+
parents.clear();
|
|
142
|
+
islandTimers.clear();
|
|
143
|
+
// Build the active constraint graph even when sleeping is disabled. The same union-find owns the
|
|
144
|
+
// solve islands below; clearing it and returning here would split every awake body into a singleton
|
|
145
|
+
// and assign a multi-body constraint to only the first of those artificial components.
|
|
146
|
+
for (let contactIndex = 0; contactIndex < world.contacts.length; contactIndex += 1) {
|
|
147
|
+
const contact = world.contacts[contactIndex];
|
|
148
|
+
if (!contact.enabled || contact.sensor)
|
|
149
|
+
continue;
|
|
150
|
+
unionDynamicPair(world, parents, contact.bodyA, contact.bodyB);
|
|
151
|
+
}
|
|
152
|
+
for (let jointIndex = 0; jointIndex < world.joints.length; jointIndex += 1) {
|
|
153
|
+
const joint = world.joints[jointIndex];
|
|
154
|
+
const solver = world.jointSolvers.get(joint.kind);
|
|
155
|
+
if (solver === undefined || joint.broken || solver.usesBodyA === false)
|
|
156
|
+
continue;
|
|
157
|
+
unionDynamicPair(world, parents, joint.bodyA, joint.bodyB);
|
|
158
|
+
}
|
|
159
|
+
if (!config.allowSleeping) {
|
|
160
|
+
// The mechanism is off, so nothing may be left asleep from when it was on — a body that stayed
|
|
161
|
+
// asleep here would never be integrated again and would look frozen for the rest of the session.
|
|
162
|
+
for (let bodyIndex = 0; bodyIndex < bodies.length; bodyIndex += 1) {
|
|
163
|
+
const body = bodies[bodyIndex];
|
|
164
|
+
body.sleeping = false;
|
|
165
|
+
body.sleepTimer = 0;
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// Per-body stillness first: each body's own timer, independent of who it is touching.
|
|
170
|
+
for (let bodyIndex = 0; bodyIndex < bodies.length; bodyIndex += 1) {
|
|
171
|
+
const body = bodies[bodyIndex];
|
|
172
|
+
if (body.type === 'static')
|
|
173
|
+
continue;
|
|
174
|
+
if (!body.sleepEnabled) {
|
|
175
|
+
body.sleeping = false;
|
|
176
|
+
body.sleepTimer = 0;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (isBodyStill(body, config.sleepLinearThreshold, config.sleepAngularThreshold)) {
|
|
180
|
+
body.sleepTimer += dt;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
body.sleepTimer = 0;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// A constraint driven by state outside the simulation cannot infer that its next target write is
|
|
187
|
+
// coming, so its solver declares that participating bodies stay awake for the constraint's lifetime.
|
|
188
|
+
// Reset after the stillness pass so even a timestep longer than timeToSleep cannot put one to sleep.
|
|
189
|
+
for (let jointIndex = 0; jointIndex < world.joints.length; jointIndex += 1) {
|
|
190
|
+
const joint = world.joints[jointIndex];
|
|
191
|
+
const solver = world.jointSolvers.get(joint.kind);
|
|
192
|
+
if (solver?.keepsBodiesAwake !== true || joint.broken)
|
|
193
|
+
continue;
|
|
194
|
+
if (solver.usesBodyA !== false)
|
|
195
|
+
keepBodyAwake(world, joint.bodyA);
|
|
196
|
+
keepBodyAwake(world, joint.bodyB);
|
|
197
|
+
}
|
|
198
|
+
// The island's timer is the MINIMUM across its members: the least-settled body decides.
|
|
199
|
+
for (let bodyIndex = 0; bodyIndex < bodies.length; bodyIndex += 1) {
|
|
200
|
+
const body = bodies[bodyIndex];
|
|
201
|
+
if (body.type === 'static')
|
|
202
|
+
continue;
|
|
203
|
+
const root = islandRootOf(parents, body.index);
|
|
204
|
+
const current = islandTimers.get(root);
|
|
205
|
+
islandTimers.set(root, current === undefined ? body.sleepTimer : Math.min(current, body.sleepTimer));
|
|
206
|
+
}
|
|
207
|
+
for (let bodyIndex = 0; bodyIndex < bodies.length; bodyIndex += 1) {
|
|
208
|
+
const body = bodies[bodyIndex];
|
|
209
|
+
if (body.type === 'static')
|
|
210
|
+
continue;
|
|
211
|
+
const islandTimer = islandTimers.get(islandRootOf(parents, body.index)) ?? body.sleepTimer;
|
|
212
|
+
const shouldSleep = body.sleepEnabled && islandTimer >= config.timeToSleep;
|
|
213
|
+
if (!shouldSleep && body.sleeping) {
|
|
214
|
+
// Waking clears the timer so a woken island must earn its rest again from zero rather than
|
|
215
|
+
// falling straight back asleep on the next step.
|
|
216
|
+
body.sleepTimer = 0;
|
|
217
|
+
}
|
|
218
|
+
body.sleeping = shouldSleep;
|
|
219
|
+
if (shouldSleep) {
|
|
220
|
+
// Zeroed rather than merely small. A sleeping body is not integrated, so any residual velocity is
|
|
221
|
+
// motion that will be silently resumed the moment it wakes — a crate that settled ten steps ago
|
|
222
|
+
// would twitch on waking. Zeroing also makes the stillness test trivially true next step, so a
|
|
223
|
+
// body cannot oscillate across the threshold while asleep.
|
|
224
|
+
body.velocityX = 0;
|
|
225
|
+
body.velocityY = 0;
|
|
226
|
+
body.velocityZ = 0;
|
|
227
|
+
body.angularVelocityX = 0;
|
|
228
|
+
body.angularVelocityY = 0;
|
|
229
|
+
body.angularVelocityZ = 0;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function copyIslandStarts(cursors, starts) {
|
|
234
|
+
cursors.length = starts.length;
|
|
235
|
+
for (let i = 0; i < starts.length; i += 1)
|
|
236
|
+
cursors[i] = starts[i];
|
|
237
|
+
}
|
|
238
|
+
// A body the solver can still move: dynamic or kinematic, and awake. Static bodies are never live —
|
|
239
|
+
// their inverse mass is zero, so an impulse against them changes nothing regardless of sleep state.
|
|
240
|
+
function isBodyLive(body) {
|
|
241
|
+
return body.type !== 'static' && !body.sleeping;
|
|
242
|
+
}
|
|
243
|
+
function isBodyStill(body, linearThreshold, angularThreshold) {
|
|
244
|
+
// A body someone has applied force or torque to is not at rest, whatever its velocity currently
|
|
245
|
+
// reads. Velocity alone would miss it: force is applied during the step, so a sleeper skips the
|
|
246
|
+
// integration that would have turned it into motion, and the force is cleared at the end of the step —
|
|
247
|
+
// the push would be silently swallowed and the body would stay asleep under continuous load.
|
|
248
|
+
if (body.forceX !== 0 || body.forceY !== 0 || body.forceZ !== 0)
|
|
249
|
+
return false;
|
|
250
|
+
if (body.torqueX !== 0 || body.torqueY !== 0 || body.torqueZ !== 0)
|
|
251
|
+
return false;
|
|
252
|
+
const speedSquared = body.velocityX * body.velocityX + body.velocityY * body.velocityY + body.velocityZ * body.velocityZ;
|
|
253
|
+
if (speedSquared > linearThreshold * linearThreshold)
|
|
254
|
+
return false;
|
|
255
|
+
// Compared as a magnitude, not per axis. Three axes each just under the threshold describe a body
|
|
256
|
+
// tumbling at sqrt(3) times it, which per-axis tests would call still.
|
|
257
|
+
const angularSquared = body.angularVelocityX * body.angularVelocityX +
|
|
258
|
+
body.angularVelocityY * body.angularVelocityY +
|
|
259
|
+
body.angularVelocityZ * body.angularVelocityZ;
|
|
260
|
+
return angularSquared <= angularThreshold * angularThreshold;
|
|
261
|
+
}
|
|
262
|
+
function islandItemCount(starts, counts) {
|
|
263
|
+
const last = counts.length - 1;
|
|
264
|
+
return last < 0 ? 0 : starts[last] + counts[last];
|
|
265
|
+
}
|
|
266
|
+
// Union-find with path compression. An index with no entry is its own root, so a body touching nothing
|
|
267
|
+
// is an island of one without needing to be inserted first.
|
|
268
|
+
function islandRootOf(parents, index) {
|
|
269
|
+
let root = index;
|
|
270
|
+
for (;;) {
|
|
271
|
+
const parent = parents.get(root);
|
|
272
|
+
if (parent === undefined || parent === root)
|
|
273
|
+
break;
|
|
274
|
+
root = parent;
|
|
275
|
+
}
|
|
276
|
+
let walk = index;
|
|
277
|
+
for (;;) {
|
|
278
|
+
const parent = parents.get(walk);
|
|
279
|
+
if (parent === undefined || parent === walk)
|
|
280
|
+
break;
|
|
281
|
+
parents.set(walk, root);
|
|
282
|
+
walk = parent;
|
|
283
|
+
}
|
|
284
|
+
return root;
|
|
285
|
+
}
|
|
286
|
+
function keepBodyAwake(world, bodyIndex) {
|
|
287
|
+
const body = findPhysics3DBody(world, bodyIndex);
|
|
288
|
+
if (body !== null && body.type !== 'static')
|
|
289
|
+
body.sleepTimer = 0;
|
|
290
|
+
}
|
|
291
|
+
function prepareIslandSlices(starts, counts, cursors) {
|
|
292
|
+
starts.length = counts.length;
|
|
293
|
+
cursors.length = counts.length;
|
|
294
|
+
let start = 0;
|
|
295
|
+
for (let i = 0; i < counts.length; i += 1) {
|
|
296
|
+
starts[i] = start;
|
|
297
|
+
start += counts[i];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function solveIslandForBody(world, bodyIndex) {
|
|
301
|
+
const body = findPhysics3DBody(world, bodyIndex);
|
|
302
|
+
if (body === null || body.type === 'static' || body.sleeping)
|
|
303
|
+
return -1;
|
|
304
|
+
return world.solveIslandByRoot.get(islandRootOf(world.islandParents, body.index)) ?? -1;
|
|
305
|
+
}
|
|
306
|
+
function solveIslandForPair(world, bodyA, bodyB) {
|
|
307
|
+
const islandA = solveIslandForBody(world, bodyA);
|
|
308
|
+
if (islandA >= 0)
|
|
309
|
+
return islandA;
|
|
310
|
+
return solveIslandForBody(world, bodyB);
|
|
311
|
+
}
|
|
312
|
+
// Joins two bodies into one island, but only when BOTH are dynamic. A static body is not a member of
|
|
313
|
+
// any island, so it cannot act as a bridge — otherwise the ground would merge every stack in the level
|
|
314
|
+
// into a single island that sleeps only when nothing anywhere is moving.
|
|
315
|
+
//
|
|
316
|
+
// Kinematic bodies deliberately do NOT break islands, even though the solver cannot move them either.
|
|
317
|
+
// A kinematic body joins the islands it touches, and a moving one has its stillness timer reset every
|
|
318
|
+
// step, so the island minimum stays zero and everything riding it stays awake. Excluding it the way
|
|
319
|
+
// static bodies are excluded would let a crate fall asleep on a lift that is still travelling.
|
|
320
|
+
function unionDynamicPair(world, parents, a, b) {
|
|
321
|
+
const first = findPhysics3DBody(world, a);
|
|
322
|
+
const second = findPhysics3DBody(world, b);
|
|
323
|
+
if (first === null || second === null)
|
|
324
|
+
return;
|
|
325
|
+
if (first.type === 'static' || second.type === 'static')
|
|
326
|
+
return;
|
|
327
|
+
const rootA = islandRootOf(parents, a);
|
|
328
|
+
const rootB = islandRootOf(parents, b);
|
|
329
|
+
if (rootA !== rootB)
|
|
330
|
+
parents.set(rootA, rootB);
|
|
331
|
+
}
|
|
332
|
+
let physics3DJointResolutionGuard = null;
|
|
333
|
+
//# sourceMappingURL=islands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"islands.js","sourceRoot":"","sources":["../src/islands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Physics3DJoint, Physics3DWorld } from '@flighthq/types/contract';
|
|
2
|
+
export declare function breakPhysics3DJoint(world: Physics3DWorld, joint: Physics3DJoint): void;
|
|
3
|
+
export declare function evaluatePhysics3DJointBreakage(world: Physics3DWorld, dt: number): void;
|
|
4
|
+
export declare function isPhysics3DJointBreakable(joint: Readonly<Physics3DJoint>): boolean;
|
|
5
|
+
//# sourceMappingURL=jointBreakage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jointBreakage.d.ts","sourceRoot":"","sources":["../src/jointBreakage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAoB/E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAItF;AAQD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAYtF;AAID,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAElF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createPhysics3DJointReaction, getPhysics3DJointReactionForce, getPhysics3DJointReactionTorque, writePhysics3DJointReaction, } from './jointReaction';
|
|
2
|
+
// Breaking a joint under load. A rope that parts, a hinge torn off its frame, a weld that fails.
|
|
3
|
+
//
|
|
4
|
+
// Read from the same reaction a caller can query, rather than from a private measurement, so the number
|
|
5
|
+
// a threshold fires on is the number the caller can inspect BEFORE it fires. A break that could not have
|
|
6
|
+
// been predicted from the public API would be untunable.
|
|
7
|
+
// Marks a joint broken and records it, whatever its load. The manual door into the same state the
|
|
8
|
+
// threshold produces, for a caller cutting a rope on cue rather than by force.
|
|
9
|
+
//
|
|
10
|
+
// Idempotent, because the event list is a record of TRANSITIONS: breaking an already-broken joint a
|
|
11
|
+
// second time would report a second break that never happened.
|
|
12
|
+
export function breakPhysics3DJoint(world, joint) {
|
|
13
|
+
if (joint.broken)
|
|
14
|
+
return;
|
|
15
|
+
joint.broken = true;
|
|
16
|
+
world.jointEvents.broke.push(joint);
|
|
17
|
+
}
|
|
18
|
+
// Tests every joint's load against its own thresholds and breaks those that exceed either.
|
|
19
|
+
//
|
|
20
|
+
// Runs where the impulses are FINAL — after the velocity iterations of the sub-interval that produced
|
|
21
|
+
// them, and before the next sub-interval overwrites them. Testing earlier reads a partly converged
|
|
22
|
+
// accumulator and breaks joints that would have held, which presents as thresholds that drift with the
|
|
23
|
+
// solver's iteration count rather than with the load.
|
|
24
|
+
export function evaluatePhysics3DJointBreakage(world, dt) {
|
|
25
|
+
for (const joint of world.joints) {
|
|
26
|
+
if (joint.broken)
|
|
27
|
+
continue;
|
|
28
|
+
if (!isPhysics3DJointBreakable(joint))
|
|
29
|
+
continue;
|
|
30
|
+
if (!writePhysics3DJointReaction(world, joint, dt, breakageReaction))
|
|
31
|
+
continue;
|
|
32
|
+
if (getPhysics3DJointReactionForce(breakageReaction) > joint.breakForce ||
|
|
33
|
+
getPhysics3DJointReactionTorque(breakageReaction) > joint.breakTorque) {
|
|
34
|
+
breakPhysics3DJoint(world, joint);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Whether a joint could break at all. Checked before the reaction is measured, because the overwhelming
|
|
39
|
+
// majority of joints are unbreakable and a reaction is real arithmetic per joint per sub-interval.
|
|
40
|
+
export function isPhysics3DJointBreakable(joint) {
|
|
41
|
+
return Number.isFinite(joint.breakForce) || Number.isFinite(joint.breakTorque);
|
|
42
|
+
}
|
|
43
|
+
const breakageReaction = createPhysics3DJointReaction();
|
|
44
|
+
//# sourceMappingURL=jointBreakage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jointBreakage.js","sourceRoot":"","sources":["../src/jointBreakage.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,EAC9B,+BAA+B,EAC/B,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAEzB,iGAAiG;AACjG,EAAE;AACF,wGAAwG;AACxG,yGAAyG;AACzG,yDAAyD;AAEzD,kGAAkG;AAClG,+EAA+E;AAC/E,EAAE;AACF,oGAAoG;AACpG,+DAA+D;AAC/D,MAAM,UAAU,mBAAmB,CAAC,KAAqB,EAAE,KAAqB;IAC9E,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO;IACzB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,2FAA2F;AAC3F,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,uGAAuG;AACvG,sDAAsD;AACtD,MAAM,UAAU,8BAA8B,CAAC,KAAqB,EAAE,EAAU;IAC9E,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,MAAM;YAAE,SAAS;QAC3B,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC;YAAE,SAAS;QAChD,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,gBAAgB,CAAC;YAAE,SAAS;QAC/E,IACE,8BAA8B,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC,UAAU;YACnE,+BAA+B,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC,WAAW,EACrE,CAAC;YACD,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,mGAAmG;AACnG,MAAM,UAAU,yBAAyB,CAAC,KAA+B;IACvE,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,gBAAgB,GAAG,4BAA4B,EAAE,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Physics3DWorld } from '@flighthq/types/contract';
|
|
2
|
+
export declare function isPhysics3DPairJointSuppressed(world: Readonly<Physics3DWorld>, bodyA: number, bodyB: number): boolean;
|
|
3
|
+
export declare function rebuildPhysics3DJointCollisionSuppressions(world: Physics3DWorld): void;
|
|
4
|
+
//# sourceMappingURL=jointCollisionSuppression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jointCollisionSuppression.d.ts","sourceRoot":"","sources":["../src/jointCollisionSuppression.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIrH;AAYD,wBAAgB,0CAA0C,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAmBtF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Constant-time lookup for whether any active joint suppresses collision between a body pair. A broadphase
|
|
2
|
+
// asks this once per candidate pair, so it has to be a lookup rather than a scan of the joint list.
|
|
3
|
+
export function isPhysics3DPairJointSuppressed(world, bodyA, bodyB) {
|
|
4
|
+
const first = Math.min(bodyA, bodyB);
|
|
5
|
+
const second = Math.max(bodyA, bodyB);
|
|
6
|
+
return (world.jointCollisionSuppressions.get(first)?.get(second) ?? 0) > 0;
|
|
7
|
+
}
|
|
8
|
+
// Rebuilds the suppression index from the joint list. Called at every lifecycle and invalidation boundary,
|
|
9
|
+
// where the work is O(joints) once, rather than during the step, where the question is asked O(pairs) times.
|
|
10
|
+
//
|
|
11
|
+
// Rebuilding wholesale is also what makes explicit invalidation sufficient after a caller edits a joint's
|
|
12
|
+
// endpoints or `collideConnected` in place: there is no per-joint shadow state that could still describe the
|
|
13
|
+
// pair the joint used to connect.
|
|
14
|
+
//
|
|
15
|
+
// The nested value is a REFERENCE COUNT, not a flag. Two joints may connect the same pair — a hinge plus a
|
|
16
|
+
// motor-bearing slider on the same hinge line — and removing one of them must not re-enable a collision the
|
|
17
|
+
// other still suppresses.
|
|
18
|
+
export function rebuildPhysics3DJointCollisionSuppressions(world) {
|
|
19
|
+
const suppressions = world.jointCollisionSuppressions;
|
|
20
|
+
suppressions.clear();
|
|
21
|
+
for (const joint of world.joints) {
|
|
22
|
+
if (joint.collideConnected)
|
|
23
|
+
continue;
|
|
24
|
+
// A joint whose kind has no registered solver constrains nothing, and a one-body kind never reads
|
|
25
|
+
// bodyA — in both cases the pair is not actually held together, so suppressing its collision would hide
|
|
26
|
+
// a contact for no reason.
|
|
27
|
+
const solver = world.jointSolvers.get(joint.kind);
|
|
28
|
+
if (solver === undefined || solver.usesBodyA === false)
|
|
29
|
+
continue;
|
|
30
|
+
const first = Math.min(joint.bodyA, joint.bodyB);
|
|
31
|
+
const second = Math.max(joint.bodyA, joint.bodyB);
|
|
32
|
+
let seconds = suppressions.get(first);
|
|
33
|
+
if (seconds === undefined) {
|
|
34
|
+
seconds = new Map();
|
|
35
|
+
suppressions.set(first, seconds);
|
|
36
|
+
}
|
|
37
|
+
seconds.set(second, (seconds.get(second) ?? 0) + 1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=jointCollisionSuppression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jointCollisionSuppression.js","sourceRoot":"","sources":["../src/jointCollisionSuppression.ts"],"names":[],"mappings":"AAEA,2GAA2G;AAC3G,oGAAoG;AACpG,MAAM,UAAU,8BAA8B,CAAC,KAA+B,EAAE,KAAa,EAAE,KAAa;IAC1G,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7E,CAAC;AAED,2GAA2G;AAC3G,6GAA6G;AAC7G,EAAE;AACF,0GAA0G;AAC1G,6GAA6G;AAC7G,kCAAkC;AAClC,EAAE;AACF,2GAA2G;AAC3G,4GAA4G;AAC5G,0BAA0B;AAC1B,MAAM,UAAU,0CAA0C,CAAC,KAAqB;IAC9E,MAAM,YAAY,GAAG,KAAK,CAAC,0BAA0B,CAAC;IACtD,YAAY,CAAC,KAAK,EAAE,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,gBAAgB;YAAE,SAAS;QACrC,kGAAkG;QAClG,wGAAwG;QACxG,2BAA2B;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK;YAAE,SAAS;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;YACpB,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Physics3DBallAndSocketJoint, Physics3DBallAndSocketJointOptions, Physics3DConeTwistJoint, Physics3DConeTwistJointOptions, Physics3DDistanceJoint, Physics3DDistanceJointOptions, Physics3DFixedJoint, Physics3DFixedJointOptions, Physics3DGeneric6DofJoint, Physics3DGeneric6DofJointOptions, Physics3DHingeJoint, Physics3DHingeJointOptions, Physics3DSliderJoint, Physics3DSliderJointOptions } from '@flighthq/types/contract';
|
|
2
|
+
export declare function createPhysics3DBallAndSocketJoint(options: Readonly<Physics3DBallAndSocketJointOptions>): Physics3DBallAndSocketJoint;
|
|
3
|
+
export declare function createPhysics3DConeTwistJoint(options: Readonly<Physics3DConeTwistJointOptions>): Physics3DConeTwistJoint;
|
|
4
|
+
export declare function createPhysics3DDistanceJoint(options: Readonly<Physics3DDistanceJointOptions>): Physics3DDistanceJoint;
|
|
5
|
+
export declare function createPhysics3DFixedJoint(options: Readonly<Physics3DFixedJointOptions>): Physics3DFixedJoint;
|
|
6
|
+
export declare function createPhysics3DGeneric6DofJoint(options: Readonly<Physics3DGeneric6DofJointOptions>): Physics3DGeneric6DofJoint;
|
|
7
|
+
export declare function createPhysics3DHingeJoint(options: Readonly<Physics3DHingeJointOptions>): Physics3DHingeJoint;
|
|
8
|
+
export declare function createPhysics3DSliderJoint(options: Readonly<Physics3DSliderJointOptions>): Physics3DSliderJoint;
|
|
9
|
+
//# sourceMappingURL=jointFactories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jointFactories.d.ts","sourceRoot":"","sources":["../src/jointFactories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAC3B,kCAAkC,EAClC,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,6BAA6B,EAC7B,mBAAmB,EACnB,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,mBAAmB,EACnB,0BAA0B,EAK1B,oBAAoB,EACpB,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAkBlC,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,QAAQ,CAAC,kCAAkC,CAAC,GACpD,2BAA2B,CAE7B;AAKD,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,QAAQ,CAAC,8BAA8B,CAAC,GAChD,uBAAuB,CAkBzB;AAKD,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,QAAQ,CAAC,6BAA6B,CAAC,GAAG,sBAAsB,CAcrH;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,QAAQ,CAAC,0BAA0B,CAAC,GAAG,mBAAmB,CAE5G;AAKD,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,QAAQ,CAAC,gCAAgC,CAAC,GAClD,yBAAyB,CAuB3B;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,QAAQ,CAAC,0BAA0B,CAAC,GAAG,mBAAmB,CAkB5G;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,QAAQ,CAAC,2BAA2B,CAAC,GAAG,oBAAoB,CAkB/G"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Physics3DBallAndSocketJointKind, Physics3DConeTwistJointKind, Physics3DDistanceJointKind, Physics3DFixedJointKind, Physics3DGeneric6DofJointKind, Physics3DHingeJointKind, Physics3DSliderJointKind, } from './joints';
|
|
2
|
+
// Joint factories allocate plain data, take one readonly options object, and make only authoring choices.
|
|
3
|
+
// Registration and world membership stay explicit operations, so constructing a joint links no solver math
|
|
4
|
+
// and touches no world.
|
|
5
|
+
//
|
|
6
|
+
// The two shared helpers are also the boundary that keeps solver-owned cache out of every public options
|
|
7
|
+
// type: a caller names anchors, frames, and limits, and never the accumulators.
|
|
8
|
+
export function createPhysics3DBallAndSocketJoint(options) {
|
|
9
|
+
return { kind: Physics3DBallAndSocketJointKind, ...createJointBase(options) };
|
|
10
|
+
}
|
|
11
|
+
// Defaults to a cone of 45 degrees in both directions and a free twist. A cone-twist with no limits at all is
|
|
12
|
+
// a ball-and-socket that costs more, so the swing limit defaults ON and the twist limit — which has no
|
|
13
|
+
// natural neutral range — defaults off.
|
|
14
|
+
export function createPhysics3DConeTwistJoint(options) {
|
|
15
|
+
return {
|
|
16
|
+
kind: Physics3DConeTwistJointKind,
|
|
17
|
+
...createJointBase(options),
|
|
18
|
+
...createJointFrames(options),
|
|
19
|
+
enableSwingLimit: options.enableSwingLimit ?? true,
|
|
20
|
+
swingLimitY: options.swingLimitY ?? Math.PI / 4,
|
|
21
|
+
swingLimitZ: options.swingLimitZ ?? Math.PI / 4,
|
|
22
|
+
enableTwistLimit: options.enableTwistLimit ?? false,
|
|
23
|
+
lowerTwistAngle: options.lowerTwistAngle ?? 0,
|
|
24
|
+
upperTwistAngle: options.upperTwistAngle ?? 0,
|
|
25
|
+
enableLimitSpring: options.enableLimitSpring ?? false,
|
|
26
|
+
limitFrequencyHz: options.limitFrequencyHz ?? 0,
|
|
27
|
+
limitDampingRatio: options.limitDampingRatio ?? 0,
|
|
28
|
+
swingLimitImpulse: 0,
|
|
29
|
+
lowerTwistImpulse: 0,
|
|
30
|
+
upperTwistImpulse: 0,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Defaults to a RIGID strut: no spring, no limit, and a rest length of zero, which holds the two anchors
|
|
34
|
+
// coincident until a caller names a length. The limit interval defaults to `[0, Infinity]` so that switching
|
|
35
|
+
// `enableLimit` on alone gives a rope with no stated bound rather than one pinned to zero length.
|
|
36
|
+
export function createPhysics3DDistanceJoint(options) {
|
|
37
|
+
return {
|
|
38
|
+
kind: Physics3DDistanceJointKind,
|
|
39
|
+
...createJointBase(options),
|
|
40
|
+
length: options.length ?? 0,
|
|
41
|
+
enableSpring: options.enableSpring ?? false,
|
|
42
|
+
frequencyHz: options.frequencyHz ?? 0,
|
|
43
|
+
dampingRatio: options.dampingRatio ?? 0,
|
|
44
|
+
enableLimit: options.enableLimit ?? false,
|
|
45
|
+
minLength: options.minLength ?? 0,
|
|
46
|
+
maxLength: options.maxLength ?? Number.POSITIVE_INFINITY,
|
|
47
|
+
lowerLimitImpulse: 0,
|
|
48
|
+
upperLimitImpulse: 0,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function createPhysics3DFixedJoint(options) {
|
|
52
|
+
return { kind: Physics3DFixedJointKind, ...createJointBase(options), ...createJointFrames(options) };
|
|
53
|
+
}
|
|
54
|
+
// Defaults every axis to FREE, so a joint built with no bounds constrains nothing and each axis is opted into
|
|
55
|
+
// by naming its interval. The alternative — defaulting to locked — would make a partially configured joint
|
|
56
|
+
// silently rigid, which is the harder failure to see.
|
|
57
|
+
export function createPhysics3DGeneric6DofJoint(options) {
|
|
58
|
+
return {
|
|
59
|
+
kind: Physics3DGeneric6DofJointKind,
|
|
60
|
+
...createJointBase(options),
|
|
61
|
+
...createJointFrames(options),
|
|
62
|
+
lowerLinearX: options.lowerLinearX ?? 1,
|
|
63
|
+
lowerLinearY: options.lowerLinearY ?? 1,
|
|
64
|
+
lowerLinearZ: options.lowerLinearZ ?? 1,
|
|
65
|
+
upperLinearX: options.upperLinearX ?? -1,
|
|
66
|
+
upperLinearY: options.upperLinearY ?? -1,
|
|
67
|
+
upperLinearZ: options.upperLinearZ ?? -1,
|
|
68
|
+
lowerAngularX: options.lowerAngularX ?? 1,
|
|
69
|
+
lowerAngularY: options.lowerAngularY ?? 1,
|
|
70
|
+
lowerAngularZ: options.lowerAngularZ ?? 1,
|
|
71
|
+
upperAngularX: options.upperAngularX ?? -1,
|
|
72
|
+
upperAngularY: options.upperAngularY ?? -1,
|
|
73
|
+
upperAngularZ: options.upperAngularZ ?? -1,
|
|
74
|
+
enableLimitSpring: options.enableLimitSpring ?? false,
|
|
75
|
+
limitFrequencyHz: options.limitFrequencyHz ?? 0,
|
|
76
|
+
limitDampingRatio: options.limitDampingRatio ?? 0,
|
|
77
|
+
lowerLimitImpulses: [0, 0, 0, 0, 0, 0],
|
|
78
|
+
upperLimitImpulses: [0, 0, 0, 0, 0, 0],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function createPhysics3DHingeJoint(options) {
|
|
82
|
+
return {
|
|
83
|
+
kind: Physics3DHingeJointKind,
|
|
84
|
+
...createJointBase(options),
|
|
85
|
+
...createJointFrames(options),
|
|
86
|
+
enableLimit: options.enableLimit ?? false,
|
|
87
|
+
lowerAngle: options.lowerAngle ?? 0,
|
|
88
|
+
upperAngle: options.upperAngle ?? 0,
|
|
89
|
+
enableMotor: options.enableMotor ?? false,
|
|
90
|
+
motorSpeed: options.motorSpeed ?? 0,
|
|
91
|
+
maxMotorTorque: options.maxMotorTorque ?? 0,
|
|
92
|
+
enableLimitSpring: options.enableLimitSpring ?? false,
|
|
93
|
+
limitFrequencyHz: options.limitFrequencyHz ?? 0,
|
|
94
|
+
limitDampingRatio: options.limitDampingRatio ?? 0,
|
|
95
|
+
motorImpulse: 0,
|
|
96
|
+
lowerLimitImpulse: 0,
|
|
97
|
+
upperLimitImpulse: 0,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function createPhysics3DSliderJoint(options) {
|
|
101
|
+
return {
|
|
102
|
+
kind: Physics3DSliderJointKind,
|
|
103
|
+
...createJointBase(options),
|
|
104
|
+
...createJointFrames(options),
|
|
105
|
+
enableLimit: options.enableLimit ?? false,
|
|
106
|
+
lowerTranslation: options.lowerTranslation ?? 0,
|
|
107
|
+
upperTranslation: options.upperTranslation ?? 0,
|
|
108
|
+
enableMotor: options.enableMotor ?? false,
|
|
109
|
+
motorSpeed: options.motorSpeed ?? 0,
|
|
110
|
+
maxMotorForce: options.maxMotorForce ?? 0,
|
|
111
|
+
enableLimitSpring: options.enableLimitSpring ?? false,
|
|
112
|
+
limitFrequencyHz: options.limitFrequencyHz ?? 0,
|
|
113
|
+
limitDampingRatio: options.limitDampingRatio ?? 0,
|
|
114
|
+
motorImpulse: 0,
|
|
115
|
+
lowerLimitImpulse: 0,
|
|
116
|
+
upperLimitImpulse: 0,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function createJointBase(options) {
|
|
120
|
+
return {
|
|
121
|
+
bodyA: options.bodyA,
|
|
122
|
+
bodyB: options.bodyB,
|
|
123
|
+
localAnchorAX: options.localAnchorAX ?? 0,
|
|
124
|
+
localAnchorAY: options.localAnchorAY ?? 0,
|
|
125
|
+
localAnchorAZ: options.localAnchorAZ ?? 0,
|
|
126
|
+
localAnchorBX: options.localAnchorBX ?? 0,
|
|
127
|
+
localAnchorBY: options.localAnchorBY ?? 0,
|
|
128
|
+
localAnchorBZ: options.localAnchorBZ ?? 0,
|
|
129
|
+
collideConnected: options.collideConnected ?? false,
|
|
130
|
+
breakForce: options.breakForce ?? Number.POSITIVE_INFINITY,
|
|
131
|
+
breakTorque: options.breakTorque ?? Number.POSITIVE_INFINITY,
|
|
132
|
+
broken: false,
|
|
133
|
+
impulse0: 0,
|
|
134
|
+
impulse1: 0,
|
|
135
|
+
impulse2: 0,
|
|
136
|
+
impulse3: 0,
|
|
137
|
+
impulse4: 0,
|
|
138
|
+
impulse5: 0,
|
|
139
|
+
rAX: 0,
|
|
140
|
+
rAY: 0,
|
|
141
|
+
rAZ: 0,
|
|
142
|
+
rBX: 0,
|
|
143
|
+
rBY: 0,
|
|
144
|
+
rBZ: 0,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function createJointFrames(options) {
|
|
148
|
+
return {
|
|
149
|
+
localRotationAX: options.localRotationAX ?? 0,
|
|
150
|
+
localRotationAY: options.localRotationAY ?? 0,
|
|
151
|
+
localRotationAZ: options.localRotationAZ ?? 0,
|
|
152
|
+
localRotationAW: options.localRotationAW ?? 1,
|
|
153
|
+
localRotationBX: options.localRotationBX ?? 0,
|
|
154
|
+
localRotationBY: options.localRotationBY ?? 0,
|
|
155
|
+
localRotationBZ: options.localRotationBZ ?? 0,
|
|
156
|
+
localRotationBW: options.localRotationBW ?? 1,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=jointFactories.js.map
|