@newkrok/nape-js 3.5.1 → 3.5.2
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/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/llms-full.txt +1620 -0
- package/llms.txt +103 -0
- package/package.json +6 -2
package/llms-full.txt
ADDED
|
@@ -0,0 +1,1620 @@
|
|
|
1
|
+
# @newkrok/nape-js — Complete API Reference
|
|
2
|
+
|
|
3
|
+
> Modern TypeScript 2D physics engine for the web. Fully typed, tree-shakeable, dual ESM/CJS exports. Originally ported from the Haxe Nape engine by Luca Deltodesco.
|
|
4
|
+
|
|
5
|
+
- **npm**: `npm install @newkrok/nape-js`
|
|
6
|
+
- **GitHub**: https://github.com/NewKrok/nape-js
|
|
7
|
+
- **API docs**: https://newkrok.github.io/nape-js/api/index.html
|
|
8
|
+
- **Demos**: https://newkrok.github.io/nape-js/examples.html
|
|
9
|
+
- **License**: MIT
|
|
10
|
+
- **Version**: 3.5.1
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Space, Body, BodyType, Vec2, Circle, Polygon } from "@newkrok/nape-js";
|
|
18
|
+
|
|
19
|
+
// Create a physics world with downward gravity
|
|
20
|
+
const space = new Space(new Vec2(0, 600));
|
|
21
|
+
|
|
22
|
+
// Static floor
|
|
23
|
+
const floor = new Body(BodyType.STATIC, new Vec2(400, 550));
|
|
24
|
+
floor.shapes.add(new Polygon(Polygon.box(800, 20)));
|
|
25
|
+
floor.space = space;
|
|
26
|
+
|
|
27
|
+
// Dynamic box
|
|
28
|
+
const box = new Body(BodyType.DYNAMIC, new Vec2(400, 100));
|
|
29
|
+
box.shapes.add(new Polygon(Polygon.box(40, 40)));
|
|
30
|
+
box.space = space;
|
|
31
|
+
|
|
32
|
+
// Dynamic circle
|
|
33
|
+
const ball = new Body(BodyType.DYNAMIC, new Vec2(420, 50));
|
|
34
|
+
ball.shapes.add(new Circle(20));
|
|
35
|
+
ball.space = space;
|
|
36
|
+
|
|
37
|
+
// Game loop — step 60 fps
|
|
38
|
+
function update() {
|
|
39
|
+
space.step(1 / 60);
|
|
40
|
+
for (const body of space.bodies) {
|
|
41
|
+
console.log(`x=${body.position.x.toFixed(1)} y=${body.position.y.toFixed(1)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Key Concepts
|
|
49
|
+
|
|
50
|
+
### Architecture
|
|
51
|
+
|
|
52
|
+
All public classes are exported from the main entry point `@newkrok/nape-js`. The engine uses internal `ZPP_*` classes for computation, wrapped by typed public API classes. Users only interact with the public API.
|
|
53
|
+
|
|
54
|
+
### Object Pooling
|
|
55
|
+
|
|
56
|
+
`Vec2`, `Vec3`, `AABB`, and other frequently-allocated types use internal object pools. Use `Vec2.get()` and `dispose()` for explicit pool management. Weak Vec2s (`Vec2.weak()`) auto-dispose after a single API call.
|
|
57
|
+
|
|
58
|
+
### Lists
|
|
59
|
+
|
|
60
|
+
All collection properties (e.g., `body.shapes`, `space.bodies`) return `NapeList<T>` which supports ES6 iteration (`for...of`), indexed access (`.at(i)`), and standard mutation (`add()`, `remove()`, `push()`, `pop()`).
|
|
61
|
+
|
|
62
|
+
### Simulation Loop
|
|
63
|
+
|
|
64
|
+
Call `space.step(deltaTime)` once per frame. The engine handles broadphase collision detection, narrow-phase contact generation, constraint solving, and callback dispatch.
|
|
65
|
+
|
|
66
|
+
### Callback System
|
|
67
|
+
|
|
68
|
+
Attach listeners to `space.listeners` to receive events. Use `CbType` tags on bodies/shapes/constraints to filter which interactions trigger callbacks.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { InteractionListener, CbEvent, InteractionType, CbType } from "@newkrok/nape-js";
|
|
72
|
+
|
|
73
|
+
const listener = new InteractionListener(
|
|
74
|
+
CbEvent.BEGIN,
|
|
75
|
+
InteractionType.COLLISION,
|
|
76
|
+
CbType.ANY_BODY,
|
|
77
|
+
CbType.ANY_BODY,
|
|
78
|
+
(cb) => {
|
|
79
|
+
console.log("Collision between", cb.int1, "and", cb.int2);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
space.listeners.add(listener);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Geometry Types
|
|
88
|
+
|
|
89
|
+
### Vec2
|
|
90
|
+
|
|
91
|
+
2D vector used for positions, velocities, forces, and other 2D quantities. Supports object pooling via `Vec2.get()` / `dispose()`, weak references that auto-dispose after a single use, and immutability guards.
|
|
92
|
+
|
|
93
|
+
#### Constructor
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
new Vec2(x?: number, y?: number)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Creates a Vec2 with the given components. Defaults to (0, 0). Throws if components are NaN.
|
|
100
|
+
|
|
101
|
+
#### Static Factories
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
Vec2.get(x?: number, y?: number, weak?: boolean): Vec2
|
|
105
|
+
```
|
|
106
|
+
Allocate a Vec2 from the public object pool. If `weak` is true, the vector auto-disposes after a single API call.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
Vec2.weak(x?: number, y?: number): Vec2
|
|
110
|
+
```
|
|
111
|
+
Allocate a weak Vec2 (auto-disposes after a single use).
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
Vec2.fromPolar(length: number, angle: number, weak?: boolean): Vec2
|
|
115
|
+
```
|
|
116
|
+
Create a Vec2 from polar coordinates (length and angle in radians). Returns `(length * cos(angle), length * sin(angle))`.
|
|
117
|
+
|
|
118
|
+
#### Static Methods
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
Vec2.distance(a: Vec2, b: Vec2): number
|
|
122
|
+
```
|
|
123
|
+
Euclidean distance between two Vec2s.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
Vec2.dsq(a: Vec2, b: Vec2): number
|
|
127
|
+
```
|
|
128
|
+
Squared Euclidean distance (avoids sqrt).
|
|
129
|
+
|
|
130
|
+
#### Properties
|
|
131
|
+
|
|
132
|
+
| Property | Type | Description |
|
|
133
|
+
|----------|------|-------------|
|
|
134
|
+
| `x` | `number` | The x component. Throws if NaN or immutable. |
|
|
135
|
+
| `y` | `number` | The y component. Throws if NaN or immutable. |
|
|
136
|
+
| `length` | `number` | Magnitude. Setting scales the vector to the given magnitude (throws for zero vectors). |
|
|
137
|
+
| `angle` | `number` | Angle in radians from +x axis. Setting preserves magnitude. |
|
|
138
|
+
|
|
139
|
+
#### Instance Methods
|
|
140
|
+
|
|
141
|
+
| Method | Returns | Description |
|
|
142
|
+
|--------|---------|-------------|
|
|
143
|
+
| `set(vector: Vec2)` | `this` | Copy another Vec2's components into this vector in-place. |
|
|
144
|
+
| `setxy(x: number, y: number)` | `this` | Set both components at once in-place. |
|
|
145
|
+
| `copy(weak?: boolean)` | `Vec2` | Return a new Vec2 with the same components. |
|
|
146
|
+
| `add(vector: Vec2, weak?: boolean)` | `Vec2` | Return `this + other`. |
|
|
147
|
+
| `addMul(vector: Vec2, scalar: number, weak?: boolean)` | `Vec2` | Return `this + other * scalar`. |
|
|
148
|
+
| `sub(vector: Vec2, weak?: boolean)` | `Vec2` | Return `this - other`. |
|
|
149
|
+
| `mul(scalar: number, weak?: boolean)` | `Vec2` | Return `this * scalar`. |
|
|
150
|
+
| `addeq(vector: Vec2)` | `this` | In-place `this += other`. |
|
|
151
|
+
| `subeq(vector: Vec2)` | `this` | In-place `this -= other`. |
|
|
152
|
+
| `muleq(scalar: number)` | `this` | In-place `this *= scalar`. |
|
|
153
|
+
| `dot(vector: Vec2)` | `number` | Dot product. |
|
|
154
|
+
| `cross(vector: Vec2)` | `number` | 2D cross product (scalar). |
|
|
155
|
+
| `lsq()` | `number` | Squared magnitude (avoids sqrt). |
|
|
156
|
+
| `perp(weak?: boolean)` | `Vec2` | Perpendicular vector rotated 90° CCW: `(-y, x)`. |
|
|
157
|
+
| `rotate(angle: number)` | `this` | Rotate by angle (radians) in-place. |
|
|
158
|
+
| `normalise()` | `this` | Normalise to unit length in-place. Throws for zero vectors. |
|
|
159
|
+
| `unit(weak?: boolean)` | `Vec2` | Return a normalised copy. |
|
|
160
|
+
| `reflect(vec: Vec2, weak?: boolean)` | `Vec2` | Reflect `vec` about this vector as a normal axis. |
|
|
161
|
+
| `dispose()` | `void` | Return this Vec2 to the pool. Throws if immutable or in use. |
|
|
162
|
+
| `toString()` | `string` | String in the form `{ x: ... y: ... }`. |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Vec3
|
|
167
|
+
|
|
168
|
+
3D vector used for constraint impulses.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
new Vec3(x?: number, y?: number, z?: number)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### Static Factories
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
Vec3.get(x?: number, y?: number, z?: number): Vec3
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Properties
|
|
181
|
+
|
|
182
|
+
| Property | Type | Description |
|
|
183
|
+
|----------|------|-------------|
|
|
184
|
+
| `x` | `number` | X component |
|
|
185
|
+
| `y` | `number` | Y component |
|
|
186
|
+
| `z` | `number` | Z component |
|
|
187
|
+
| `length` | `number` | Magnitude |
|
|
188
|
+
|
|
189
|
+
#### Methods
|
|
190
|
+
|
|
191
|
+
| Method | Returns | Description |
|
|
192
|
+
|--------|---------|-------------|
|
|
193
|
+
| `lsq()` | `number` | Squared magnitude |
|
|
194
|
+
| `set(v: Vec3)` | `this` | Copy from another Vec3 |
|
|
195
|
+
| `setxyz(x, y, z)` | `this` | Set all components |
|
|
196
|
+
| `xy(weak?: boolean)` | `Vec2` | Extract x, y as a Vec2 |
|
|
197
|
+
| `dispose()` | `void` | Return to pool |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### AABB
|
|
202
|
+
|
|
203
|
+
Axis-aligned bounding box defined by min/max corners or x/y/width/height.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
new AABB(x?: number, y?: number, width?: number, height?: number)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
All values default to 0. Width and height must be >= 0.
|
|
210
|
+
|
|
211
|
+
#### Properties
|
|
212
|
+
|
|
213
|
+
| Property | Type | Description |
|
|
214
|
+
|----------|------|-------------|
|
|
215
|
+
| `x` | `number` | Left edge (minx). Setting shifts box horizontally. |
|
|
216
|
+
| `y` | `number` | Top edge (miny). Setting shifts box vertically. |
|
|
217
|
+
| `width` | `number` | Width (maxx - minx). Must be >= 0. |
|
|
218
|
+
| `height` | `number` | Height (maxy - miny). Must be >= 0. |
|
|
219
|
+
| `min` | `Vec2` | Top-left corner as live Vec2 (mutating updates AABB). |
|
|
220
|
+
| `max` | `Vec2` | Bottom-right corner as live Vec2 (mutating updates AABB). |
|
|
221
|
+
|
|
222
|
+
#### Methods
|
|
223
|
+
|
|
224
|
+
| Method | Returns | Description |
|
|
225
|
+
|--------|---------|-------------|
|
|
226
|
+
| `copy()` | `AABB` | Return a new AABB with the same bounds. |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### Ray
|
|
231
|
+
|
|
232
|
+
Ray for raycasting queries with origin, direction, and optional maximum distance.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
new Ray(origin: Vec2, direction: Vec2)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Static Factories
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
Ray.fromSegment(start: Vec2, end: Vec2): Ray
|
|
242
|
+
```
|
|
243
|
+
Create a ray from a line segment.
|
|
244
|
+
|
|
245
|
+
#### Properties
|
|
246
|
+
|
|
247
|
+
| Property | Type | Description |
|
|
248
|
+
|----------|------|-------------|
|
|
249
|
+
| `origin` | `Vec2` | World-space start point |
|
|
250
|
+
| `direction` | `Vec2` | Direction vector |
|
|
251
|
+
| `maxDistance` | `number` | Maximum cast distance (default: infinity) |
|
|
252
|
+
|
|
253
|
+
#### Methods
|
|
254
|
+
|
|
255
|
+
| Method | Returns | Description |
|
|
256
|
+
|--------|---------|-------------|
|
|
257
|
+
| `aabb()` | `AABB` | Bounding box of the ray |
|
|
258
|
+
| `at(t: number, weak?: boolean)` | `Vec2` | Point along ray at parameter t |
|
|
259
|
+
| `copy()` | `Ray` | Create a copy |
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### Mat23
|
|
264
|
+
|
|
265
|
+
2×3 affine transformation matrix for 2D transforms.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
new Mat23(a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Represents: `| a b tx |`
|
|
272
|
+
`| c d ty |`
|
|
273
|
+
|
|
274
|
+
#### Static Factories
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
Mat23.rotation(angle: number): Mat23
|
|
278
|
+
Mat23.translation(tx: number, ty: number): Mat23
|
|
279
|
+
Mat23.scale(sx: number, sy: number): Mat23
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### Properties
|
|
283
|
+
|
|
284
|
+
| Property | Type | Description |
|
|
285
|
+
|----------|------|-------------|
|
|
286
|
+
| `a`, `b`, `c`, `d` | `number` | Rotation/scale components |
|
|
287
|
+
| `tx`, `ty` | `number` | Translation components |
|
|
288
|
+
| `determinant` | `number` | Matrix determinant |
|
|
289
|
+
|
|
290
|
+
#### Methods
|
|
291
|
+
|
|
292
|
+
| Method | Returns | Description |
|
|
293
|
+
|--------|---------|-------------|
|
|
294
|
+
| `copy()` | `Mat23` | Copy this matrix |
|
|
295
|
+
| `set(m: Mat23)` | `this` | Copy from another matrix |
|
|
296
|
+
| `setAs(a, b, c, d, tx, ty)` | `this` | Set all components |
|
|
297
|
+
| `reset()` | `this` | Set to identity |
|
|
298
|
+
| `singular()` | `boolean` | True if non-invertible |
|
|
299
|
+
| `inverse()` | `Mat23` | Return inverse matrix |
|
|
300
|
+
| `transpose()` | `Mat23` | Return transposed matrix |
|
|
301
|
+
| `concat(m: Mat23)` | `Mat23` | Return this * m |
|
|
302
|
+
| `transform(v: Vec2, weak?)` | `Vec2` | Transform a point |
|
|
303
|
+
| `inverseTransform(v: Vec2, weak?)` | `Vec2` | Inverse-transform a point |
|
|
304
|
+
| `orthogonal()` | `boolean` | Test orthogonality |
|
|
305
|
+
| `equiorthogonal()` | `boolean` | Test equi-orthogonality |
|
|
306
|
+
| `orthogonalise()` | `this` | Make orthogonal in-place |
|
|
307
|
+
| `equiorthogonalise()` | `this` | Make equi-orthogonal in-place |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### MatMN
|
|
312
|
+
|
|
313
|
+
Variable M×N matrix for constraint math.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
new MatMN(rows: number, cols: number)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Methods
|
|
320
|
+
|
|
321
|
+
| Method | Returns | Description |
|
|
322
|
+
|--------|---------|-------------|
|
|
323
|
+
| `x(row, col)` | `number` | Get element |
|
|
324
|
+
| `setx(row, col, value)` | `void` | Set element |
|
|
325
|
+
| `transpose()` | `MatMN` | Return transposed matrix |
|
|
326
|
+
| `mul(m: MatMN)` | `MatMN` | Return this * m |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### Geom
|
|
331
|
+
|
|
332
|
+
Static geometry utility class.
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
Geom.distanceBody(body1: Body, body2: Body, out1?: Vec2, out2?: Vec2): number
|
|
336
|
+
Geom.distance(shape1: Shape, shape2: Shape, out1?: Vec2, out2?: Vec2): number
|
|
337
|
+
Geom.intersectsBody(body1: Body, body2: Body): boolean
|
|
338
|
+
Geom.intersects(shape1: Shape, shape2: Shape): boolean
|
|
339
|
+
Geom.contains(shape1: Shape, shape2: Shape): boolean
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### GeomPoly
|
|
345
|
+
|
|
346
|
+
Polygon data container for geometry operations (decomposition, winding, containment).
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
new GeomPoly(vertices?: Array<Vec2> | Vec2List | GeomPoly)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
#### Properties and Methods
|
|
353
|
+
|
|
354
|
+
| Member | Type | Description |
|
|
355
|
+
|--------|------|-------------|
|
|
356
|
+
| `empty()` | `boolean` | True if no vertices |
|
|
357
|
+
| `size()` | `number` | Vertex count |
|
|
358
|
+
| `area()` | `number` | Signed area |
|
|
359
|
+
| `winding()` | `Winding` | CLOCKWISE or COUNTER_CLOCKWISE |
|
|
360
|
+
| `contains(point: Vec2)` | `boolean` | Point-in-polygon test |
|
|
361
|
+
| `isClockwise()` | `boolean` | Clockwise winding |
|
|
362
|
+
| `isConvex()` | `boolean` | Convexity test |
|
|
363
|
+
| `isSimple()` | `boolean` | Simple polygon test |
|
|
364
|
+
| `simplify(tolerance)` | `GeomPoly` | Simplify polygon |
|
|
365
|
+
| `convexDecomposition()` | `GeomPolyList` | Decompose into convex parts |
|
|
366
|
+
| `triangularDecomposition()` | `GeomPolyList` | Triangulate |
|
|
367
|
+
| `inflate(distance)` | `GeomPoly` | Offset polygon |
|
|
368
|
+
| `transform(matrix: Mat23)` | `GeomPoly` | Apply transformation |
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### MarchingSquares
|
|
373
|
+
|
|
374
|
+
Isosurface extraction from scalar fields.
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
MarchingSquares.run(
|
|
378
|
+
iso: (x: number, y: number) => number,
|
|
379
|
+
bounds: AABB,
|
|
380
|
+
cellsize: Vec2,
|
|
381
|
+
quality?: number,
|
|
382
|
+
subgrid?: Vec2,
|
|
383
|
+
combine?: boolean,
|
|
384
|
+
output?: GeomPolyList
|
|
385
|
+
): GeomPolyList
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Physics Types
|
|
391
|
+
|
|
392
|
+
### Body
|
|
393
|
+
|
|
394
|
+
Rigid body in the physics world. Can be DYNAMIC, STATIC, or KINEMATIC.
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
new Body(type?: BodyType, position?: Vec2)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### Properties
|
|
401
|
+
|
|
402
|
+
| Property | Type | R/W | Description |
|
|
403
|
+
|----------|------|-----|-------------|
|
|
404
|
+
| `type` | `BodyType` | R/W | DYNAMIC, STATIC, or KINEMATIC |
|
|
405
|
+
| `position` | `Vec2` | R/W | World-space position (live Vec2) |
|
|
406
|
+
| `rotation` | `number` | R/W | Rotation in radians |
|
|
407
|
+
| `velocity` | `Vec2` | R/W | Linear velocity (live Vec2) |
|
|
408
|
+
| `angularVel` | `number` | R/W | Angular velocity (rad/s) |
|
|
409
|
+
| `force` | `Vec2` | R/W | Accumulated force (live Vec2) |
|
|
410
|
+
| `torque` | `number` | R/W | Accumulated torque |
|
|
411
|
+
| `mass` | `number` | R/W | Total mass |
|
|
412
|
+
| `inertia` | `number` | R/W | Rotational inertia |
|
|
413
|
+
| `massMode` | `MassMode` | R/W | DEFAULT or FIXED |
|
|
414
|
+
| `inertiaMode` | `InertiaMode` | R/W | DEFAULT or FIXED |
|
|
415
|
+
| `gravMassMode` | `GravMassMode` | R/W | DEFAULT, FIXED, or SCALED |
|
|
416
|
+
| `gravMass` | `number` | R/W | Gravity mass (when gravMassMode is FIXED) |
|
|
417
|
+
| `gravMassScale` | `number` | R/W | Gravity mass scale (when gravMassMode is SCALED) |
|
|
418
|
+
| `shapes` | `NapeList<Shape>` | R | Attached shapes |
|
|
419
|
+
| `constraints` | `NapeList<Constraint>` | R | Connected constraints |
|
|
420
|
+
| `arbiters` | `NapeList<Arbiter>` | R | Active interaction arbiters |
|
|
421
|
+
| `compound` | `Compound \| null` | R/W | Parent compound |
|
|
422
|
+
| `space` | `Space \| null` | R/W | Parent space (set to add body to world) |
|
|
423
|
+
| `isSleeping` | `boolean` | R | True if body is asleep |
|
|
424
|
+
| `isStatic` | `boolean` | R | True if type is STATIC |
|
|
425
|
+
| `isDynamic` | `boolean` | R | True if type is DYNAMIC |
|
|
426
|
+
| `isKinematic` | `boolean` | R | True if type is KINEMATIC |
|
|
427
|
+
| `worldCOM` | `Vec2` | R | World-space center of mass (live Vec2) |
|
|
428
|
+
| `localCOM` | `Vec2` | R/W | Local-space center of mass |
|
|
429
|
+
| `kinematicVel` | `Vec2` | R/W | Kinematic velocity (live Vec2) |
|
|
430
|
+
| `kinAngVel` | `number` | R/W | Kinematic angular velocity |
|
|
431
|
+
| `surfaceVel` | `Vec2` | R/W | Surface velocity (for conveyor belt effects) |
|
|
432
|
+
| `cbTypes` | `NapeList<CbType>` | R | Callback type tags |
|
|
433
|
+
| `group` | `InteractionGroup \| null` | R/W | Interaction group |
|
|
434
|
+
| `userData` | `Record<string, unknown>` | R | User data object |
|
|
435
|
+
| `allowMovement` | `boolean` | R/W | If false, body cannot translate |
|
|
436
|
+
| `allowRotation` | `boolean` | R/W | If false, body cannot rotate |
|
|
437
|
+
| `bounds` | `AABB` | R | World-space axis-aligned bounding box |
|
|
438
|
+
| `id` | `number` | R | Unique body identifier |
|
|
439
|
+
|
|
440
|
+
#### Methods
|
|
441
|
+
|
|
442
|
+
| Method | Returns | Description |
|
|
443
|
+
|--------|---------|-------------|
|
|
444
|
+
| `applyImpulse(impulse: Vec2, pos?: Vec2)` | `void` | Apply a linear impulse at a world point |
|
|
445
|
+
| `applyAngularImpulse(impulse: number)` | `void` | Apply an angular impulse |
|
|
446
|
+
| `setVelocityFromTarget(target: Vec2, targetRotation: number, dt: number)` | `void` | Set velocity to reach target position/rotation in dt seconds |
|
|
447
|
+
| `rotate(centre: Vec2, angle: number)` | `Body` | Rotate body around a world point |
|
|
448
|
+
| `translate(displacement: Vec2)` | `Body` | Translate body by displacement |
|
|
449
|
+
| `localPointToWorld(point: Vec2, weak?: boolean)` | `Vec2` | Convert local point to world coordinates |
|
|
450
|
+
| `worldPointToLocal(point: Vec2, weak?: boolean)` | `Vec2` | Convert world point to local coordinates |
|
|
451
|
+
| `localVectorToWorld(vector: Vec2, weak?: boolean)` | `Vec2` | Convert local vector to world coordinates |
|
|
452
|
+
| `worldVectorToLocal(vector: Vec2, weak?: boolean)` | `Vec2` | Convert world vector to local coordinates |
|
|
453
|
+
| `contains(point: Vec2)` | `boolean` | Test if any shape contains the point |
|
|
454
|
+
| `copy()` | `Body` | Deep copy the body (shapes, constraints copied) |
|
|
455
|
+
| `validateShapes()` | `void` | Validate all attached shapes |
|
|
456
|
+
| `wake()` | `void` | Wake a sleeping body |
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### BodyType (Enum)
|
|
461
|
+
|
|
462
|
+
| Value | Description |
|
|
463
|
+
|-------|-------------|
|
|
464
|
+
| `BodyType.STATIC` | Immovable body, infinite mass |
|
|
465
|
+
| `BodyType.DYNAMIC` | Fully simulated body affected by forces and collisions |
|
|
466
|
+
| `BodyType.KINEMATIC` | Moved by code only (not affected by forces), but interacts with dynamic bodies |
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
### Material
|
|
471
|
+
|
|
472
|
+
Physical material properties applied to shapes.
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
new Material(
|
|
476
|
+
elasticity?: number, // Bounciness (0 = no bounce, 1 = perfect bounce). Default: 0.0
|
|
477
|
+
dynamicFriction?: number, // Kinetic friction coefficient. Default: 1.0
|
|
478
|
+
staticFriction?: number, // Static friction coefficient. Default: 2.0
|
|
479
|
+
density?: number, // Mass per unit area. Default: 1.0
|
|
480
|
+
rollingFriction?: number // Rolling friction coefficient. Default: 0.001
|
|
481
|
+
)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
#### Properties
|
|
485
|
+
|
|
486
|
+
| Property | Type | Description |
|
|
487
|
+
|----------|------|-------------|
|
|
488
|
+
| `elasticity` | `number` | Bounciness. Combined per-pair: `max(e1, e2)` if either > 0, else `e1 * e2`. |
|
|
489
|
+
| `dynamicFriction` | `number` | Kinetic friction. Combined: `sqrt(f1 * f2)`. Must be >= 0. |
|
|
490
|
+
| `staticFriction` | `number` | Static friction. Combined: `sqrt(f1 * f2)`. Must be >= 0. |
|
|
491
|
+
| `density` | `number` | Mass per area. Must be > 0. Internally stored as `value / 1000`. |
|
|
492
|
+
| `rollingFriction` | `number` | Rolling friction. Combined: `sqrt(f1 * f2)`. Must be >= 0. |
|
|
493
|
+
| `userData` | `Record<string, unknown>` | User data. |
|
|
494
|
+
|
|
495
|
+
#### Static Presets
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
Material.wood() // elasticity=0.4, dynamicFriction=0.2, staticFriction=0.4, density=0.5, rollingFriction=0.001
|
|
499
|
+
Material.steel() // elasticity=0.2, dynamicFriction=0.57, staticFriction=0.74, density=7.8, rollingFriction=0.001
|
|
500
|
+
Material.ice() // elasticity=0.3, dynamicFriction=0.03, staticFriction=0.1, density=0.9, rollingFriction=0.0001
|
|
501
|
+
Material.rubber() // elasticity=0.8, dynamicFriction=1.0, staticFriction=1.0, density=1.5, rollingFriction=0.01
|
|
502
|
+
Material.glass() // elasticity=0.4, dynamicFriction=0.94, staticFriction=0.94, density=2.6, rollingFriction=0.002
|
|
503
|
+
Material.sand() // elasticity=0.05, dynamicFriction=0.6, staticFriction=0.8, density=1.6, rollingFriction=0.5
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### Methods
|
|
507
|
+
|
|
508
|
+
| Method | Returns | Description |
|
|
509
|
+
|--------|---------|-------------|
|
|
510
|
+
| `copy()` | `Material` | Deep copy |
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
### FluidProperties
|
|
515
|
+
|
|
516
|
+
Fluid simulation parameters for sensor-enabled shapes.
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
new FluidProperties(density?: number, viscosity?: number)
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
| Property | Type | Description |
|
|
523
|
+
|----------|------|-------------|
|
|
524
|
+
| `density` | `number` | Fluid density (buoyancy). Default: 2.0 |
|
|
525
|
+
| `viscosity` | `number` | Fluid viscosity (drag). Default: 3.0 |
|
|
526
|
+
| `gravity` | `Vec2` | Override gravity inside fluid (live Vec2) |
|
|
527
|
+
| `shapes` | `NapeList<Shape>` | Shapes using these properties |
|
|
528
|
+
| `userData` | `Record<string, unknown>` | User data |
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
### Compound
|
|
533
|
+
|
|
534
|
+
Hierarchical grouping of bodies, constraints, and sub-compounds.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
new Compound()
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
| Property | Type | Description |
|
|
541
|
+
|----------|------|-------------|
|
|
542
|
+
| `bodies` | `NapeList<Body>` | Child bodies |
|
|
543
|
+
| `constraints` | `NapeList<Constraint>` | Child constraints |
|
|
544
|
+
| `compounds` | `NapeList<Compound>` | Child compounds |
|
|
545
|
+
| `compound` | `Compound \| null` | Parent compound |
|
|
546
|
+
| `space` | `Space \| null` | Parent space |
|
|
547
|
+
| `cbTypes` | `NapeList<CbType>` | Callback type tags |
|
|
548
|
+
| `userData` | `Record<string, unknown>` | User data |
|
|
549
|
+
|
|
550
|
+
| Method | Returns | Description |
|
|
551
|
+
|--------|---------|-------------|
|
|
552
|
+
| `copy()` | `Compound` | Deep copy |
|
|
553
|
+
| `breakApart()` | `void` | Flatten: move all children to parent space/compound |
|
|
554
|
+
| `visitBodies(fn)` | `void` | Call fn for every body (recursive) |
|
|
555
|
+
| `visitConstraints(fn)` | `void` | Call fn for every constraint (recursive) |
|
|
556
|
+
| `visitCompounds(fn)` | `void` | Call fn for every sub-compound (recursive) |
|
|
557
|
+
| `COM(weak?)` | `Vec2` | Center of mass of all bodies |
|
|
558
|
+
| `translate(displacement: Vec2)` | `void` | Translate all bodies |
|
|
559
|
+
| `rotate(centre: Vec2, angle: number)` | `void` | Rotate all bodies around point |
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
### Interactor (Base Class)
|
|
564
|
+
|
|
565
|
+
Base class for Body, Shape, Compound. Provides interaction tagging.
|
|
566
|
+
|
|
567
|
+
| Property | Type | Description |
|
|
568
|
+
|----------|------|-------------|
|
|
569
|
+
| `id` | `number` | Unique identifier |
|
|
570
|
+
| `userData` | `Record<string, unknown>` | User data |
|
|
571
|
+
| `group` | `InteractionGroup \| null` | Interaction group |
|
|
572
|
+
| `cbTypes` | `NapeList<CbType>` | Callback type tags |
|
|
573
|
+
|
|
574
|
+
| Method | Returns | Description |
|
|
575
|
+
|--------|---------|-------------|
|
|
576
|
+
| `isShape()` | `boolean` | Type check |
|
|
577
|
+
| `isBody()` | `boolean` | Type check |
|
|
578
|
+
| `isCompound()` | `boolean` | Type check |
|
|
579
|
+
| `castBody` | `Body \| null` | Cast to Body |
|
|
580
|
+
| `castShape` | `Shape \| null` | Cast to Shape |
|
|
581
|
+
| `castCompound` | `Compound \| null` | Cast to Compound |
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
### MassMode / InertiaMode / GravMassMode (Enums)
|
|
586
|
+
|
|
587
|
+
**MassMode**: `DEFAULT` (auto-calculated from shapes) | `FIXED` (user-set)
|
|
588
|
+
|
|
589
|
+
**InertiaMode**: `DEFAULT` (auto-calculated) | `FIXED` (user-set)
|
|
590
|
+
|
|
591
|
+
**GravMassMode**: `DEFAULT` (use mass) | `FIXED` (user-set gravMass) | `SCALED` (mass * gravMassScale)
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## Shape Types
|
|
596
|
+
|
|
597
|
+
### Shape (Base Class)
|
|
598
|
+
|
|
599
|
+
Base class for Circle and Polygon. Cannot be instantiated directly.
|
|
600
|
+
|
|
601
|
+
| Property | Type | R/W | Description |
|
|
602
|
+
|----------|------|-----|-------------|
|
|
603
|
+
| `type` | `ShapeType` | R | CIRCLE or POLYGON |
|
|
604
|
+
| `body` | `Body \| null` | R/W | Parent body (set to attach) |
|
|
605
|
+
| `worldCOM` | `Vec2` | R | World-space center of mass |
|
|
606
|
+
| `localCOM` | `Vec2` | R/W | Local-space center of mass |
|
|
607
|
+
| `area` | `number` | R | Shape area |
|
|
608
|
+
| `inertia` | `number` | R | Rotational inertia |
|
|
609
|
+
| `angDrag` | `number` | R | Angular drag coefficient |
|
|
610
|
+
| `bounds` | `AABB` | R | World-space bounding box |
|
|
611
|
+
| `material` | `Material` | R/W | Physical material |
|
|
612
|
+
| `filter` | `InteractionFilter` | R/W | Collision/sensor/fluid filter |
|
|
613
|
+
| `fluidProperties` | `FluidProperties` | R/W | Fluid properties |
|
|
614
|
+
| `fluidEnabled` | `boolean` | R/W | Enable fluid interaction |
|
|
615
|
+
| `sensorEnabled` | `boolean` | R/W | Enable sensor mode (detects overlap without physical response) |
|
|
616
|
+
| `cbTypes` | `NapeList<CbType>` | R | Callback type tags |
|
|
617
|
+
| `userData` | `Record<string, unknown>` | R | User data |
|
|
618
|
+
|
|
619
|
+
| Method | Returns | Description |
|
|
620
|
+
|--------|---------|-------------|
|
|
621
|
+
| `isCircle()` | `boolean` | Type check |
|
|
622
|
+
| `isPolygon()` | `boolean` | Type check |
|
|
623
|
+
| `castCircle` | `Circle \| null` | Cast to Circle |
|
|
624
|
+
| `castPolygon` | `Polygon \| null` | Cast to Polygon |
|
|
625
|
+
| `contains(point: Vec2)` | `boolean` | Point containment test |
|
|
626
|
+
| `translate(displacement: Vec2)` | `Shape` | Translate localCOM |
|
|
627
|
+
| `scale(sx: number, sy: number)` | `Shape` | Scale shape |
|
|
628
|
+
| `rotate(angle: number)` | `Shape` | Rotate shape |
|
|
629
|
+
| `transform(matrix: Mat23)` | `Shape` | Apply matrix transform |
|
|
630
|
+
| `copy()` | `Shape` | Deep copy |
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
### Circle
|
|
635
|
+
|
|
636
|
+
Circular collision shape.
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
new Circle(
|
|
640
|
+
radius?: number, // Default: 50
|
|
641
|
+
localCOM?: Vec2, // Local offset from body center
|
|
642
|
+
material?: Material, // Physical material
|
|
643
|
+
filter?: InteractionFilter // Interaction filter
|
|
644
|
+
)
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
| Property | Type | Description |
|
|
648
|
+
|----------|------|-------------|
|
|
649
|
+
| `radius` | `number` | Circle radius. Must be > 0. |
|
|
650
|
+
|
|
651
|
+
All Shape properties are inherited.
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### Polygon
|
|
656
|
+
|
|
657
|
+
Convex polygon collision shape.
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
new Polygon(
|
|
661
|
+
localVerts?: Array<Vec2> | Vec2List | GeomPoly,
|
|
662
|
+
material?: Material,
|
|
663
|
+
filter?: InteractionFilter
|
|
664
|
+
)
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
#### Static Factories
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
Polygon.box(width: number, height: number, weak?: boolean): Array<Vec2>
|
|
671
|
+
```
|
|
672
|
+
Create vertices for an axis-aligned rectangle centered at origin.
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
Polygon.rect(x: number, y: number, width: number, height: number, weak?: boolean): Array<Vec2>
|
|
676
|
+
```
|
|
677
|
+
Create vertices for a rectangle at (x, y).
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
Polygon.regular(xRadius: number, yRadius: number, edgeCount: number, angleOffset?: number, weak?: boolean): Array<Vec2>
|
|
681
|
+
```
|
|
682
|
+
Create vertices for a regular polygon.
|
|
683
|
+
|
|
684
|
+
#### Properties
|
|
685
|
+
|
|
686
|
+
| Property | Type | Description |
|
|
687
|
+
|----------|------|-------------|
|
|
688
|
+
| `localVerts` | `Vec2List` | Vertices in local coordinates |
|
|
689
|
+
| `worldVerts` | `Vec2List` | Vertices in world coordinates (read-only) |
|
|
690
|
+
| `edges` | `EdgeList` | Polygon edges (read-only) |
|
|
691
|
+
|
|
692
|
+
#### Methods
|
|
693
|
+
|
|
694
|
+
| Method | Returns | Description |
|
|
695
|
+
|--------|---------|-------------|
|
|
696
|
+
| `validity()` | `ValidationResult` | Check if polygon is valid (VALID, DEGENERATE, CONCAVE, SELF_INTERSECTING) |
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
### Edge (Read-Only)
|
|
701
|
+
|
|
702
|
+
Polygon edge data. Obtained from `polygon.edges`.
|
|
703
|
+
|
|
704
|
+
| Property | Type | Description |
|
|
705
|
+
|----------|------|-------------|
|
|
706
|
+
| `polygon` | `Polygon` | Parent polygon |
|
|
707
|
+
| `localNormal` | `Vec2` | Edge normal in local space |
|
|
708
|
+
| `worldNormal` | `Vec2` | Edge normal in world space |
|
|
709
|
+
| `length` | `number` | Edge length |
|
|
710
|
+
| `localProjection` | `number` | Normal projection in local space |
|
|
711
|
+
| `worldProjection` | `number` | Normal projection in world space |
|
|
712
|
+
| `localVertex1`, `localVertex2` | `Vec2` | Endpoints in local space |
|
|
713
|
+
| `worldVertex1`, `worldVertex2` | `Vec2` | Endpoints in world space |
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
### ShapeType (Enum)
|
|
718
|
+
|
|
719
|
+
| Value | Description |
|
|
720
|
+
|-------|-------------|
|
|
721
|
+
| `ShapeType.CIRCLE` | Circular shape |
|
|
722
|
+
| `ShapeType.POLYGON` | Polygon shape |
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
### ValidationResult (Enum)
|
|
727
|
+
|
|
728
|
+
| Value | Description |
|
|
729
|
+
|-------|-------------|
|
|
730
|
+
| `ValidationResult.VALID` | Polygon is valid |
|
|
731
|
+
| `ValidationResult.DEGENERATE` | Polygon has degenerate geometry (colinear points, zero area) |
|
|
732
|
+
| `ValidationResult.CONCAVE` | Polygon is concave (must be convex) |
|
|
733
|
+
| `ValidationResult.SELF_INTERSECTING` | Polygon edges cross |
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Constraint Types
|
|
738
|
+
|
|
739
|
+
### Constraint (Base Class)
|
|
740
|
+
|
|
741
|
+
Base class for all joints. Cannot be instantiated directly.
|
|
742
|
+
|
|
743
|
+
#### Properties
|
|
744
|
+
|
|
745
|
+
| Property | Type | R/W | Description |
|
|
746
|
+
|----------|------|-----|-------------|
|
|
747
|
+
| `active` | `boolean` | R/W | Enable/disable constraint |
|
|
748
|
+
| `stiff` | `boolean` | R/W | If true, hard constraint. If false, spring-like. |
|
|
749
|
+
| `frequency` | `number` | R/W | Spring frequency in Hz (when stiff=false). Must be > 0. |
|
|
750
|
+
| `damping` | `number` | R/W | Damping ratio (when stiff=false). 0=no damping, 1=critical. Must be >= 0. |
|
|
751
|
+
| `maxForce` | `number` | R/W | Maximum constraint force. Default: infinity. |
|
|
752
|
+
| `maxError` | `number` | R/W | Maximum positional error before breaking. Default: infinity. |
|
|
753
|
+
| `breakUnderForce` | `boolean` | R/W | Break constraint when maxForce exceeded. |
|
|
754
|
+
| `breakUnderError` | `boolean` | R/W | Break constraint when maxError exceeded. |
|
|
755
|
+
| `removeOnBreak` | `boolean` | R/W | Remove from space when broken. |
|
|
756
|
+
| `isSleeping` | `boolean` | R | True if constraint is asleep |
|
|
757
|
+
| `space` | `Space \| null` | R/W | Parent space (set to add to world) |
|
|
758
|
+
| `compound` | `Compound \| null` | R/W | Parent compound |
|
|
759
|
+
| `cbTypes` | `NapeList<CbType>` | R | Callback type tags |
|
|
760
|
+
| `userData` | `Record<string, unknown>` | R | User data |
|
|
761
|
+
| `debugDraw` | `boolean` | R/W | Enable debug drawing |
|
|
762
|
+
|
|
763
|
+
#### Methods
|
|
764
|
+
|
|
765
|
+
| Method | Returns | Description |
|
|
766
|
+
|--------|---------|-------------|
|
|
767
|
+
| `impulse()` | `MatMN` | Current constraint impulse |
|
|
768
|
+
| `bodyImpulse(body: Body)` | `Vec3` | Impulse on a specific body |
|
|
769
|
+
| `visitBodies(fn: (body: Body) => void)` | `void` | Iterate connected bodies |
|
|
770
|
+
| `copy()` | `Constraint` | Deep copy |
|
|
771
|
+
|
|
772
|
+
---
|
|
773
|
+
|
|
774
|
+
### PivotJoint
|
|
775
|
+
|
|
776
|
+
Pin two bodies at a shared anchor point (hinge/pin joint).
|
|
777
|
+
|
|
778
|
+
```typescript
|
|
779
|
+
new PivotJoint(body1?: Body, body2?: Body, anchor1?: Vec2, anchor2?: Vec2)
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Constrains two anchor points to remain coincident. 2 degrees of freedom.
|
|
783
|
+
|
|
784
|
+
| Property | Type | Description |
|
|
785
|
+
|----------|------|-------------|
|
|
786
|
+
| `body1` | `Body \| null` | First body (null = world) |
|
|
787
|
+
| `body2` | `Body \| null` | Second body (null = world) |
|
|
788
|
+
| `anchor1` | `Vec2` | Anchor point in body1 local coords |
|
|
789
|
+
| `anchor2` | `Vec2` | Anchor point in body2 local coords |
|
|
790
|
+
|
|
791
|
+
---
|
|
792
|
+
|
|
793
|
+
### DistanceJoint
|
|
794
|
+
|
|
795
|
+
Constrain distance between two anchor points.
|
|
796
|
+
|
|
797
|
+
```typescript
|
|
798
|
+
new DistanceJoint(
|
|
799
|
+
body1?: Body, body2?: Body,
|
|
800
|
+
anchor1?: Vec2, anchor2?: Vec2,
|
|
801
|
+
jointMin?: number, jointMax?: number
|
|
802
|
+
)
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
Enforces: `jointMin <= distance(anchor1, anchor2) <= jointMax`
|
|
806
|
+
|
|
807
|
+
| Property | Type | Description |
|
|
808
|
+
|----------|------|-------------|
|
|
809
|
+
| `body1` | `Body \| null` | First body |
|
|
810
|
+
| `body2` | `Body \| null` | Second body |
|
|
811
|
+
| `anchor1` | `Vec2` | Anchor on body1 |
|
|
812
|
+
| `anchor2` | `Vec2` | Anchor on body2 |
|
|
813
|
+
| `jointMin` | `number` | Minimum allowed distance |
|
|
814
|
+
| `jointMax` | `number` | Maximum allowed distance |
|
|
815
|
+
|
|
816
|
+
| Method | Returns | Description |
|
|
817
|
+
|--------|---------|-------------|
|
|
818
|
+
| `isSlack()` | `boolean` | True if constraint is not active (distance within limits) |
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
### AngleJoint
|
|
823
|
+
|
|
824
|
+
Constrain relative rotation angle between two bodies.
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
new AngleJoint(
|
|
828
|
+
body1?: Body, body2?: Body,
|
|
829
|
+
jointMin?: number, jointMax?: number,
|
|
830
|
+
ratio?: number
|
|
831
|
+
)
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
Enforces: `jointMin <= body2.rotation - ratio * body1.rotation <= jointMax`
|
|
835
|
+
|
|
836
|
+
| Property | Type | Description |
|
|
837
|
+
|----------|------|-------------|
|
|
838
|
+
| `body1` | `Body \| null` | First body |
|
|
839
|
+
| `body2` | `Body \| null` | Second body |
|
|
840
|
+
| `jointMin` | `number` | Minimum relative angle (radians) |
|
|
841
|
+
| `jointMax` | `number` | Maximum relative angle (radians) |
|
|
842
|
+
| `ratio` | `number` | Gear ratio (default 1.0) |
|
|
843
|
+
|
|
844
|
+
| Method | Returns | Description |
|
|
845
|
+
|--------|---------|-------------|
|
|
846
|
+
| `isSlack()` | `boolean` | True if constraint is not active |
|
|
847
|
+
|
|
848
|
+
---
|
|
849
|
+
|
|
850
|
+
### WeldJoint
|
|
851
|
+
|
|
852
|
+
Fix relative position and rotation (rigid weld).
|
|
853
|
+
|
|
854
|
+
```typescript
|
|
855
|
+
new WeldJoint(
|
|
856
|
+
body1?: Body, body2?: Body,
|
|
857
|
+
anchor1?: Vec2, anchor2?: Vec2,
|
|
858
|
+
phase?: number
|
|
859
|
+
)
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
| Property | Type | Description |
|
|
863
|
+
|----------|------|-------------|
|
|
864
|
+
| `body1` | `Body \| null` | First body |
|
|
865
|
+
| `body2` | `Body \| null` | Second body |
|
|
866
|
+
| `anchor1` | `Vec2` | Anchor on body1 |
|
|
867
|
+
| `anchor2` | `Vec2` | Anchor on body2 |
|
|
868
|
+
| `phase` | `number` | Target relative angle offset (radians, default 0) |
|
|
869
|
+
|
|
870
|
+
---
|
|
871
|
+
|
|
872
|
+
### MotorJoint
|
|
873
|
+
|
|
874
|
+
Drive relative angular velocity to a target rate.
|
|
875
|
+
|
|
876
|
+
```typescript
|
|
877
|
+
new MotorJoint(body1?: Body, body2?: Body, rate?: number, ratio?: number)
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
| Property | Type | Description |
|
|
881
|
+
|----------|------|-------------|
|
|
882
|
+
| `body1` | `Body \| null` | First body |
|
|
883
|
+
| `body2` | `Body \| null` | Second body |
|
|
884
|
+
| `rate` | `number` | Target angular velocity (rad/s, default 0) |
|
|
885
|
+
| `ratio` | `number` | Gear ratio (default 1.0) |
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
### LineJoint
|
|
890
|
+
|
|
891
|
+
Constrain body2's anchor to slide along a line through body1's anchor.
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
new LineJoint(
|
|
895
|
+
body1?: Body, body2?: Body,
|
|
896
|
+
anchor1?: Vec2, anchor2?: Vec2,
|
|
897
|
+
direction?: Vec2,
|
|
898
|
+
jointMin?: number, jointMax?: number
|
|
899
|
+
)
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
| Property | Type | Description |
|
|
903
|
+
|----------|------|-------------|
|
|
904
|
+
| `body1` | `Body \| null` | Body defining the line |
|
|
905
|
+
| `body2` | `Body \| null` | Body constrained to the line |
|
|
906
|
+
| `anchor1` | `Vec2` | Line origin on body1 |
|
|
907
|
+
| `anchor2` | `Vec2` | Anchor on body2 |
|
|
908
|
+
| `direction` | `Vec2` | Line direction (local to body1) |
|
|
909
|
+
| `jointMin` | `number` | Minimum displacement along line |
|
|
910
|
+
| `jointMax` | `number` | Maximum displacement along line |
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
### PulleyJoint
|
|
915
|
+
|
|
916
|
+
Constrain weighted sum of two distances (rope/pulley system).
|
|
917
|
+
|
|
918
|
+
```typescript
|
|
919
|
+
new PulleyJoint(
|
|
920
|
+
body1?: Body, body2?: Body, body3?: Body, body4?: Body,
|
|
921
|
+
anchor1?: Vec2, anchor2?: Vec2, anchor3?: Vec2, anchor4?: Vec2,
|
|
922
|
+
jointMin?: number, jointMax?: number,
|
|
923
|
+
ratio?: number
|
|
924
|
+
)
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Enforces: `jointMin <= dist(body1.anchor1, body2.anchor2) + ratio * dist(body3.anchor3, body4.anchor4) <= jointMax`
|
|
928
|
+
|
|
929
|
+
| Property | Type | Description |
|
|
930
|
+
|----------|------|-------------|
|
|
931
|
+
| `body1` - `body4` | `Body \| null` | Four bodies (null = world) |
|
|
932
|
+
| `anchor1` - `anchor4` | `Vec2` | Four anchor points |
|
|
933
|
+
| `jointMin` | `number` | Minimum combined distance |
|
|
934
|
+
| `jointMax` | `number` | Maximum combined distance |
|
|
935
|
+
| `ratio` | `number` | Weight ratio for second distance (default 1.0) |
|
|
936
|
+
|
|
937
|
+
| Method | Returns | Description |
|
|
938
|
+
|--------|---------|-------------|
|
|
939
|
+
| `isSlack()` | `boolean` | True if constraint is not active |
|
|
940
|
+
|
|
941
|
+
---
|
|
942
|
+
|
|
943
|
+
## Callbacks & Events
|
|
944
|
+
|
|
945
|
+
### CbType
|
|
946
|
+
|
|
947
|
+
Callback type tag. Attach to bodies, shapes, or constraints to control which events trigger listeners.
|
|
948
|
+
|
|
949
|
+
```typescript
|
|
950
|
+
new CbType()
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
#### Static Singletons
|
|
954
|
+
|
|
955
|
+
| Singleton | Description |
|
|
956
|
+
|-----------|-------------|
|
|
957
|
+
| `CbType.ANY_BODY` | Matches all bodies |
|
|
958
|
+
| `CbType.ANY_SHAPE` | Matches all shapes |
|
|
959
|
+
| `CbType.ANY_COMPOUND` | Matches all compounds |
|
|
960
|
+
| `CbType.ANY_CONSTRAINT` | Matches all constraints (must be manually added to constraints) |
|
|
961
|
+
|
|
962
|
+
#### Properties
|
|
963
|
+
|
|
964
|
+
| Property | Type | Description |
|
|
965
|
+
|----------|------|-------------|
|
|
966
|
+
| `id` | `number` | Unique identifier |
|
|
967
|
+
| `userData` | `Record<string, unknown>` | User data |
|
|
968
|
+
|
|
969
|
+
#### Methods
|
|
970
|
+
|
|
971
|
+
| Method | Returns | Description |
|
|
972
|
+
|--------|---------|-------------|
|
|
973
|
+
| `including(types...)` | `OptionType` | Create filter matching this AND given types |
|
|
974
|
+
| `excluding(types...)` | `OptionType` | Create filter matching this but NOT given types |
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
### CbEvent (Enum)
|
|
979
|
+
|
|
980
|
+
| Value | Description | Used with |
|
|
981
|
+
|-------|-------------|-----------|
|
|
982
|
+
| `CbEvent.BEGIN` | Interaction just started | InteractionListener |
|
|
983
|
+
| `CbEvent.ONGOING` | Interaction continues | InteractionListener |
|
|
984
|
+
| `CbEvent.END` | Interaction ended | InteractionListener |
|
|
985
|
+
| `CbEvent.WAKE` | Body woke up | BodyListener |
|
|
986
|
+
| `CbEvent.SLEEP` | Body fell asleep | BodyListener |
|
|
987
|
+
| `CbEvent.BREAK` | Constraint broke | ConstraintListener |
|
|
988
|
+
| `CbEvent.PRE` | Pre-collision phase | PreListener (internal) |
|
|
989
|
+
|
|
990
|
+
---
|
|
991
|
+
|
|
992
|
+
### InteractionType (Enum)
|
|
993
|
+
|
|
994
|
+
| Value | Description |
|
|
995
|
+
|-------|-------------|
|
|
996
|
+
| `InteractionType.COLLISION` | Physical collision |
|
|
997
|
+
| `InteractionType.SENSOR` | Overlap detection only (no physics response) |
|
|
998
|
+
| `InteractionType.FLUID` | Fluid interaction (buoyancy, drag) |
|
|
999
|
+
| `InteractionType.ANY` | Match any interaction type |
|
|
1000
|
+
|
|
1001
|
+
---
|
|
1002
|
+
|
|
1003
|
+
### InteractionListener
|
|
1004
|
+
|
|
1005
|
+
Listen for collision, sensor, or fluid interaction events.
|
|
1006
|
+
|
|
1007
|
+
```typescript
|
|
1008
|
+
new InteractionListener(
|
|
1009
|
+
event: CbEvent, // BEGIN, ONGOING, or END
|
|
1010
|
+
interactionType: InteractionType, // COLLISION, SENSOR, FLUID, or ANY
|
|
1011
|
+
options1: CbType | OptionType, // Filter for first interactor
|
|
1012
|
+
options2: CbType | OptionType, // Filter for second interactor
|
|
1013
|
+
handler: (cb: InteractionCallback) => void,
|
|
1014
|
+
precedence?: number // Lower runs first (default 0)
|
|
1015
|
+
)
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
#### Properties
|
|
1019
|
+
|
|
1020
|
+
| Property | Type | Description |
|
|
1021
|
+
|----------|------|-------------|
|
|
1022
|
+
| `options1` | `OptionType` | Filter for first interactor |
|
|
1023
|
+
| `options2` | `OptionType` | Filter for second interactor |
|
|
1024
|
+
| `handler` | `Function` | Callback function |
|
|
1025
|
+
| `interactionType` | `InteractionType` | Event interaction type |
|
|
1026
|
+
| `allowSleepingCallbacks` | `boolean` | Fire callbacks even for sleeping interactions |
|
|
1027
|
+
|
|
1028
|
+
#### Example
|
|
1029
|
+
|
|
1030
|
+
```typescript
|
|
1031
|
+
const ct = new CbType();
|
|
1032
|
+
ball.cbTypes.add(ct);
|
|
1033
|
+
|
|
1034
|
+
space.listeners.add(new InteractionListener(
|
|
1035
|
+
CbEvent.BEGIN,
|
|
1036
|
+
InteractionType.COLLISION,
|
|
1037
|
+
ct,
|
|
1038
|
+
CbType.ANY_BODY,
|
|
1039
|
+
(cb) => {
|
|
1040
|
+
console.log("Ball hit something!");
|
|
1041
|
+
const arb = cb.arbiters.at(0).collisionArbiter;
|
|
1042
|
+
console.log("Normal:", arb.normal.x, arb.normal.y);
|
|
1043
|
+
}
|
|
1044
|
+
));
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
---
|
|
1048
|
+
|
|
1049
|
+
### BodyListener
|
|
1050
|
+
|
|
1051
|
+
Listen for body wake/sleep events.
|
|
1052
|
+
|
|
1053
|
+
```typescript
|
|
1054
|
+
new BodyListener(
|
|
1055
|
+
event: CbEvent, // WAKE or SLEEP
|
|
1056
|
+
options: CbType | OptionType, // Filter
|
|
1057
|
+
handler: (cb: BodyCallback) => void,
|
|
1058
|
+
precedence?: number
|
|
1059
|
+
)
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
---
|
|
1063
|
+
|
|
1064
|
+
### ConstraintListener
|
|
1065
|
+
|
|
1066
|
+
Listen for constraint events (BREAK, WAKE, SLEEP).
|
|
1067
|
+
|
|
1068
|
+
```typescript
|
|
1069
|
+
new ConstraintListener(
|
|
1070
|
+
event: CbEvent, // WAKE, SLEEP, or BREAK
|
|
1071
|
+
options: CbType | OptionType, // Filter
|
|
1072
|
+
handler: (cb: ConstraintCallback) => void,
|
|
1073
|
+
precedence?: number
|
|
1074
|
+
)
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
---
|
|
1078
|
+
|
|
1079
|
+
### PreListener
|
|
1080
|
+
|
|
1081
|
+
Pre-collision handler for filtering or modifying collisions before the solver runs.
|
|
1082
|
+
|
|
1083
|
+
```typescript
|
|
1084
|
+
new PreListener(
|
|
1085
|
+
interactionType: InteractionType,
|
|
1086
|
+
options1: CbType | OptionType,
|
|
1087
|
+
options2: CbType | OptionType,
|
|
1088
|
+
handler: (cb: PreCallback) => PreFlag | null,
|
|
1089
|
+
precedence?: number,
|
|
1090
|
+
pure?: boolean // If true, result is cached (default false)
|
|
1091
|
+
)
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
Return `PreFlag.ACCEPT`, `PreFlag.IGNORE`, `PreFlag.ACCEPT_ONCE`, or `PreFlag.IGNORE_ONCE` to control collision response.
|
|
1095
|
+
|
|
1096
|
+
---
|
|
1097
|
+
|
|
1098
|
+
### InteractionCallback
|
|
1099
|
+
|
|
1100
|
+
Received by InteractionListener handlers.
|
|
1101
|
+
|
|
1102
|
+
| Property | Type | Description |
|
|
1103
|
+
|----------|------|-------------|
|
|
1104
|
+
| `int1` | `Interactor` | First interactor (body, shape, or compound) |
|
|
1105
|
+
| `int2` | `Interactor` | Second interactor |
|
|
1106
|
+
| `arbiters` | `ArbiterList` | All arbiters for this interaction |
|
|
1107
|
+
|
|
1108
|
+
---
|
|
1109
|
+
|
|
1110
|
+
### BodyCallback
|
|
1111
|
+
|
|
1112
|
+
Received by BodyListener handlers.
|
|
1113
|
+
|
|
1114
|
+
| Property | Type | Description |
|
|
1115
|
+
|----------|------|-------------|
|
|
1116
|
+
| `body` | `Body` | The body that woke or slept |
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
### ConstraintCallback
|
|
1121
|
+
|
|
1122
|
+
Received by ConstraintListener handlers.
|
|
1123
|
+
|
|
1124
|
+
| Property | Type | Description |
|
|
1125
|
+
|----------|------|-------------|
|
|
1126
|
+
| `constraint` | `Constraint` | The constraint that broke |
|
|
1127
|
+
|
|
1128
|
+
---
|
|
1129
|
+
|
|
1130
|
+
### PreCallback
|
|
1131
|
+
|
|
1132
|
+
Received by PreListener handlers.
|
|
1133
|
+
|
|
1134
|
+
| Property | Type | Description |
|
|
1135
|
+
|----------|------|-------------|
|
|
1136
|
+
| `arbiter` | `Arbiter` | The arbiter (mutable — modify collision properties here) |
|
|
1137
|
+
| `int1` | `Interactor` | First interactor |
|
|
1138
|
+
| `int2` | `Interactor` | Second interactor |
|
|
1139
|
+
| `swapped` | `boolean` | True if int1/int2 are swapped relative to listener definition |
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
### PreFlag (Enum)
|
|
1144
|
+
|
|
1145
|
+
| Value | Description |
|
|
1146
|
+
|-------|-------------|
|
|
1147
|
+
| `PreFlag.ACCEPT` | Allow collision (permanent) |
|
|
1148
|
+
| `PreFlag.IGNORE` | Ignore collision (permanent) |
|
|
1149
|
+
| `PreFlag.ACCEPT_ONCE` | Allow collision (re-evaluate next step) |
|
|
1150
|
+
| `PreFlag.IGNORE_ONCE` | Ignore collision (re-evaluate next step) |
|
|
1151
|
+
|
|
1152
|
+
---
|
|
1153
|
+
|
|
1154
|
+
## Collision & Dynamics
|
|
1155
|
+
|
|
1156
|
+
### Arbiter (Base Class)
|
|
1157
|
+
|
|
1158
|
+
Interaction data between two shapes. Pooled — do not hold references after `space.step()`.
|
|
1159
|
+
|
|
1160
|
+
| Property | Type | Description |
|
|
1161
|
+
|----------|------|-------------|
|
|
1162
|
+
| `type` | `ArbiterType` | COLLISION, SENSOR, or FLUID |
|
|
1163
|
+
| `shape1` | `Shape` | First shape |
|
|
1164
|
+
| `shape2` | `Shape` | Second shape |
|
|
1165
|
+
| `body1` | `Body` | First body |
|
|
1166
|
+
| `body2` | `Body` | Second body |
|
|
1167
|
+
| `isSleeping` | `boolean` | True if interaction is sleeping |
|
|
1168
|
+
|
|
1169
|
+
| Method | Returns | Description |
|
|
1170
|
+
|--------|---------|-------------|
|
|
1171
|
+
| `isCollisionArbiter()` | `boolean` | Type check |
|
|
1172
|
+
| `isFluidArbiter()` | `boolean` | Type check |
|
|
1173
|
+
| `isSensorArbiter()` | `boolean` | Type check |
|
|
1174
|
+
| `collisionArbiter` | `CollisionArbiter` | Cast (throws if wrong type) |
|
|
1175
|
+
| `fluidArbiter` | `FluidArbiter` | Cast (throws if wrong type) |
|
|
1176
|
+
| `totalImpulse(body?, freshOnly?)` | `Vec3` | Total impulse (x, y, angular) |
|
|
1177
|
+
|
|
1178
|
+
---
|
|
1179
|
+
|
|
1180
|
+
### CollisionArbiter
|
|
1181
|
+
|
|
1182
|
+
Collision-specific arbiter with contact points and impulse data.
|
|
1183
|
+
|
|
1184
|
+
| Property | Type | R/W | Description |
|
|
1185
|
+
|----------|------|-----|-------------|
|
|
1186
|
+
| `contacts` | `ContactList` | R | Active contact points |
|
|
1187
|
+
| `normal` | `Vec2` | R | Collision normal (shape1 → shape2) |
|
|
1188
|
+
| `radius` | `number` | R | Sum of shape radii |
|
|
1189
|
+
| `referenceEdge1` | `Edge \| null` | R | Reference edge on shape1 |
|
|
1190
|
+
| `referenceEdge2` | `Edge \| null` | R | Reference edge on shape2 |
|
|
1191
|
+
| `elasticity` | `number` | R/W* | Combined elasticity (* mutable in PreListener) |
|
|
1192
|
+
| `dynamicFriction` | `number` | R/W* | Combined dynamic friction |
|
|
1193
|
+
| `staticFriction` | `number` | R/W* | Combined static friction |
|
|
1194
|
+
| `rollingFriction` | `number` | R/W* | Combined rolling friction |
|
|
1195
|
+
|
|
1196
|
+
| Method | Returns | Description |
|
|
1197
|
+
|--------|---------|-------------|
|
|
1198
|
+
| `normalImpulse(body?, freshOnly?)` | `Vec3` | Normal impulse |
|
|
1199
|
+
| `tangentImpulse(body?, freshOnly?)` | `Vec3` | Tangent (friction) impulse |
|
|
1200
|
+
| `rollingImpulse(body?, freshOnly?)` | `number` | Rolling friction impulse |
|
|
1201
|
+
| `totalImpulse(body?, freshOnly?)` | `Vec3` | Total impulse |
|
|
1202
|
+
| `firstVertex()` | `boolean` | True if contact is at first vertex |
|
|
1203
|
+
| `secondVertex()` | `boolean` | True if contact is at second vertex |
|
|
1204
|
+
|
|
1205
|
+
---
|
|
1206
|
+
|
|
1207
|
+
### FluidArbiter
|
|
1208
|
+
|
|
1209
|
+
Fluid-specific arbiter with buoyancy and drag data.
|
|
1210
|
+
|
|
1211
|
+
| Property | Type | R/W | Description |
|
|
1212
|
+
|----------|------|-----|-------------|
|
|
1213
|
+
| `position` | `Vec2` | R/W* | Center of overlap (* mutable in PreListener) |
|
|
1214
|
+
| `overlap` | `number` | R/W* | Overlap area in pixels² |
|
|
1215
|
+
|
|
1216
|
+
| Method | Returns | Description |
|
|
1217
|
+
|--------|---------|-------------|
|
|
1218
|
+
| `buoyancyImpulse(body?)` | `Vec3` | Buoyancy impulse |
|
|
1219
|
+
| `dragImpulse(body?)` | `Vec3` | Drag impulse |
|
|
1220
|
+
| `totalImpulse(body?)` | `Vec3` | Total fluid impulse |
|
|
1221
|
+
|
|
1222
|
+
---
|
|
1223
|
+
|
|
1224
|
+
### Contact
|
|
1225
|
+
|
|
1226
|
+
Single contact point between two colliding shapes.
|
|
1227
|
+
|
|
1228
|
+
| Property | Type | Description |
|
|
1229
|
+
|----------|------|-------------|
|
|
1230
|
+
| `arbiter` | `CollisionArbiter` | Parent arbiter |
|
|
1231
|
+
| `position` | `Vec2` | World-space contact point |
|
|
1232
|
+
| `penetration` | `number` | Overlap depth (positive = overlapping) |
|
|
1233
|
+
| `fresh` | `boolean` | True if newly created this step |
|
|
1234
|
+
| `friction` | `number` | Friction at this contact |
|
|
1235
|
+
|
|
1236
|
+
| Method | Returns | Description |
|
|
1237
|
+
|--------|---------|-------------|
|
|
1238
|
+
| `normalImpulse(body?)` | `Vec3` | Normal impulse at this contact |
|
|
1239
|
+
| `tangentImpulse(body?)` | `Vec3` | Tangent impulse at this contact |
|
|
1240
|
+
| `rollingImpulse(body?)` | `number` | Rolling impulse at this contact |
|
|
1241
|
+
| `totalImpulse(body?)` | `Vec3` | Total impulse at this contact |
|
|
1242
|
+
|
|
1243
|
+
---
|
|
1244
|
+
|
|
1245
|
+
### InteractionFilter
|
|
1246
|
+
|
|
1247
|
+
Bitmask-based filtering for collision, sensor, and fluid interactions.
|
|
1248
|
+
|
|
1249
|
+
```typescript
|
|
1250
|
+
new InteractionFilter(
|
|
1251
|
+
collisionGroup?: number, // Default: 1
|
|
1252
|
+
collisionMask?: number, // Default: -1 (all bits set)
|
|
1253
|
+
sensorGroup?: number, // Default: 1
|
|
1254
|
+
sensorMask?: number, // Default: -1
|
|
1255
|
+
fluidGroup?: number, // Default: 1
|
|
1256
|
+
fluidMask?: number // Default: -1
|
|
1257
|
+
)
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
Two shapes interact when: `(filter1.mask & filter2.group) != 0 && (filter2.mask & filter1.group) != 0`
|
|
1261
|
+
|
|
1262
|
+
| Property | Type | Description |
|
|
1263
|
+
|----------|------|-------------|
|
|
1264
|
+
| `collisionGroup` | `number` | Collision group bits |
|
|
1265
|
+
| `collisionMask` | `number` | Collision mask bits |
|
|
1266
|
+
| `sensorGroup` | `number` | Sensor group bits |
|
|
1267
|
+
| `sensorMask` | `number` | Sensor mask bits |
|
|
1268
|
+
| `fluidGroup` | `number` | Fluid group bits |
|
|
1269
|
+
| `fluidMask` | `number` | Fluid mask bits |
|
|
1270
|
+
|
|
1271
|
+
| Method | Returns | Description |
|
|
1272
|
+
|--------|---------|-------------|
|
|
1273
|
+
| `shouldCollide(other: InteractionFilter)` | `boolean` | Test collision interaction |
|
|
1274
|
+
| `shouldSense(other: InteractionFilter)` | `boolean` | Test sensor interaction |
|
|
1275
|
+
| `shouldFlow(other: InteractionFilter)` | `boolean` | Test fluid interaction |
|
|
1276
|
+
| `copy()` | `InteractionFilter` | Deep copy |
|
|
1277
|
+
|
|
1278
|
+
---
|
|
1279
|
+
|
|
1280
|
+
### InteractionGroup
|
|
1281
|
+
|
|
1282
|
+
Hierarchical grouping for interaction control.
|
|
1283
|
+
|
|
1284
|
+
```typescript
|
|
1285
|
+
new InteractionGroup(ignore?: boolean)
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
When two interactors share a common group ancestor with `ignore=true`, they don't interact.
|
|
1289
|
+
|
|
1290
|
+
| Property | Type | Description |
|
|
1291
|
+
|----------|------|-------------|
|
|
1292
|
+
| `group` | `InteractionGroup \| null` | Parent group |
|
|
1293
|
+
| `ignore` | `boolean` | If true, members don't interact with each other |
|
|
1294
|
+
|
|
1295
|
+
---
|
|
1296
|
+
|
|
1297
|
+
### ArbiterType (Enum)
|
|
1298
|
+
|
|
1299
|
+
| Value | Description |
|
|
1300
|
+
|-------|-------------|
|
|
1301
|
+
| `ArbiterType.COLLISION` | Physical collision |
|
|
1302
|
+
| `ArbiterType.SENSOR` | Sensor overlap |
|
|
1303
|
+
| `ArbiterType.FLUID` | Fluid interaction |
|
|
1304
|
+
|
|
1305
|
+
---
|
|
1306
|
+
|
|
1307
|
+
## Space
|
|
1308
|
+
|
|
1309
|
+
### Space
|
|
1310
|
+
|
|
1311
|
+
Physics world. Create with gravity, add bodies/constraints, call `step(dt)` to simulate.
|
|
1312
|
+
|
|
1313
|
+
```typescript
|
|
1314
|
+
new Space(gravity?: Vec2, broadphase?: Broadphase)
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
#### Properties
|
|
1318
|
+
|
|
1319
|
+
| Property | Type | R/W | Description |
|
|
1320
|
+
|----------|------|-----|-------------|
|
|
1321
|
+
| `gravity` | `Vec2` | R/W | World gravity (live Vec2). Default: (0, 0). |
|
|
1322
|
+
| `broadphase` | `Broadphase` | R | SWEEP_AND_PRUNE or DYNAMIC_AABB_TREE |
|
|
1323
|
+
| `sortContacts` | `boolean` | R/W | Sort contacts for determinism. Default: true. |
|
|
1324
|
+
| `worldLinearDrag` | `number` | R/W | Global linear drag coefficient |
|
|
1325
|
+
| `worldAngularDrag` | `number` | R/W | Global angular drag coefficient |
|
|
1326
|
+
| `bodies` | `NapeList<Body>` | R | All bodies |
|
|
1327
|
+
| `liveBodies` | `NapeList<Body>` | R | Awake bodies |
|
|
1328
|
+
| `compounds` | `NapeList<Compound>` | R | All compounds |
|
|
1329
|
+
| `constraints` | `NapeList<Constraint>` | R | All constraints |
|
|
1330
|
+
| `liveConstraints` | `NapeList<Constraint>` | R | Awake constraints |
|
|
1331
|
+
| `world` | `Body` | R | Static world body (immovable anchor) |
|
|
1332
|
+
| `arbiters` | `ArbiterList` | R | Active arbiters |
|
|
1333
|
+
| `listeners` | `ListenerList` | R | Event listeners |
|
|
1334
|
+
| `timeStamp` | `number` | R | Number of step() calls |
|
|
1335
|
+
| `elapsedTime` | `number` | R | Cumulative simulated time |
|
|
1336
|
+
| `userData` | `Record<string, unknown>` | R | User data |
|
|
1337
|
+
|
|
1338
|
+
#### Simulation
|
|
1339
|
+
|
|
1340
|
+
```typescript
|
|
1341
|
+
step(deltaTime: number, velocityIterations?: number, positionIterations?: number): void
|
|
1342
|
+
```
|
|
1343
|
+
Advance simulation by `deltaTime` seconds. Iterations default to 10 each.
|
|
1344
|
+
|
|
1345
|
+
```typescript
|
|
1346
|
+
clear(): void
|
|
1347
|
+
```
|
|
1348
|
+
Remove all bodies, constraints, compounds. Cannot be called during step().
|
|
1349
|
+
|
|
1350
|
+
#### Visitors
|
|
1351
|
+
|
|
1352
|
+
```typescript
|
|
1353
|
+
visitBodies(fn: (body: Body) => void): void // All bodies including in compounds
|
|
1354
|
+
visitConstraints(fn: (c: Constraint) => void): void
|
|
1355
|
+
visitCompounds(fn: (c: Compound) => void): void
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
#### Spatial Queries
|
|
1359
|
+
|
|
1360
|
+
```typescript
|
|
1361
|
+
// Point queries
|
|
1362
|
+
shapesUnderPoint(point: Vec2, filter?: InteractionFilter): ShapeList
|
|
1363
|
+
bodiesUnderPoint(point: Vec2, filter?: InteractionFilter): BodyList
|
|
1364
|
+
|
|
1365
|
+
// AABB queries
|
|
1366
|
+
shapesInAABB(aabb: AABB, containment?: boolean, strict?: boolean, filter?: InteractionFilter): ShapeList
|
|
1367
|
+
bodiesInAABB(aabb: AABB, containment?: boolean, strict?: boolean, filter?: InteractionFilter): BodyList
|
|
1368
|
+
|
|
1369
|
+
// Circle queries
|
|
1370
|
+
shapesInCircle(position: Vec2, radius: number, containment?: boolean, filter?: InteractionFilter): ShapeList
|
|
1371
|
+
bodiesInCircle(position: Vec2, radius: number, containment?: boolean, filter?: InteractionFilter): BodyList
|
|
1372
|
+
|
|
1373
|
+
// Shape queries
|
|
1374
|
+
shapesInShape(shape: Shape, containment?: boolean, filter?: InteractionFilter): ShapeList
|
|
1375
|
+
bodiesInShape(shape: Shape, containment?: boolean, filter?: InteractionFilter): BodyList
|
|
1376
|
+
|
|
1377
|
+
// Body queries (union of all shapes)
|
|
1378
|
+
shapesInBody(body: Body, filter?: InteractionFilter): ShapeList
|
|
1379
|
+
bodiesInBody(body: Body, filter?: InteractionFilter): BodyList
|
|
1380
|
+
```
|
|
1381
|
+
|
|
1382
|
+
#### Raycasting
|
|
1383
|
+
|
|
1384
|
+
```typescript
|
|
1385
|
+
rayCast(ray: Ray, inner?: boolean, filter?: InteractionFilter): RayResult | null
|
|
1386
|
+
rayMultiCast(ray: Ray, inner?: boolean, filter?: InteractionFilter): RayResultList
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
#### Convex Sweep
|
|
1390
|
+
|
|
1391
|
+
```typescript
|
|
1392
|
+
convexCast(shape: Shape, deltaTime: number, liveSweep?: boolean, filter?: InteractionFilter): RayResult | null
|
|
1393
|
+
convexMultiCast(shape: Shape, deltaTime: number, liveSweep?: boolean, filter?: InteractionFilter): RayResultList
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
#### Interaction Type Query
|
|
1397
|
+
|
|
1398
|
+
```typescript
|
|
1399
|
+
interactionType(shape1: Shape, shape2: Shape): InteractionType | null
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
---
|
|
1403
|
+
|
|
1404
|
+
### Broadphase (Enum)
|
|
1405
|
+
|
|
1406
|
+
| Value | Description |
|
|
1407
|
+
|-------|-------------|
|
|
1408
|
+
| `Broadphase.SWEEP_AND_PRUNE` | Good for many objects with little movement |
|
|
1409
|
+
| `Broadphase.DYNAMIC_AABB_TREE` | Good for dynamic scenes with varied object sizes |
|
|
1410
|
+
|
|
1411
|
+
---
|
|
1412
|
+
|
|
1413
|
+
## Collections
|
|
1414
|
+
|
|
1415
|
+
### NapeList\<T\>
|
|
1416
|
+
|
|
1417
|
+
Generic iterable list wrapping internal Haxe lists. Supports ES6 iteration.
|
|
1418
|
+
|
|
1419
|
+
| Property | Type | Description |
|
|
1420
|
+
|----------|------|-------------|
|
|
1421
|
+
| `length` | `number` | Number of elements |
|
|
1422
|
+
| `empty` | `boolean` | True if length is 0 |
|
|
1423
|
+
|
|
1424
|
+
| Method | Returns | Description |
|
|
1425
|
+
|--------|---------|-------------|
|
|
1426
|
+
| `at(index: number)` | `T` | Get element by index |
|
|
1427
|
+
| `push(item: T)` | `boolean` | Add to end |
|
|
1428
|
+
| `pop()` | `T` | Remove from end |
|
|
1429
|
+
| `unshift(item: T)` | `boolean` | Add to beginning |
|
|
1430
|
+
| `shift()` | `T` | Remove from beginning |
|
|
1431
|
+
| `add(item: T)` | `boolean` | Add item |
|
|
1432
|
+
| `remove(item: T)` | `boolean` | Remove item |
|
|
1433
|
+
| `has(item: T)` | `boolean` | Check if contains item |
|
|
1434
|
+
| `clear()` | `void` | Remove all items |
|
|
1435
|
+
| `forEach(fn: (item: T) => void)` | `void` | Iterate all items |
|
|
1436
|
+
| `toArray()` | `T[]` | Convert to JavaScript array |
|
|
1437
|
+
| `[Symbol.iterator]()` | `Iterator<T>` | ES6 iteration support |
|
|
1438
|
+
|
|
1439
|
+
#### Usage
|
|
1440
|
+
|
|
1441
|
+
```typescript
|
|
1442
|
+
// Iterate with for...of
|
|
1443
|
+
for (const body of space.bodies) {
|
|
1444
|
+
console.log(body.position.x, body.position.y);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Indexed access
|
|
1448
|
+
const first = space.bodies.at(0);
|
|
1449
|
+
|
|
1450
|
+
// Add/remove
|
|
1451
|
+
body.shapes.add(new Circle(20));
|
|
1452
|
+
body.shapes.remove(oldShape);
|
|
1453
|
+
|
|
1454
|
+
// Convert to array
|
|
1455
|
+
const bodyArray = space.bodies.toArray();
|
|
1456
|
+
```
|
|
1457
|
+
|
|
1458
|
+
---
|
|
1459
|
+
|
|
1460
|
+
## Common Patterns
|
|
1461
|
+
|
|
1462
|
+
### Adding Bodies to Space
|
|
1463
|
+
|
|
1464
|
+
```typescript
|
|
1465
|
+
const body = new Body(BodyType.DYNAMIC, new Vec2(100, 100));
|
|
1466
|
+
body.shapes.add(new Circle(25));
|
|
1467
|
+
body.space = space; // This adds the body to the space
|
|
1468
|
+
```
|
|
1469
|
+
|
|
1470
|
+
### Removing Bodies
|
|
1471
|
+
|
|
1472
|
+
```typescript
|
|
1473
|
+
body.space = null; // Removes from space
|
|
1474
|
+
```
|
|
1475
|
+
|
|
1476
|
+
### Applying Forces
|
|
1477
|
+
|
|
1478
|
+
```typescript
|
|
1479
|
+
// Continuous force (applied per step)
|
|
1480
|
+
body.force.setxy(100, 0);
|
|
1481
|
+
|
|
1482
|
+
// One-time impulse
|
|
1483
|
+
body.applyImpulse(new Vec2(500, 0));
|
|
1484
|
+
|
|
1485
|
+
// Impulse at a point (creates torque)
|
|
1486
|
+
body.applyImpulse(new Vec2(0, -100), new Vec2(body.position.x + 10, body.position.y));
|
|
1487
|
+
```
|
|
1488
|
+
|
|
1489
|
+
### Sensors
|
|
1490
|
+
|
|
1491
|
+
```typescript
|
|
1492
|
+
const sensor = new Circle(50);
|
|
1493
|
+
sensor.sensorEnabled = true;
|
|
1494
|
+
body.shapes.add(sensor);
|
|
1495
|
+
|
|
1496
|
+
space.listeners.add(new InteractionListener(
|
|
1497
|
+
CbEvent.BEGIN, InteractionType.SENSOR,
|
|
1498
|
+
CbType.ANY_BODY, CbType.ANY_BODY,
|
|
1499
|
+
(cb) => console.log("Sensor triggered!")
|
|
1500
|
+
));
|
|
1501
|
+
```
|
|
1502
|
+
|
|
1503
|
+
### Fluids
|
|
1504
|
+
|
|
1505
|
+
```typescript
|
|
1506
|
+
const water = new Body(BodyType.STATIC, new Vec2(400, 400));
|
|
1507
|
+
const waterShape = new Polygon(Polygon.box(800, 200));
|
|
1508
|
+
waterShape.fluidEnabled = true;
|
|
1509
|
+
waterShape.fluidProperties = new FluidProperties(2.0, 3.0);
|
|
1510
|
+
waterShape.sensorEnabled = true;
|
|
1511
|
+
water.shapes.add(waterShape);
|
|
1512
|
+
water.space = space;
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
### Collision Layers
|
|
1516
|
+
|
|
1517
|
+
```typescript
|
|
1518
|
+
const LAYER_PLAYER = 1;
|
|
1519
|
+
const LAYER_ENEMY = 2;
|
|
1520
|
+
const LAYER_BULLET = 4;
|
|
1521
|
+
|
|
1522
|
+
// Player collides with enemy and bullet
|
|
1523
|
+
playerShape.filter = new InteractionFilter(LAYER_PLAYER, LAYER_ENEMY | LAYER_BULLET);
|
|
1524
|
+
|
|
1525
|
+
// Enemy collides with player and bullet
|
|
1526
|
+
enemyShape.filter = new InteractionFilter(LAYER_ENEMY, LAYER_PLAYER | LAYER_BULLET);
|
|
1527
|
+
|
|
1528
|
+
// Bullets collide with player and enemy (not each other)
|
|
1529
|
+
bulletShape.filter = new InteractionFilter(LAYER_BULLET, LAYER_PLAYER | LAYER_ENEMY);
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
### Spring Constraints
|
|
1533
|
+
|
|
1534
|
+
```typescript
|
|
1535
|
+
const spring = new DistanceJoint(body1, body2,
|
|
1536
|
+
new Vec2(0, 0), new Vec2(0, 0),
|
|
1537
|
+
50, 100 // min/max distance
|
|
1538
|
+
);
|
|
1539
|
+
spring.stiff = false; // Make it springy
|
|
1540
|
+
spring.frequency = 2.0; // 2 Hz oscillation
|
|
1541
|
+
spring.damping = 0.5; // Half critical damping
|
|
1542
|
+
spring.space = space;
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1545
|
+
### Raycasting
|
|
1546
|
+
|
|
1547
|
+
```typescript
|
|
1548
|
+
const ray = new Ray(new Vec2(0, 300), new Vec2(1, 0));
|
|
1549
|
+
ray.maxDistance = 800;
|
|
1550
|
+
|
|
1551
|
+
const result = space.rayCast(ray);
|
|
1552
|
+
if (result) {
|
|
1553
|
+
console.log("Hit shape:", result.shape);
|
|
1554
|
+
console.log("Hit point:", ray.at(result.distance));
|
|
1555
|
+
console.log("Normal:", result.normal);
|
|
1556
|
+
}
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
### One-Way Platforms
|
|
1560
|
+
|
|
1561
|
+
```typescript
|
|
1562
|
+
space.listeners.add(new PreListener(
|
|
1563
|
+
InteractionType.COLLISION,
|
|
1564
|
+
platformType, playerType,
|
|
1565
|
+
(cb) => {
|
|
1566
|
+
const arb = cb.arbiter.collisionArbiter;
|
|
1567
|
+
// Only collide if player is above platform (normal points up)
|
|
1568
|
+
if (arb.normal.y < 0) return PreFlag.ACCEPT;
|
|
1569
|
+
return PreFlag.IGNORE;
|
|
1570
|
+
}
|
|
1571
|
+
));
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
---
|
|
1575
|
+
|
|
1576
|
+
## Exports
|
|
1577
|
+
|
|
1578
|
+
All classes are available from the main entry point:
|
|
1579
|
+
|
|
1580
|
+
```typescript
|
|
1581
|
+
import {
|
|
1582
|
+
// Geometry
|
|
1583
|
+
Vec2, Vec3, Mat23, MatMN, AABB, Ray,
|
|
1584
|
+
ConvexResult, RayResult, Geom, GeomPoly,
|
|
1585
|
+
Winding, MarchingSquares,
|
|
1586
|
+
|
|
1587
|
+
// Physics
|
|
1588
|
+
Body, BodyType, Compound, Interactor,
|
|
1589
|
+
Material, FluidProperties,
|
|
1590
|
+
MassMode, InertiaMode, GravMassMode,
|
|
1591
|
+
|
|
1592
|
+
// Shapes
|
|
1593
|
+
Shape, Circle, Polygon, Edge,
|
|
1594
|
+
ShapeType, ValidationResult,
|
|
1595
|
+
|
|
1596
|
+
// Space
|
|
1597
|
+
Space, Broadphase,
|
|
1598
|
+
|
|
1599
|
+
// Dynamics
|
|
1600
|
+
Arbiter, CollisionArbiter, FluidArbiter,
|
|
1601
|
+
Contact, ArbiterType,
|
|
1602
|
+
InteractionFilter, InteractionGroup,
|
|
1603
|
+
|
|
1604
|
+
// Callbacks
|
|
1605
|
+
CbEvent, CbType, Listener,
|
|
1606
|
+
BodyListener, InteractionListener,
|
|
1607
|
+
ConstraintListener, PreListener,
|
|
1608
|
+
Callback, BodyCallback,
|
|
1609
|
+
InteractionCallback, ConstraintCallback, PreCallback,
|
|
1610
|
+
InteractionType, ListenerType, PreFlag, OptionType,
|
|
1611
|
+
|
|
1612
|
+
// Constraints
|
|
1613
|
+
Constraint, PivotJoint, DistanceJoint,
|
|
1614
|
+
AngleJoint, WeldJoint, MotorJoint,
|
|
1615
|
+
LineJoint, PulleyJoint,
|
|
1616
|
+
|
|
1617
|
+
// Utilities
|
|
1618
|
+
NapeList, VERSION
|
|
1619
|
+
} from "@newkrok/nape-js";
|
|
1620
|
+
```
|