@codexo/exojs-physics 0.15.3 → 0.16.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 +51 -23
- package/dist/esm/Aabb.d.ts +6 -10
- package/dist/esm/Aabb.d.ts.map +1 -0
- package/dist/esm/Aabb.js +9 -5
- package/dist/esm/Aabb.js.map +1 -1
- package/dist/esm/Collider.d.ts +62 -10
- package/dist/esm/Collider.d.ts.map +1 -0
- package/dist/esm/Collider.js +263 -157
- package/dist/esm/Collider.js.map +1 -1
- package/dist/esm/ContactGraph.d.ts +51 -5
- package/dist/esm/ContactGraph.d.ts.map +1 -0
- package/dist/esm/ContactGraph.js +282 -223
- package/dist/esm/ContactGraph.js.map +1 -1
- package/dist/esm/ContactModifier.d.ts +85 -0
- package/dist/esm/ContactModifier.d.ts.map +1 -0
- package/dist/esm/ContactModifier.js +49 -0
- package/dist/esm/ContactModifier.js.map +1 -0
- package/dist/esm/PhysicsBody.d.ts +56 -22
- package/dist/esm/PhysicsBody.d.ts.map +1 -0
- package/dist/esm/PhysicsBody.js +461 -443
- package/dist/esm/PhysicsBody.js.map +1 -1
- package/dist/esm/PhysicsWorld.d.ts +276 -43
- package/dist/esm/PhysicsWorld.d.ts.map +1 -0
- package/dist/esm/PhysicsWorld.js +890 -626
- package/dist/esm/PhysicsWorld.js.map +1 -1
- package/dist/esm/TimeStepper.d.ts +3 -2
- package/dist/esm/TimeStepper.d.ts.map +1 -0
- package/dist/esm/TimeStepper.js +56 -67
- package/dist/esm/TimeStepper.js.map +1 -1
- package/dist/esm/backend/NativePhysicsBackend.d.ts +8 -4
- package/dist/esm/backend/NativePhysicsBackend.d.ts.map +1 -0
- package/dist/esm/backend/NativePhysicsBackend.js +48 -41
- package/dist/esm/backend/NativePhysicsBackend.js.map +1 -1
- package/dist/esm/backend/PhysicsBackend.d.ts +9 -2
- package/dist/esm/backend/PhysicsBackend.d.ts.map +1 -0
- package/dist/esm/binding/BindingRegistry.d.ts +25 -4
- package/dist/esm/binding/BindingRegistry.d.ts.map +1 -0
- package/dist/esm/binding/BindingRegistry.js +70 -36
- package/dist/esm/binding/BindingRegistry.js.map +1 -1
- package/dist/esm/binding/PhysicsBinding.d.ts +22 -5
- package/dist/esm/binding/PhysicsBinding.d.ts.map +1 -0
- package/dist/esm/binding/PhysicsBinding.js +46 -21
- package/dist/esm/binding/PhysicsBinding.js.map +1 -1
- package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts +68 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts.map +1 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.js +149 -0
- package/dist/esm/broadphase/AabbTreeBroadPhase.js.map +1 -0
- package/dist/esm/broadphase/BroadPhase.d.ts +7 -4
- package/dist/esm/broadphase/BroadPhase.d.ts.map +1 -0
- package/dist/esm/broadphase/index.d.ts +2 -1
- package/dist/esm/broadphase/index.d.ts.map +1 -0
- package/dist/esm/collision/CollisionProxy.d.ts +3 -2
- package/dist/esm/collision/CollisionProxy.d.ts.map +1 -0
- package/dist/esm/collision/Manifold.d.ts +5 -4
- package/dist/esm/collision/Manifold.d.ts.map +1 -0
- package/dist/esm/collision/Manifold.js +34 -25
- package/dist/esm/collision/Manifold.js.map +1 -1
- package/dist/esm/collision/chainAdjacency.d.ts +29 -0
- package/dist/esm/collision/chainAdjacency.d.ts.map +1 -0
- package/dist/esm/collision/chainAdjacency.js +44 -0
- package/dist/esm/collision/chainAdjacency.js.map +1 -0
- package/dist/esm/collision/dispatch.d.ts +35 -0
- package/dist/esm/collision/dispatch.d.ts.map +1 -0
- package/dist/esm/collision/dispatch.js +58 -0
- package/dist/esm/collision/dispatch.js.map +1 -0
- package/dist/esm/collision/index.d.ts +2 -0
- package/dist/esm/collision/index.d.ts.map +1 -0
- package/dist/esm/collision/narrowphase.d.ts +5 -2
- package/dist/esm/collision/narrowphase.d.ts.map +1 -0
- package/dist/esm/collision/narrowphase.js +524 -399
- package/dist/esm/collision/narrowphase.js.map +1 -1
- package/dist/esm/collision/segments.d.ts +19 -0
- package/dist/esm/collision/segments.d.ts.map +1 -0
- package/dist/esm/collision/segments.js +36 -0
- package/dist/esm/collision/segments.js.map +1 -0
- package/dist/esm/collision/sweep.d.ts +35 -0
- package/dist/esm/collision/sweep.d.ts.map +1 -0
- package/dist/esm/collision/sweep.js +437 -0
- package/dist/esm/collision/sweep.js.map +1 -0
- package/dist/esm/debug/PhysicsDebugDraw.d.ts +23 -4
- package/dist/esm/debug/PhysicsDebugDraw.d.ts.map +1 -0
- package/dist/esm/debug/PhysicsDebugDraw.js +230 -188
- package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
- package/dist/esm/debug/index.d.ts +1 -0
- package/dist/esm/debug/index.d.ts.map +1 -0
- package/dist/esm/debug/index.js +3 -2
- package/dist/esm/events.d.ts +1 -0
- package/dist/esm/events.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +24 -19
- package/dist/esm/joints/DistanceJoint.d.ts +4 -3
- package/dist/esm/joints/DistanceJoint.d.ts.map +1 -0
- package/dist/esm/joints/DistanceJoint.js +160 -172
- package/dist/esm/joints/DistanceJoint.js.map +1 -1
- package/dist/esm/joints/Joint.d.ts +5 -4
- package/dist/esm/joints/Joint.d.ts.map +1 -0
- package/dist/esm/joints/Joint.js +23 -21
- package/dist/esm/joints/Joint.js.map +1 -1
- package/dist/esm/joints/MouseJoint.d.ts +8 -7
- package/dist/esm/joints/MouseJoint.d.ts.map +1 -0
- package/dist/esm/joints/MouseJoint.js +132 -133
- package/dist/esm/joints/MouseJoint.js.map +1 -1
- package/dist/esm/joints/PrismaticJoint.d.ts +5 -4
- package/dist/esm/joints/PrismaticJoint.d.ts.map +1 -0
- package/dist/esm/joints/PrismaticJoint.js +211 -240
- package/dist/esm/joints/PrismaticJoint.js.map +1 -1
- package/dist/esm/joints/RevoluteJoint.d.ts +4 -3
- package/dist/esm/joints/RevoluteJoint.d.ts.map +1 -0
- package/dist/esm/joints/RevoluteJoint.js +191 -213
- package/dist/esm/joints/RevoluteJoint.js.map +1 -1
- package/dist/esm/joints/WeldJoint.d.ts +3 -2
- package/dist/esm/joints/WeldJoint.d.ts.map +1 -0
- package/dist/esm/joints/WeldJoint.js +156 -152
- package/dist/esm/joints/WeldJoint.js.map +1 -1
- package/dist/esm/joints/WheelJoint.d.ts +4 -3
- package/dist/esm/joints/WheelJoint.d.ts.map +1 -0
- package/dist/esm/joints/WheelJoint.js +228 -255
- package/dist/esm/joints/WheelJoint.js.map +1 -1
- package/dist/esm/math.d.ts +6 -9
- package/dist/esm/math.d.ts.map +1 -0
- package/dist/esm/math.js +37 -39
- package/dist/esm/math.js.map +1 -1
- package/dist/esm/physicsBuildInfo.d.ts +1 -0
- package/dist/esm/physicsBuildInfo.d.ts.map +1 -0
- package/dist/esm/physicsBuildInfo.js +6 -4
- package/dist/esm/physicsBuildInfo.js.map +1 -1
- package/dist/esm/public.d.ts +8 -3
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/query/QueryEngine.d.ts +56 -12
- package/dist/esm/query/QueryEngine.d.ts.map +1 -0
- package/dist/esm/query/QueryEngine.js +494 -237
- package/dist/esm/query/QueryEngine.js.map +1 -1
- package/dist/esm/query/SpatialIndex.d.ts +34 -0
- package/dist/esm/query/SpatialIndex.d.ts.map +1 -0
- package/dist/esm/shapes/AnyShape.d.ts +9 -4
- package/dist/esm/shapes/AnyShape.d.ts.map +1 -0
- package/dist/esm/shapes/BoxShape.d.ts +2 -1
- package/dist/esm/shapes/BoxShape.d.ts.map +1 -0
- package/dist/esm/shapes/BoxShape.js +37 -25
- package/dist/esm/shapes/BoxShape.js.map +1 -1
- package/dist/esm/shapes/CapsuleShape.d.ts +30 -0
- package/dist/esm/shapes/CapsuleShape.d.ts.map +1 -0
- package/dist/esm/shapes/CapsuleShape.js +88 -0
- package/dist/esm/shapes/CapsuleShape.js.map +1 -0
- package/dist/esm/shapes/ChainEdgeShape.d.ts +30 -0
- package/dist/esm/shapes/ChainEdgeShape.d.ts.map +1 -0
- package/dist/esm/shapes/ChainEdgeShape.js +66 -0
- package/dist/esm/shapes/ChainEdgeShape.js.map +1 -0
- package/dist/esm/shapes/ChainShape.d.ts +52 -0
- package/dist/esm/shapes/ChainShape.d.ts.map +1 -0
- package/dist/esm/shapes/ChainShape.js +85 -0
- package/dist/esm/shapes/ChainShape.js.map +1 -0
- package/dist/esm/shapes/CircleShape.d.ts +3 -4
- package/dist/esm/shapes/CircleShape.d.ts.map +1 -0
- package/dist/esm/shapes/CircleShape.js +27 -26
- package/dist/esm/shapes/CircleShape.js.map +1 -1
- package/dist/esm/shapes/PolygonShape.d.ts +7 -8
- package/dist/esm/shapes/PolygonShape.d.ts.map +1 -0
- package/dist/esm/shapes/PolygonShape.js +131 -162
- package/dist/esm/shapes/PolygonShape.js.map +1 -1
- package/dist/esm/shapes/SegmentShape.d.ts +31 -0
- package/dist/esm/shapes/SegmentShape.d.ts.map +1 -0
- package/dist/esm/shapes/SegmentShape.js +62 -0
- package/dist/esm/shapes/SegmentShape.js.map +1 -0
- package/dist/esm/shapes/Shape.d.ts +28 -17
- package/dist/esm/shapes/Shape.d.ts.map +1 -0
- package/dist/esm/shapes/Shape.js +12 -13
- package/dist/esm/shapes/Shape.js.map +1 -1
- package/dist/esm/shapes/convexParts.d.ts +21 -0
- package/dist/esm/shapes/convexParts.d.ts.map +1 -0
- package/dist/esm/shapes/convexParts.js +26 -0
- package/dist/esm/shapes/convexParts.js.map +1 -0
- package/dist/esm/shapes/decompose.d.ts +24 -0
- package/dist/esm/shapes/decompose.d.ts.map +1 -0
- package/dist/esm/shapes/decompose.js +272 -0
- package/dist/esm/shapes/decompose.js.map +1 -0
- package/dist/esm/shapes/index.d.ts +4 -0
- package/dist/esm/shapes/index.d.ts.map +1 -0
- package/dist/esm/solver/ContactSolver.d.ts +12 -5
- package/dist/esm/solver/ContactSolver.d.ts.map +1 -0
- package/dist/esm/solver/ContactSolver.js +425 -471
- package/dist/esm/solver/ContactSolver.js.map +1 -1
- package/dist/esm/solver/tolerances.d.ts +34 -0
- package/dist/esm/solver/tolerances.d.ts.map +1 -0
- package/dist/esm/solver/tolerances.js +38 -0
- package/dist/esm/solver/tolerances.js.map +1 -0
- package/dist/esm/sort.d.ts +5 -4
- package/dist/esm/sort.d.ts.map +1 -0
- package/dist/esm/sort.js +41 -51
- package/dist/esm/sort.js.map +1 -1
- package/dist/esm/types.d.ts +4 -8
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +15 -17
- package/dist/esm/types.js.map +1 -1
- package/package.json +6 -6
- package/dist/esm/broadphase/SweepAndPrune.d.ts +0 -15
- package/dist/esm/broadphase/SweepAndPrune.js +0 -77
- package/dist/esm/broadphase/SweepAndPrune.js.map +0 -1
- package/dist/esm/debug/index.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
package/dist/esm/PhysicsBody.js
CHANGED
|
@@ -1,447 +1,465 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Collider } from
|
|
3
|
-
import {
|
|
1
|
+
import { applyTransform, createTransform, setTransform } from "./math.js";
|
|
2
|
+
import { Collider } from "./Collider.js";
|
|
3
|
+
import { Vector } from "@codexo/exojs";
|
|
4
4
|
|
|
5
|
+
//#region src/PhysicsBody.ts
|
|
5
6
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
7
|
+
* A rigid body: a world transform plus mass properties aggregated from its
|
|
8
|
+
* colliders. Dynamic bodies integrate under gravity, accumulated forces/torque
|
|
9
|
+
* and contact impulses each fixed sub-step; static bodies never move; kinematic
|
|
10
|
+
* bodies move by their velocity only and stay immovable under contacts. Drive a
|
|
11
|
+
* body with {@link applyForce}, {@link applyTorque} and {@link applyImpulse}, or
|
|
12
|
+
* set {@link linearVelocityX}/{@link linearVelocityY}/{@link angularVelocity}
|
|
13
|
+
* directly; reposition it (teleport, no velocity) with {@link setTransform}.
|
|
14
|
+
*/
|
|
15
|
+
var PhysicsBody = class {
|
|
16
|
+
type;
|
|
17
|
+
/** Linear damping applied to the velocity each sub-step. */
|
|
18
|
+
linearDamping;
|
|
19
|
+
/** Angular damping applied to the angular velocity each sub-step. */
|
|
20
|
+
angularDamping;
|
|
21
|
+
/** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). */
|
|
22
|
+
gravityScale;
|
|
23
|
+
/** When `true`, rotational inertia is treated as infinite. */
|
|
24
|
+
fixedRotation;
|
|
25
|
+
/** When `true`, the body's colliders are shape-cast along each step's motion (CCD) so it cannot tunnel through thin geometry. */
|
|
26
|
+
isBullet;
|
|
27
|
+
/** Total mass (0 for static/kinematic). */
|
|
28
|
+
mass = 0;
|
|
29
|
+
/** Inverse mass (`0` = immovable). */
|
|
30
|
+
invMass = 0;
|
|
31
|
+
/** Rotational inertia about the centre of mass (0 for static/kinematic or fixed rotation). */
|
|
32
|
+
inertia = 0;
|
|
33
|
+
/** Inverse rotational inertia (`0` = no angular response). */
|
|
34
|
+
invInertia = 0;
|
|
35
|
+
/** Linear velocity X in px/s. */
|
|
36
|
+
linearVelocityX = 0;
|
|
37
|
+
/** Linear velocity Y in px/s. */
|
|
38
|
+
linearVelocityY = 0;
|
|
39
|
+
/** Angular velocity in rad/s. */
|
|
40
|
+
angularVelocity = 0;
|
|
41
|
+
/** When `false`, this body is never put to sleep. Default `true`. */
|
|
42
|
+
allowSleep = true;
|
|
43
|
+
/** @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}. */
|
|
44
|
+
_deltaPosX = 0;
|
|
45
|
+
/** @internal - Delta position Y accumulated across the frame's sub-steps by the TGS integrator. */
|
|
46
|
+
_deltaPosY = 0;
|
|
47
|
+
/** @internal - Delta rotation (radians) accumulated across the frame's sub-steps by the TGS integrator. */
|
|
48
|
+
_deltaAngle = 0;
|
|
49
|
+
/** @internal - `cos(_deltaAngle)`, cached so the solver can rotate the contact anchors by the live sub-step rotation without a per-contact trig call. */
|
|
50
|
+
_deltaCos = 1;
|
|
51
|
+
/** @internal - `sin(_deltaAngle)`, cached alongside {@link _deltaCos}. */
|
|
52
|
+
_deltaSin = 0;
|
|
53
|
+
_forceX = 0;
|
|
54
|
+
_forceY = 0;
|
|
55
|
+
_torque = 0;
|
|
56
|
+
/** @internal - seconds the body has stayed below the sleep thresholds (frozen while asleep). Read by the world's island pass. */
|
|
57
|
+
_sleepTime = 0;
|
|
58
|
+
/** @internal - dense union-find index assigned by the world's island pass each step. */
|
|
59
|
+
_islandIndex = 0;
|
|
60
|
+
/**
|
|
61
|
+
* @internal - raised by {@link setTransform}, cleared once the fixed step that
|
|
62
|
+
* saw it completes. A static/kinematic body driven by teleporting carries no
|
|
63
|
+
* velocity, so this is the world's only signal that such a body moved and its
|
|
64
|
+
* sleeping contact partners must be woken.
|
|
65
|
+
*/
|
|
66
|
+
_teleported = false;
|
|
67
|
+
/** @internal - world-space centre of mass at the start of the current fixed step (CCD swept-test origin). */
|
|
68
|
+
_ccdPrevX = 0;
|
|
69
|
+
/** @internal - see {@link _ccdPrevX}. */
|
|
70
|
+
_ccdPrevY = 0;
|
|
71
|
+
_sleeping = false;
|
|
72
|
+
_id = -1;
|
|
73
|
+
_owner = null;
|
|
74
|
+
_attached = false;
|
|
75
|
+
_transform;
|
|
76
|
+
_previousX;
|
|
77
|
+
_previousY;
|
|
78
|
+
_previousAngle;
|
|
79
|
+
_colliders = [];
|
|
80
|
+
_comX = 0;
|
|
81
|
+
_comY = 0;
|
|
82
|
+
_massReady = false;
|
|
83
|
+
_destroyed = false;
|
|
84
|
+
constructor(options = {}) {
|
|
85
|
+
this.type = options.type ?? "dynamic";
|
|
86
|
+
this._transform = createTransform(options.position?.x ?? 0, options.position?.y ?? 0, options.angle ?? 0);
|
|
87
|
+
this._previousX = this._transform.x;
|
|
88
|
+
this._previousY = this._transform.y;
|
|
89
|
+
this._previousAngle = this._transform.angle;
|
|
90
|
+
this.linearDamping = options.linearDamping ?? 0;
|
|
91
|
+
this.angularDamping = options.angularDamping ?? 0;
|
|
92
|
+
this.gravityScale = options.gravityScale ?? 1;
|
|
93
|
+
this.fixedRotation = options.fixedRotation ?? false;
|
|
94
|
+
this.isBullet = options.isBullet ?? false;
|
|
95
|
+
if (options.colliders) for (const entry of options.colliders) this._colliders.push(entry instanceof Collider ? entry : new Collider(entry));
|
|
96
|
+
}
|
|
97
|
+
/** Stable id, assigned when the body joins a world via `world.add()`; `-1` until then. */
|
|
98
|
+
get id() {
|
|
99
|
+
return this._id;
|
|
100
|
+
}
|
|
101
|
+
/** `true` once the body has been added to a world (guards against double-add). */
|
|
102
|
+
get attached() {
|
|
103
|
+
return this._attached;
|
|
104
|
+
}
|
|
105
|
+
/** World X. */
|
|
106
|
+
get x() {
|
|
107
|
+
return this._transform.x;
|
|
108
|
+
}
|
|
109
|
+
/** World Y. */
|
|
110
|
+
get y() {
|
|
111
|
+
return this._transform.y;
|
|
112
|
+
}
|
|
113
|
+
/** Rotation in radians. */
|
|
114
|
+
get angle() {
|
|
115
|
+
return this._transform.angle;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* World X at the start of the most recent fixed step. With {@link x} it
|
|
119
|
+
* brackets the last step, which is what an interpolating presentation blends
|
|
120
|
+
* between; a teleport collapses it onto {@link x}. Never read by the solver.
|
|
121
|
+
*/
|
|
122
|
+
get previousX() {
|
|
123
|
+
return this._previousX;
|
|
124
|
+
}
|
|
125
|
+
/** World Y at the start of the most recent fixed step; see {@link previousX}. */
|
|
126
|
+
get previousY() {
|
|
127
|
+
return this._previousY;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Rotation in radians at the start of the most recent fixed step; see
|
|
131
|
+
* {@link previousX}. Body angles are continuous and unbounded, never wrapped
|
|
132
|
+
* to a range, so this and {@link angle} can be blended with a plain lerp.
|
|
133
|
+
*/
|
|
134
|
+
get previousAngle() {
|
|
135
|
+
return this._previousAngle;
|
|
136
|
+
}
|
|
137
|
+
/** A fresh `Vector` copy of the body's world position. */
|
|
138
|
+
get position() {
|
|
139
|
+
return new Vector(this._transform.x, this._transform.y);
|
|
140
|
+
}
|
|
141
|
+
/** The body's world transform (read-only; mutate via {@link setTransform}). */
|
|
142
|
+
get transform() {
|
|
143
|
+
return this._transform;
|
|
144
|
+
}
|
|
145
|
+
/** The body's colliders (read-only view). */
|
|
146
|
+
get colliders() {
|
|
147
|
+
return this._colliders;
|
|
148
|
+
}
|
|
149
|
+
/** Centre of mass in body-local space (relative to the body origin). */
|
|
150
|
+
get centerOfMassX() {
|
|
151
|
+
return this._comX;
|
|
152
|
+
}
|
|
153
|
+
/** Centre of mass in body-local space (relative to the body origin). */
|
|
154
|
+
get centerOfMassY() {
|
|
155
|
+
return this._comY;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* `true` when the body is ready to simulate. Static/kinematic bodies are
|
|
159
|
+
* always ready (infinite-mass semantics); a dynamic body is ready only once
|
|
160
|
+
* it has at least one positive-density collider.
|
|
161
|
+
*/
|
|
162
|
+
get isMassReady() {
|
|
163
|
+
return this.type !== "dynamic" || this._massReady;
|
|
164
|
+
}
|
|
165
|
+
/** `true` after the owning world has destroyed this body. */
|
|
166
|
+
get destroyed() {
|
|
167
|
+
return this._destroyed;
|
|
168
|
+
}
|
|
169
|
+
/** `true` when the body is asleep - skipped by the integrator and solver until woken. */
|
|
170
|
+
get isSleeping() {
|
|
171
|
+
return this._sleeping;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Attach a collider to this body. Accepts a {@link Collider} instance or its
|
|
175
|
+
* {@link ColliderOptions} (a convenience that constructs the collider for you).
|
|
176
|
+
* When the body is already in a world, the collider is id-allocated, registered,
|
|
177
|
+
* the mass model is recomputed and the world geometry synchronised immediately;
|
|
178
|
+
* on a free-standing body the collider is simply held until `world.add()`.
|
|
179
|
+
* Returns the collider.
|
|
180
|
+
*/
|
|
181
|
+
addCollider(collider) {
|
|
182
|
+
if (this._destroyed) throw new Error("PhysicsBody: cannot add a collider to a destroyed body.");
|
|
183
|
+
const instance = collider instanceof Collider ? collider : new Collider(collider);
|
|
184
|
+
this._colliders.push(instance);
|
|
185
|
+
if (this._attached && this._owner) {
|
|
186
|
+
attachWithChainEdges(instance, this, this._owner);
|
|
187
|
+
this._recomputeMass();
|
|
188
|
+
this._assertDynamicCarriesMass();
|
|
189
|
+
instance.synchronize(this._transform);
|
|
190
|
+
this._owner._registerCollider(instance);
|
|
191
|
+
}
|
|
192
|
+
return instance;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Set the body's world transform. Resets the body's cached collider geometry
|
|
196
|
+
* immediately so subsequent queries see the new placement. Returns `this`.
|
|
197
|
+
*/
|
|
198
|
+
setTransform(position, angle = this._transform.angle) {
|
|
199
|
+
if (this._destroyed) throw new Error("PhysicsBody: cannot move a destroyed body.");
|
|
200
|
+
this.wake();
|
|
201
|
+
this._teleported = true;
|
|
202
|
+
setTransform(this._transform, position.x, position.y, angle);
|
|
203
|
+
this._previousX = this._transform.x;
|
|
204
|
+
this._previousY = this._transform.y;
|
|
205
|
+
this._previousAngle = this._transform.angle;
|
|
206
|
+
for (const collider of this._colliders) collider.synchronize(this._transform);
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
/** Refresh every collider's world geometry from the current transform. */
|
|
210
|
+
synchronizeColliders() {
|
|
211
|
+
for (const collider of this._colliders) collider.synchronize(this._transform);
|
|
212
|
+
}
|
|
213
|
+
/** World-space centre of mass X (body origin + rotated local centre of mass). */
|
|
214
|
+
get worldCenterOfMassX() {
|
|
215
|
+
return this._transform.x + this._transform.cos * this._comX - this._transform.sin * this._comY;
|
|
216
|
+
}
|
|
217
|
+
/** World-space centre of mass Y. */
|
|
218
|
+
get worldCenterOfMassY() {
|
|
219
|
+
return this._transform.y + this._transform.sin * this._comX + this._transform.cos * this._comY;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Accumulate a world-space force at the centre of mass; integrated on the next
|
|
223
|
+
* sub-step and then cleared. No-op on static/kinematic bodies. Returns `this`.
|
|
224
|
+
*/
|
|
225
|
+
applyForce(forceX, forceY) {
|
|
226
|
+
this.wake();
|
|
227
|
+
this._forceX += forceX;
|
|
228
|
+
this._forceY += forceY;
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Accumulate a torque; integrated on the next sub-step and then cleared. No-op
|
|
233
|
+
* on static/kinematic bodies (and fixed-rotation bodies). Returns `this`.
|
|
234
|
+
*/
|
|
235
|
+
applyTorque(torque) {
|
|
236
|
+
this.wake();
|
|
237
|
+
this._torque += torque;
|
|
238
|
+
return this;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Apply an instantaneous world-space impulse at `(pointX, pointY)` (world space;
|
|
242
|
+
* defaults to the centre of mass), changing velocity immediately. No-op on
|
|
243
|
+
* static/kinematic bodies (infinite mass). Returns `this`.
|
|
244
|
+
*/
|
|
245
|
+
applyImpulse(impulseX, impulseY, pointX, pointY) {
|
|
246
|
+
if (this.invMass === 0) return this;
|
|
247
|
+
this.wake();
|
|
248
|
+
this.linearVelocityX += impulseX * this.invMass;
|
|
249
|
+
this.linearVelocityY += impulseY * this.invMass;
|
|
250
|
+
if (pointX !== void 0 && pointY !== void 0 && this.invInertia !== 0) {
|
|
251
|
+
const rx = pointX - this.worldCenterOfMassX;
|
|
252
|
+
const ry = pointY - this.worldCenterOfMassY;
|
|
253
|
+
this.angularVelocity += (rx * impulseY - ry * impulseX) * this.invInertia;
|
|
254
|
+
}
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* @internal - integrate velocity from gravity, accumulated forces/torque and
|
|
259
|
+
* damping over the sub-step `h`. No-op for static/kinematic (infinite mass
|
|
260
|
+
* keeps their velocity solver-driven only). Called once per TGS sub-step, so
|
|
261
|
+
* gravity/forces are applied with `h` each sub-step (`N·h = dt`, same total
|
|
262
|
+
* impulse, but the small-step position error scales with `h²`). The
|
|
263
|
+
* force/torque accumulators are **not** cleared here - they are consumed by
|
|
264
|
+
* every sub-step and cleared once per frame by {@link _finalizePosition}.
|
|
265
|
+
*/
|
|
266
|
+
_integrateVelocity(h, gravityX, gravityY) {
|
|
267
|
+
if (this.invMass === 0 || this._sleeping) return;
|
|
268
|
+
this.linearVelocityX += (gravityX * this.gravityScale + this._forceX * this.invMass) * h;
|
|
269
|
+
this.linearVelocityY += (gravityY * this.gravityScale + this._forceY * this.invMass) * h;
|
|
270
|
+
this.angularVelocity += this._torque * this.invInertia * h;
|
|
271
|
+
this.linearVelocityX /= 1 + h * this.linearDamping;
|
|
272
|
+
this.linearVelocityY /= 1 + h * this.linearDamping;
|
|
273
|
+
this.angularVelocity /= 1 + h * this.angularDamping;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* @internal - accumulate this sub-step's velocity into the per-frame delta
|
|
277
|
+
* position/rotation (TGS sub-stepping). The transform itself is **not** moved
|
|
278
|
+
* here; {@link _finalizePosition} writes the accumulated delta once per frame.
|
|
279
|
+
* Tracking the delta (rather than moving the transform each sub-step) lets the
|
|
280
|
+
* solver recompute contact separation from it without re-running detection or
|
|
281
|
+
* re-syncing collider geometry per sub-step. Static bodies never move.
|
|
282
|
+
*/
|
|
283
|
+
_integratePosition(h) {
|
|
284
|
+
if (this.type === "static" || this._sleeping) return;
|
|
285
|
+
this._deltaPosX += this.linearVelocityX * h;
|
|
286
|
+
this._deltaPosY += this.linearVelocityY * h;
|
|
287
|
+
this._deltaAngle += this.angularVelocity * h;
|
|
288
|
+
if (this._deltaAngle !== 0) {
|
|
289
|
+
this._deltaCos = Math.cos(this._deltaAngle);
|
|
290
|
+
this._deltaSin = Math.sin(this._deltaAngle);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* @internal - advance the sleep timer over one fixed step `dt`. A body below
|
|
295
|
+
* both velocity thresholds accumulates time; a too-fast body, or one that opts
|
|
296
|
+
* out via {@link allowSleep}, resets it. The sleep/wake decision is made per
|
|
297
|
+
* island by the world (so a stack sleeps as a unit) from {@link _sleepTime}.
|
|
298
|
+
*/
|
|
299
|
+
_accumulateSleepTime(dt, linearThreshold, angularThreshold) {
|
|
300
|
+
const tooFast = this.linearVelocityX * this.linearVelocityX + this.linearVelocityY * this.linearVelocityY > linearThreshold * linearThreshold || Math.abs(this.angularVelocity) > angularThreshold;
|
|
301
|
+
this._sleepTime = !this.allowSleep || tooFast ? 0 : this._sleepTime + dt;
|
|
302
|
+
}
|
|
303
|
+
/** @internal - set the sleep state. Sleeping zeroes the velocity; waking resets the sleep timer. */
|
|
304
|
+
_setSleeping(sleeping) {
|
|
305
|
+
if (this._sleeping === sleeping) return;
|
|
306
|
+
this._sleeping = sleeping;
|
|
307
|
+
if (sleeping) {
|
|
308
|
+
this.linearVelocityX = 0;
|
|
309
|
+
this.linearVelocityY = 0;
|
|
310
|
+
this.angularVelocity = 0;
|
|
311
|
+
} else this._sleepTime = 0;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Wake the body if it is asleep, resetting its sleep timer. The rest of its
|
|
315
|
+
* island wakes with it on the next step (a contact to an awake body keeps the
|
|
316
|
+
* whole island awake). Returns `this`.
|
|
317
|
+
*/
|
|
318
|
+
wake() {
|
|
319
|
+
this._setSleeping(false);
|
|
320
|
+
this._sleepTime = 0;
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* @internal - apply the frame's accumulated delta position/rotation to the
|
|
325
|
+
* transform (rotating about the centre of mass), re-sync collider geometry and
|
|
326
|
+
* clear the force/torque accumulators. Called once per frame after the
|
|
327
|
+
* sub-step loop. Static bodies never move; the force clear still runs (forces
|
|
328
|
+
* are a no-op on infinite mass but the accumulator is reset for consistency).
|
|
329
|
+
*/
|
|
330
|
+
_finalizePosition() {
|
|
331
|
+
this._forceX = 0;
|
|
332
|
+
this._forceY = 0;
|
|
333
|
+
this._torque = 0;
|
|
334
|
+
this._teleported = false;
|
|
335
|
+
this._previousX = this._transform.x;
|
|
336
|
+
this._previousY = this._transform.y;
|
|
337
|
+
this._previousAngle = this._transform.angle;
|
|
338
|
+
if (this.type === "static" || this._deltaPosX === 0 && this._deltaPosY === 0 && this._deltaAngle === 0) {
|
|
339
|
+
this._resetDelta();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const newComX = this.worldCenterOfMassX + this._deltaPosX;
|
|
343
|
+
const newComY = this.worldCenterOfMassY + this._deltaPosY;
|
|
344
|
+
const newAngle = this._transform.angle + this._deltaAngle;
|
|
345
|
+
const cos = Math.cos(newAngle);
|
|
346
|
+
const sin = Math.sin(newAngle);
|
|
347
|
+
setTransform(this._transform, newComX - (cos * this._comX - sin * this._comY), newComY - (sin * this._comX + cos * this._comY), newAngle);
|
|
348
|
+
this._resetDelta();
|
|
349
|
+
for (const collider of this._colliders) collider.synchronize(this._transform);
|
|
350
|
+
}
|
|
351
|
+
/** Clear the per-frame TGS delta accumulators (position, rotation and its cached cos/sin). */
|
|
352
|
+
_resetDelta() {
|
|
353
|
+
this._deltaPosX = 0;
|
|
354
|
+
this._deltaPosY = 0;
|
|
355
|
+
this._deltaAngle = 0;
|
|
356
|
+
this._deltaCos = 1;
|
|
357
|
+
this._deltaSin = 0;
|
|
358
|
+
}
|
|
359
|
+
/** Internal: detach a collider (called by the world during destruction). */
|
|
360
|
+
_removeCollider(collider) {
|
|
361
|
+
const index = this._colliders.indexOf(collider);
|
|
362
|
+
if (index !== -1) {
|
|
363
|
+
this._colliders.splice(index, 1);
|
|
364
|
+
this._recomputeMass();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* @internal - join `owner`'s world with the allocated `id`. Allocates ids for
|
|
369
|
+
* and registers every held collider, then aggregates the mass model and
|
|
370
|
+
* synchronises world geometry. Called once by {@link PhysicsWorld.add}.
|
|
371
|
+
*
|
|
372
|
+
* Ordering matters and mirrors the per-collider create path exactly: ids and
|
|
373
|
+
* the body link go on first, then a single mass recompute over the full
|
|
374
|
+
* collider set (so the centre of mass / inertia aggregate is correct), then
|
|
375
|
+
* `synchronize` over every collider (the cached world geometry the broad/narrow
|
|
376
|
+
* phase reads), then world registration last. Recomputing mass before all
|
|
377
|
+
* colliders are linked, or syncing before the mass model exists, would feed the
|
|
378
|
+
* solver a stale CoM and produce subtle integration bugs.
|
|
379
|
+
*/
|
|
380
|
+
_attachToWorld(owner, id) {
|
|
381
|
+
if (this._destroyed) throw new Error("PhysicsBody: cannot add a destroyed body to a world.");
|
|
382
|
+
this._owner = owner;
|
|
383
|
+
this._id = id;
|
|
384
|
+
this._attached = true;
|
|
385
|
+
for (const collider of this._colliders) attachWithChainEdges(collider, this, owner);
|
|
386
|
+
this._recomputeMass();
|
|
387
|
+
this._assertDynamicCarriesMass();
|
|
388
|
+
for (const collider of this._colliders) collider.synchronize(this._transform);
|
|
389
|
+
for (const collider of this._colliders) owner._registerCollider(collider);
|
|
390
|
+
}
|
|
391
|
+
/** Internal: mark destroyed (called by the world). */
|
|
392
|
+
_markDestroyed() {
|
|
393
|
+
this._destroyed = true;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* A dynamic body has to carry mass. Boundary geometry (a segment, a chain)
|
|
397
|
+
* reports no mass properties, and a collider may also be given zero density,
|
|
398
|
+
* so a dynamic body can end up with none at all - which the solver cannot tell
|
|
399
|
+
* apart from a static body, since both have `invMass === 0`. Rejecting it is
|
|
400
|
+
* the difference between a clear error and a body that silently stops moving.
|
|
401
|
+
*/
|
|
402
|
+
_assertDynamicCarriesMass() {
|
|
403
|
+
if (this.type !== "dynamic" || this._massReady || this._colliders.length === 0) return;
|
|
404
|
+
throw new Error("PhysicsBody: a dynamic body must carry at least one collider with mass — every collider it holds is either boundary geometry (a segment or chain, which has no interior) or has zero density. Add a solid collider, or make the body static or kinematic.");
|
|
405
|
+
}
|
|
406
|
+
/** Recompute mass, centre of mass and rotational inertia from the colliders. */
|
|
407
|
+
_recomputeMass() {
|
|
408
|
+
if (this.type !== "dynamic") {
|
|
409
|
+
this.mass = 0;
|
|
410
|
+
this.invMass = 0;
|
|
411
|
+
this.inertia = 0;
|
|
412
|
+
this.invInertia = 0;
|
|
413
|
+
this._comX = 0;
|
|
414
|
+
this._comY = 0;
|
|
415
|
+
this._massReady = false;
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
let mass = 0;
|
|
419
|
+
let cx = 0;
|
|
420
|
+
let cy = 0;
|
|
421
|
+
let inertiaOrigin = 0;
|
|
422
|
+
const point = {
|
|
423
|
+
x: 0,
|
|
424
|
+
y: 0
|
|
425
|
+
};
|
|
426
|
+
for (const collider of this._colliders) {
|
|
427
|
+
const massProperties = collider.shape.massProperties;
|
|
428
|
+
if (massProperties === null) continue;
|
|
429
|
+
const m = collider.density * massProperties.area;
|
|
430
|
+
if (m <= 0) continue;
|
|
431
|
+
applyTransform(collider.localTransform, massProperties.centroidX, massProperties.centroidY, point);
|
|
432
|
+
mass += m;
|
|
433
|
+
cx += m * point.x;
|
|
434
|
+
cy += m * point.y;
|
|
435
|
+
inertiaOrigin += collider.density * massProperties.unitInertia + m * (point.x * point.x + point.y * point.y);
|
|
436
|
+
}
|
|
437
|
+
if (mass > 0) {
|
|
438
|
+
cx /= mass;
|
|
439
|
+
cy /= mass;
|
|
440
|
+
}
|
|
441
|
+
this.mass = mass;
|
|
442
|
+
this.invMass = mass > 0 ? 1 / mass : 0;
|
|
443
|
+
this._comX = cx;
|
|
444
|
+
this._comY = cy;
|
|
445
|
+
const inertiaCom = inertiaOrigin - mass * (cx * cx + cy * cy);
|
|
446
|
+
this.inertia = this.fixedRotation ? 0 : inertiaCom;
|
|
447
|
+
this.invInertia = this.fixedRotation || inertiaCom <= 0 ? 0 : 1 / inertiaCom;
|
|
448
|
+
this._massReady = mass > 0;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
/**
|
|
452
|
+
* Give a collider its id, and a chain collider's edge proxies theirs. The
|
|
453
|
+
* proxies are ids in the same space as authored colliders - the contact graph
|
|
454
|
+
* keys pairs on them - but they never appear in `body.colliders`.
|
|
455
|
+
*/
|
|
456
|
+
const attachWithChainEdges = (collider, body, owner) => {
|
|
457
|
+
collider._attach(body, owner._allocateColliderId());
|
|
458
|
+
const edges = collider.chainEdges;
|
|
459
|
+
if (edges === null) return;
|
|
460
|
+
for (const edge of edges) edge._attach(body, owner._allocateColliderId());
|
|
461
|
+
};
|
|
445
462
|
|
|
463
|
+
//#endregion
|
|
446
464
|
export { PhysicsBody };
|
|
447
|
-
//# sourceMappingURL=PhysicsBody.js.map
|
|
465
|
+
//# sourceMappingURL=PhysicsBody.js.map
|