@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/Collider.js
CHANGED
|
@@ -1,160 +1,266 @@
|
|
|
1
|
-
import { createAabb } from
|
|
2
|
-
import {
|
|
3
|
-
import { resolveFilter } from
|
|
1
|
+
import { createAabb } from "./Aabb.js";
|
|
2
|
+
import { applyRotation, applyTransform, composeTransforms, createTransform } from "./math.js";
|
|
3
|
+
import { resolveFilter } from "./types.js";
|
|
4
4
|
|
|
5
|
+
//#region src/Collider.ts
|
|
6
|
+
/** Number of world-space vertices a shape kind caches on its collider. */
|
|
7
|
+
const worldVertexCount = (shape) => {
|
|
8
|
+
switch (shape.type) {
|
|
9
|
+
case "polygon": return shape.count;
|
|
10
|
+
case "capsule":
|
|
11
|
+
case "segment": return 2;
|
|
12
|
+
case "circle":
|
|
13
|
+
case "chain": return 0;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
5
16
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Collider {
|
|
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
|
-
|
|
17
|
+
* Geometry attached to a {@link PhysicsBody}: a {@link Shape} plus a body-local
|
|
18
|
+
* offset/rotation, material (friction/restitution/density) and a collision
|
|
19
|
+
* filter. A body may own several colliders (compound). The collider also caches
|
|
20
|
+
* its world-space geometry - refreshed by {@link synchronize} - which the broad
|
|
21
|
+
* phase, narrow phase and queries read directly.
|
|
22
|
+
*
|
|
23
|
+
* Material fields and the filter are mutable; the shape and local placement are
|
|
24
|
+
* immutable (rebuild the collider to change geometry).
|
|
25
|
+
*/
|
|
26
|
+
var Collider = class Collider {
|
|
27
|
+
/** Stable id, assigned when the owning body joins a world (`-1` until then). */
|
|
28
|
+
shape;
|
|
29
|
+
offsetX;
|
|
30
|
+
offsetY;
|
|
31
|
+
localRotation;
|
|
32
|
+
density;
|
|
33
|
+
friction;
|
|
34
|
+
restitution;
|
|
35
|
+
isSensor;
|
|
36
|
+
filter;
|
|
37
|
+
_id = -1;
|
|
38
|
+
_body = null;
|
|
39
|
+
_chainEdges;
|
|
40
|
+
_chainParent = null;
|
|
41
|
+
_localTransform;
|
|
42
|
+
_worldTransform = createTransform();
|
|
43
|
+
_aabb = createAabb();
|
|
44
|
+
_worldCenter = {
|
|
45
|
+
x: 0,
|
|
46
|
+
y: 0
|
|
47
|
+
};
|
|
48
|
+
_syncScratch = {
|
|
49
|
+
x: 0,
|
|
50
|
+
y: 0
|
|
51
|
+
};
|
|
52
|
+
_worldVertices;
|
|
53
|
+
_worldNormals;
|
|
54
|
+
_destroyed = false;
|
|
55
|
+
/**
|
|
56
|
+
* @internal - proxy id in the physics world's broad-phase spatial tree; `-1`
|
|
57
|
+
* when not inserted. Like `PhysicsBody._islandIndex`/`_sleepTime`, this is a
|
|
58
|
+
* single-owner slot: exactly ONE `AabbTreeBroadPhase` may track this collider
|
|
59
|
+
* at a time (in production, the world's own broad phase for the collider's
|
|
60
|
+
* whole lifetime). A second broad phase over the same collider would clobber
|
|
61
|
+
* this value and corrupt the first's tree - never do that.
|
|
62
|
+
*/
|
|
63
|
+
_treeProxy = -1;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
const density = options.density ?? 1;
|
|
66
|
+
if (!Number.isFinite(density) || density < 0) throw new RangeError(`Collider: density must be a non-negative finite number, received ${density}.`);
|
|
67
|
+
this.shape = options.shape;
|
|
68
|
+
this.offsetX = options.offset?.x ?? 0;
|
|
69
|
+
this.offsetY = options.offset?.y ?? 0;
|
|
70
|
+
this.localRotation = options.rotation ?? 0;
|
|
71
|
+
this.density = density;
|
|
72
|
+
this.friction = options.friction ?? .2;
|
|
73
|
+
this.restitution = options.restitution ?? 0;
|
|
74
|
+
this.isSensor = options.isSensor ?? false;
|
|
75
|
+
this.filter = resolveFilter(options.filter);
|
|
76
|
+
this._localTransform = createTransform(this.offsetX, this.offsetY, this.localRotation);
|
|
77
|
+
const vertexCount = worldVertexCount(this.shape);
|
|
78
|
+
this._worldVertices = new Array(vertexCount * 2).fill(0);
|
|
79
|
+
this._worldNormals = new Array(vertexCount * 2).fill(0);
|
|
80
|
+
this._chainEdges = this.shape.type === "chain" ? this._buildChainEdges(this.shape) : null;
|
|
81
|
+
}
|
|
82
|
+
/** Stable id, assigned when the owning body joins a world via `world.add()`; `-1` until then. */
|
|
83
|
+
get id() {
|
|
84
|
+
return this._id;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The body this collider belongs to. `null` until the collider has been added
|
|
88
|
+
* to a body that has joined a world (free-standing colliders have no body yet).
|
|
89
|
+
*/
|
|
90
|
+
get body() {
|
|
91
|
+
if (this._body === null) throw new Error("Collider: this collider has not been attached to a body in a world yet.");
|
|
92
|
+
return this._body;
|
|
93
|
+
}
|
|
94
|
+
/** The collider's world AABB (valid after the latest {@link synchronize}). */
|
|
95
|
+
get aabb() {
|
|
96
|
+
return this._aabb;
|
|
97
|
+
}
|
|
98
|
+
/** The collider's world transform (offset/rotation composed with the body's). */
|
|
99
|
+
get worldTransform() {
|
|
100
|
+
return this._worldTransform;
|
|
101
|
+
}
|
|
102
|
+
/** The collider's body-local transform (offset + local rotation). */
|
|
103
|
+
get localTransform() {
|
|
104
|
+
return this._localTransform;
|
|
105
|
+
}
|
|
106
|
+
/** World-space circle centre (only meaningful for circle shapes). */
|
|
107
|
+
get worldCenter() {
|
|
108
|
+
return this._worldCenter;
|
|
109
|
+
}
|
|
110
|
+
/** World-space polygon vertices `[x0, y0, ...]` (only meaningful for polygon shapes). */
|
|
111
|
+
get worldVertices() {
|
|
112
|
+
return this._worldVertices;
|
|
113
|
+
}
|
|
114
|
+
/** World-space polygon outward normals `[x0, y0, ...]` (only meaningful for polygon shapes). */
|
|
115
|
+
get worldNormals() {
|
|
116
|
+
return this._worldNormals;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* @internal - the engine-owned edge proxies a chain collider fans out into,
|
|
120
|
+
* one per chain edge; `null` for every other shape. They are what the broad
|
|
121
|
+
* phase, the narrow phase and the solver see, so a chain contact reuses the
|
|
122
|
+
* one-manifold-per-pair model unchanged. They are never part of
|
|
123
|
+
* `body.colliders`, `world.colliders` or any query result - the authored
|
|
124
|
+
* collider is the public identity of every contact they produce.
|
|
125
|
+
*/
|
|
126
|
+
get chainEdges() {
|
|
127
|
+
return this._chainEdges;
|
|
128
|
+
}
|
|
129
|
+
/** @internal - the authored chain collider this edge proxy belongs to; `null` for an authored collider. */
|
|
130
|
+
get chainParent() {
|
|
131
|
+
return this._chainParent;
|
|
132
|
+
}
|
|
133
|
+
/** `true` after the owning world has destroyed this collider. */
|
|
134
|
+
get destroyed() {
|
|
135
|
+
return this._destroyed;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Recompute the cached world geometry from the body's transform. Called by the
|
|
139
|
+
* body on `setTransform`, on collider creation, and by the world before each
|
|
140
|
+
* detection pass.
|
|
141
|
+
*/
|
|
142
|
+
synchronize(bodyTransform) {
|
|
143
|
+
const world = composeTransforms(bodyTransform, this._localTransform, this._worldTransform);
|
|
144
|
+
switch (this.shape.type) {
|
|
145
|
+
case "circle":
|
|
146
|
+
this._synchronizeCircle(world, this.shape.radius);
|
|
147
|
+
break;
|
|
148
|
+
case "capsule":
|
|
149
|
+
this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, 2, this.shape.radius);
|
|
150
|
+
break;
|
|
151
|
+
case "segment":
|
|
152
|
+
this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, 2, 0);
|
|
153
|
+
break;
|
|
154
|
+
case "polygon":
|
|
155
|
+
this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, this.shape.count, 0);
|
|
156
|
+
break;
|
|
157
|
+
case "chain": this._synchronizeChain(bodyTransform);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A chain's world geometry is its edge proxies': each of them shares the
|
|
162
|
+
* chain's local placement and syncs its own two endpoints, and the chain's own
|
|
163
|
+
* AABB is their union. Nothing is transformed twice, and no proxy is rebuilt.
|
|
164
|
+
*/
|
|
165
|
+
_synchronizeChain(bodyTransform) {
|
|
166
|
+
const edges = this._chainEdges;
|
|
167
|
+
let minX = Infinity;
|
|
168
|
+
let minY = Infinity;
|
|
169
|
+
let maxX = -Infinity;
|
|
170
|
+
let maxY = -Infinity;
|
|
171
|
+
for (const edge of edges) {
|
|
172
|
+
edge.synchronize(bodyTransform);
|
|
173
|
+
const aabb = edge.aabb;
|
|
174
|
+
minX = aabb.minX < minX ? aabb.minX : minX;
|
|
175
|
+
minY = aabb.minY < minY ? aabb.minY : minY;
|
|
176
|
+
maxX = aabb.maxX > maxX ? aabb.maxX : maxX;
|
|
177
|
+
maxY = aabb.maxY > maxY ? aabb.maxY : maxY;
|
|
178
|
+
}
|
|
179
|
+
this._aabb.minX = minX;
|
|
180
|
+
this._aabb.minY = minY;
|
|
181
|
+
this._aabb.maxX = maxX;
|
|
182
|
+
this._aabb.maxY = maxY;
|
|
183
|
+
}
|
|
184
|
+
/** A circle is its transformed centre; the local vertex buffers stay unused. */
|
|
185
|
+
_synchronizeCircle(world, radius) {
|
|
186
|
+
this._worldCenter.x = world.x;
|
|
187
|
+
this._worldCenter.y = world.y;
|
|
188
|
+
this._aabb.minX = world.x - radius;
|
|
189
|
+
this._aabb.minY = world.y - radius;
|
|
190
|
+
this._aabb.maxX = world.x + radius;
|
|
191
|
+
this._aabb.maxY = world.y + radius;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Transform a local vertex/normal ring into the world buffers and take the
|
|
195
|
+
* AABB while doing it. `radius` inflates the box for a rounded outline (a
|
|
196
|
+
* capsule's spine); it is `0` for a plain polygon.
|
|
197
|
+
*/
|
|
198
|
+
_synchronizePolygon(world, local, normals, count, radius) {
|
|
199
|
+
const out = this._syncScratch;
|
|
200
|
+
let minX = Infinity;
|
|
201
|
+
let minY = Infinity;
|
|
202
|
+
let maxX = -Infinity;
|
|
203
|
+
let maxY = -Infinity;
|
|
204
|
+
for (let i = 0; i < count; i++) {
|
|
205
|
+
applyTransform(world, local[i * 2], local[i * 2 + 1], out);
|
|
206
|
+
this._worldVertices[i * 2] = out.x;
|
|
207
|
+
this._worldVertices[i * 2 + 1] = out.y;
|
|
208
|
+
minX = out.x < minX ? out.x : minX;
|
|
209
|
+
minY = out.y < minY ? out.y : minY;
|
|
210
|
+
maxX = out.x > maxX ? out.x : maxX;
|
|
211
|
+
maxY = out.y > maxY ? out.y : maxY;
|
|
212
|
+
applyRotation(world, normals[i * 2], normals[i * 2 + 1], out);
|
|
213
|
+
this._worldNormals[i * 2] = out.x;
|
|
214
|
+
this._worldNormals[i * 2 + 1] = out.y;
|
|
215
|
+
}
|
|
216
|
+
this._aabb.minX = minX - radius;
|
|
217
|
+
this._aabb.minY = minY - radius;
|
|
218
|
+
this._aabb.maxX = maxX + radius;
|
|
219
|
+
this._aabb.maxY = maxY + radius;
|
|
220
|
+
}
|
|
221
|
+
/** @internal - bind this collider to its body and id (called when the body joins a world). */
|
|
222
|
+
_attach(body, id) {
|
|
223
|
+
this._body = body;
|
|
224
|
+
this._id = id;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Fan a chain out into one proxy per edge. Each proxy carries the chain's own
|
|
228
|
+
* local placement, so it needs no transform of its own, and its shape carries
|
|
229
|
+
* the adjacency that keeps a body from snagging at a shared vertex.
|
|
230
|
+
*/
|
|
231
|
+
_buildChainEdges(chain) {
|
|
232
|
+
const edges = [];
|
|
233
|
+
for (const edgeShape of chain.edges) {
|
|
234
|
+
const edge = new Collider({
|
|
235
|
+
shape: edgeShape,
|
|
236
|
+
offset: {
|
|
237
|
+
x: this.offsetX,
|
|
238
|
+
y: this.offsetY
|
|
239
|
+
},
|
|
240
|
+
rotation: this.localRotation,
|
|
241
|
+
density: 0
|
|
242
|
+
});
|
|
243
|
+
edge._chainParent = this;
|
|
244
|
+
edges.push(edge);
|
|
245
|
+
}
|
|
246
|
+
return edges;
|
|
247
|
+
}
|
|
248
|
+
/** Internal: mark destroyed (called by the world). */
|
|
249
|
+
_markDestroyed() {
|
|
250
|
+
this._destroyed = true;
|
|
251
|
+
if (this._chainEdges !== null) for (const edge of this._chainEdges) edge._destroyed = true;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* The authored collider a contact, query hit or sweep target belongs to: the
|
|
256
|
+
* collider itself, or the chain it is an engine-owned edge proxy of. Every
|
|
257
|
+
* public identity - events, query results, the contact modifier - goes through
|
|
258
|
+
* this, so a solver-side partition never reaches a caller.
|
|
259
|
+
*
|
|
260
|
+
* @internal
|
|
261
|
+
*/
|
|
262
|
+
const authoredCollider = (collider) => collider.chainParent ?? collider;
|
|
158
263
|
|
|
159
|
-
|
|
160
|
-
|
|
264
|
+
//#endregion
|
|
265
|
+
export { Collider, authoredCollider };
|
|
266
|
+
//# sourceMappingURL=Collider.js.map
|
package/dist/esm/Collider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collider.js","sources":["../../../src/Collider.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Collider.js","names":[],"sources":["../../src/Collider.ts"],"sourcesContent":["import type { AabbLike, PointLike } from '@codexo/exojs';\n\nimport { createAabb } from './Aabb';\nimport type { Transform } from './math';\nimport { applyRotation, applyTransform, composeTransforms, createTransform } from './math';\nimport type { PhysicsBody } from './PhysicsBody';\nimport type { AnyShape } from './shapes/AnyShape';\nimport type { ChainShape } from './shapes/ChainShape';\nimport type { CollisionFilter } from './types';\nimport { resolveFilter } from './types';\n\n/** Number of world-space vertices a shape kind caches on its collider. */\nconst worldVertexCount = (shape: AnyShape): number => {\n switch (shape.type) {\n case 'polygon':\n return shape.count;\n case 'capsule':\n case 'segment':\n // Two endpoints. Both are a two-vertex ring, with and without a radius.\n return 2;\n case 'circle':\n case 'chain':\n // A chain caches nothing of its own: its geometry lives on the per-edge\n // child proxies, and its AABB is the union of theirs.\n return 0;\n }\n};\n\n/** Construction options for a collider. */\nexport interface ColliderOptions {\n /** The collision geometry. */\n shape: AnyShape;\n /** Density (mass per px²) for the owning body's mass; ignored for static/kinematic. Default `1`. */\n density?: number;\n /** Coulomb friction coefficient (used by the solver once dynamics ship). Default `0.2`. */\n friction?: number;\n /** Restitution / bounciness in `[0, 1]` (used by the solver once dynamics ship). Default `0`. */\n restitution?: number;\n /** When `true`, generates overlap events but no contact response. Default `false`. */\n isSensor?: boolean;\n /** Category/mask/group filter; partials merge over the defaults. */\n filter?: Partial<CollisionFilter>;\n /** Body-local offset of the shape origin. Default `(0, 0)`. */\n offset?: Readonly<PointLike>;\n /** Body-local rotation of the shape in radians (compound colliders). Default `0`. */\n rotation?: number;\n}\n\n/**\n * Geometry attached to a {@link PhysicsBody}: a {@link Shape} plus a body-local\n * offset/rotation, material (friction/restitution/density) and a collision\n * filter. A body may own several colliders (compound). The collider also caches\n * its world-space geometry - refreshed by {@link synchronize} - which the broad\n * phase, narrow phase and queries read directly.\n *\n * Material fields and the filter are mutable; the shape and local placement are\n * immutable (rebuild the collider to change geometry).\n */\nexport class Collider {\n /** Stable id, assigned when the owning body joins a world (`-1` until then). */\n public readonly shape: AnyShape;\n public readonly offsetX: number;\n public readonly offsetY: number;\n public readonly localRotation: number;\n\n public density: number;\n public friction: number;\n public restitution: number;\n public isSensor: boolean;\n public readonly filter: CollisionFilter;\n\n private _id = -1;\n private _body: PhysicsBody | null = null;\n private readonly _chainEdges: readonly Collider[] | null;\n private _chainParent: Collider | null = null;\n private readonly _localTransform: Transform;\n private readonly _worldTransform: Transform = createTransform();\n private readonly _aabb: AabbLike = createAabb();\n private readonly _worldCenter: PointLike = { x: 0, y: 0 };\n // Reused per-vertex scratch for synchronize()'s polygon transform loop so a\n // collider sync allocates nothing. Instance-private: never held across the\n // call, never aliased between colliders.\n private readonly _syncScratch: PointLike = { x: 0, y: 0 };\n private readonly _worldVertices: number[];\n private readonly _worldNormals: number[];\n\n private _destroyed = false;\n\n /**\n * @internal - proxy id in the physics world's broad-phase spatial tree; `-1`\n * when not inserted. Like `PhysicsBody._islandIndex`/`_sleepTime`, this is a\n * single-owner slot: exactly ONE `AabbTreeBroadPhase` may track this collider\n * at a time (in production, the world's own broad phase for the collider's\n * whole lifetime). A second broad phase over the same collider would clobber\n * this value and corrupt the first's tree - never do that.\n */\n public _treeProxy = -1;\n\n public constructor(options: ColliderOptions) {\n const density = options.density ?? 1;\n\n if (!Number.isFinite(density) || density < 0) {\n throw new RangeError(`Collider: density must be a non-negative finite number, received ${density}.`);\n }\n\n this.shape = options.shape;\n this.offsetX = options.offset?.x ?? 0;\n this.offsetY = options.offset?.y ?? 0;\n this.localRotation = options.rotation ?? 0;\n this.density = density;\n this.friction = options.friction ?? 0.2;\n this.restitution = options.restitution ?? 0;\n this.isSensor = options.isSensor ?? false;\n this.filter = resolveFilter(options.filter);\n this._localTransform = createTransform(this.offsetX, this.offsetY, this.localRotation);\n\n const vertexCount = worldVertexCount(this.shape);\n\n this._worldVertices = new Array<number>(vertexCount * 2).fill(0);\n this._worldNormals = new Array<number>(vertexCount * 2).fill(0);\n this._chainEdges = this.shape.type === 'chain' ? this._buildChainEdges(this.shape) : null;\n }\n\n /** Stable id, assigned when the owning body joins a world via `world.add()`; `-1` until then. */\n public get id(): number {\n return this._id;\n }\n\n /**\n * The body this collider belongs to. `null` until the collider has been added\n * to a body that has joined a world (free-standing colliders have no body yet).\n */\n public get body(): PhysicsBody {\n if (this._body === null) {\n throw new Error('Collider: this collider has not been attached to a body in a world yet.');\n }\n\n return this._body;\n }\n\n /** The collider's world AABB (valid after the latest {@link synchronize}). */\n public get aabb(): Readonly<AabbLike> {\n return this._aabb;\n }\n\n /** The collider's world transform (offset/rotation composed with the body's). */\n public get worldTransform(): Readonly<Transform> {\n return this._worldTransform;\n }\n\n /** The collider's body-local transform (offset + local rotation). */\n public get localTransform(): Readonly<Transform> {\n return this._localTransform;\n }\n\n /** World-space circle centre (only meaningful for circle shapes). */\n public get worldCenter(): Readonly<PointLike> {\n return this._worldCenter;\n }\n\n /** World-space polygon vertices `[x0, y0, ...]` (only meaningful for polygon shapes). */\n public get worldVertices(): readonly number[] {\n return this._worldVertices;\n }\n\n /** World-space polygon outward normals `[x0, y0, ...]` (only meaningful for polygon shapes). */\n public get worldNormals(): readonly number[] {\n return this._worldNormals;\n }\n\n /**\n * @internal - the engine-owned edge proxies a chain collider fans out into,\n * one per chain edge; `null` for every other shape. They are what the broad\n * phase, the narrow phase and the solver see, so a chain contact reuses the\n * one-manifold-per-pair model unchanged. They are never part of\n * `body.colliders`, `world.colliders` or any query result - the authored\n * collider is the public identity of every contact they produce.\n */\n public get chainEdges(): readonly Collider[] | null {\n return this._chainEdges;\n }\n\n /** @internal - the authored chain collider this edge proxy belongs to; `null` for an authored collider. */\n public get chainParent(): Collider | null {\n return this._chainParent;\n }\n\n /** `true` after the owning world has destroyed this collider. */\n public get destroyed(): boolean {\n return this._destroyed;\n }\n\n /**\n * Recompute the cached world geometry from the body's transform. Called by the\n * body on `setTransform`, on collider creation, and by the world before each\n * detection pass.\n */\n public synchronize(bodyTransform: Transform): void {\n const world = composeTransforms(bodyTransform, this._localTransform, this._worldTransform);\n\n switch (this.shape.type) {\n case 'circle':\n this._synchronizeCircle(world, this.shape.radius);\n break;\n case 'capsule':\n // A capsule is a two-vertex ring plus a radius, so it rides the polygon\n // path and only the AABB inflation differs.\n this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, 2, this.shape.radius);\n break;\n case 'segment':\n this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, 2, 0);\n break;\n case 'polygon':\n this._synchronizePolygon(world, this.shape.vertices, this.shape.normals, this.shape.count, 0);\n break;\n case 'chain':\n this._synchronizeChain(bodyTransform);\n break;\n }\n }\n\n /**\n * A chain's world geometry is its edge proxies': each of them shares the\n * chain's local placement and syncs its own two endpoints, and the chain's own\n * AABB is their union. Nothing is transformed twice, and no proxy is rebuilt.\n */\n private _synchronizeChain(bodyTransform: Transform): void {\n const edges = this._chainEdges!;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const edge of edges) {\n edge.synchronize(bodyTransform);\n\n const aabb = edge.aabb;\n\n minX = aabb.minX < minX ? aabb.minX : minX;\n minY = aabb.minY < minY ? aabb.minY : minY;\n maxX = aabb.maxX > maxX ? aabb.maxX : maxX;\n maxY = aabb.maxY > maxY ? aabb.maxY : maxY;\n }\n\n this._aabb.minX = minX;\n this._aabb.minY = minY;\n this._aabb.maxX = maxX;\n this._aabb.maxY = maxY;\n }\n\n /** A circle is its transformed centre; the local vertex buffers stay unused. */\n private _synchronizeCircle(world: Transform, radius: number): void {\n this._worldCenter.x = world.x;\n this._worldCenter.y = world.y;\n this._aabb.minX = world.x - radius;\n this._aabb.minY = world.y - radius;\n this._aabb.maxX = world.x + radius;\n this._aabb.maxY = world.y + radius;\n }\n\n /**\n * Transform a local vertex/normal ring into the world buffers and take the\n * AABB while doing it. `radius` inflates the box for a rounded outline (a\n * capsule's spine); it is `0` for a plain polygon.\n */\n private _synchronizePolygon(world: Transform, local: readonly number[], normals: readonly number[], count: number, radius: number): void {\n const out = this._syncScratch;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (let i = 0; i < count; i++) {\n applyTransform(world, local[i * 2]!, local[i * 2 + 1]!, out);\n this._worldVertices[i * 2] = out.x;\n this._worldVertices[i * 2 + 1] = out.y;\n minX = out.x < minX ? out.x : minX;\n minY = out.y < minY ? out.y : minY;\n maxX = out.x > maxX ? out.x : maxX;\n maxY = out.y > maxY ? out.y : maxY;\n\n applyRotation(world, normals[i * 2]!, normals[i * 2 + 1]!, out);\n this._worldNormals[i * 2] = out.x;\n this._worldNormals[i * 2 + 1] = out.y;\n }\n\n this._aabb.minX = minX - radius;\n this._aabb.minY = minY - radius;\n this._aabb.maxX = maxX + radius;\n this._aabb.maxY = maxY + radius;\n }\n\n /** @internal - bind this collider to its body and id (called when the body joins a world). */\n public _attach(body: PhysicsBody, id: number): void {\n this._body = body;\n this._id = id;\n }\n\n /**\n * Fan a chain out into one proxy per edge. Each proxy carries the chain's own\n * local placement, so it needs no transform of its own, and its shape carries\n * the adjacency that keeps a body from snagging at a shared vertex.\n */\n private _buildChainEdges(chain: ChainShape): readonly Collider[] {\n const edges: Collider[] = [];\n\n for (const edgeShape of chain.edges) {\n const edge = new Collider({\n shape: edgeShape,\n offset: { x: this.offsetX, y: this.offsetY },\n rotation: this.localRotation,\n // Material, filter and sensor flag stay mutable on the authored collider\n // and are read from there per pass, so copying them here would only add a\n // second, staler source of truth.\n density: 0,\n });\n\n edge._chainParent = this;\n edges.push(edge);\n }\n\n return edges;\n }\n\n /** Internal: mark destroyed (called by the world). */\n public _markDestroyed(): void {\n this._destroyed = true;\n\n if (this._chainEdges !== null) {\n for (const edge of this._chainEdges) {\n edge._destroyed = true;\n }\n }\n }\n}\n\n/**\n * The authored collider a contact, query hit or sweep target belongs to: the\n * collider itself, or the chain it is an engine-owned edge proxy of. Every\n * public identity - events, query results, the contact modifier - goes through\n * this, so a solver-side partition never reaches a caller.\n *\n * @internal\n */\nexport const authoredCollider = (collider: Collider): Collider => collider.chainParent ?? collider;\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CandidatePair } from './broadphase/BroadPhase';
|
|
2
2
|
import type { Collider } from './Collider';
|
|
3
3
|
import { Manifold } from './collision/Manifold';
|
|
4
|
+
import type { ContactModifier } from './ContactModifier';
|
|
4
5
|
import type { CollisionEvent, SensorEvent } from './events';
|
|
5
6
|
/**
|
|
6
7
|
* Persistent per-pair contact state. For solid contacts it carries a manifold
|
|
@@ -10,9 +11,25 @@ import type { CollisionEvent, SensorEvent } from './events';
|
|
|
10
11
|
export interface ContactRecord {
|
|
11
12
|
readonly a: Collider;
|
|
12
13
|
readonly b: Collider;
|
|
14
|
+
/**
|
|
15
|
+
* Authored collider behind {@link a} - itself, unless `a` is an engine-owned
|
|
16
|
+
* chain edge proxy, in which case it is the chain collider the caller made.
|
|
17
|
+
* Solver identity is the proxy pair; public identity is the authored pair.
|
|
18
|
+
*/
|
|
19
|
+
readonly ownerA: Collider;
|
|
20
|
+
readonly ownerB: Collider;
|
|
13
21
|
readonly isSensor: boolean;
|
|
14
22
|
touching: boolean;
|
|
15
23
|
seen: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Per-step solver participation. Re-derived to `true` for every touching solid
|
|
26
|
+
* contact each pass, then optionally cleared by the world's `ContactModifier`.
|
|
27
|
+
*/
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
/** Per-step Coulomb friction, re-derived from the two colliders each pass. */
|
|
30
|
+
friction: number;
|
|
31
|
+
/** Per-step restitution, re-derived from the two colliders each pass. */
|
|
32
|
+
restitution: number;
|
|
16
33
|
/** Persistent manifold (solid contacts), refreshed each pass by the narrow phase. */
|
|
17
34
|
readonly manifold: Manifold;
|
|
18
35
|
/** Accumulated normal impulse per contact point, carried across steps (warm-start). */
|
|
@@ -27,11 +44,16 @@ export interface ContactRecord {
|
|
|
27
44
|
* touching collider pairs against the previous pass and produces immutable
|
|
28
45
|
* begin/end (and sensor enter/exit) event snapshots. Duplicate begin/end churn
|
|
29
46
|
* is suppressed by the persistent records, and the produced event arrays are
|
|
30
|
-
* sorted by collider id for deterministic dispatch
|
|
47
|
+
* sorted by collider id for deterministic dispatch.
|
|
31
48
|
*
|
|
32
49
|
* Touching solid contacts are also collected into {@link solidContacts} (with a
|
|
33
50
|
* warm-start impulse cache) for the dynamics solver. The graph holds no
|
|
34
|
-
* module-level state
|
|
51
|
+
* module-level state - each world owns one.
|
|
52
|
+
*
|
|
53
|
+
* Records are keyed on the pair the solver sees, which for a chain collider is
|
|
54
|
+
* one of its edge proxies. Events are not: a body touching several edges of one
|
|
55
|
+
* chain is one authored contact, so the graph reference-counts the authored pair
|
|
56
|
+
* behind its records and emits begin/end only on the first and last of them.
|
|
35
57
|
*/
|
|
36
58
|
export declare class ContactGraph {
|
|
37
59
|
/** Immutable solid-contact begin snapshots produced by the latest {@link update}. */
|
|
@@ -42,21 +64,44 @@ export declare class ContactGraph {
|
|
|
42
64
|
readonly sensorEnter: SensorEvent[];
|
|
43
65
|
/** Immutable sensor-exit snapshots produced by the latest {@link update}. */
|
|
44
66
|
readonly sensorExit: SensorEvent[];
|
|
45
|
-
/** Touching solid contacts this pass, in deterministic order
|
|
67
|
+
/** Touching solid contacts this pass, in deterministic order - consumed by the solver. */
|
|
46
68
|
readonly solidContacts: ContactRecord[];
|
|
47
69
|
private readonly _records;
|
|
70
|
+
private readonly _authoredPairs;
|
|
71
|
+
private readonly _modifierContext;
|
|
48
72
|
/** Touching pairs currently tracked (for debug draw). */
|
|
49
73
|
get recordCount(): number;
|
|
50
74
|
/** Diff this pass's candidate pairs against the persistent set, collecting events + solid contacts. */
|
|
51
75
|
update(pairs: readonly CandidatePair[]): void;
|
|
52
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Run `modifier` over every touching solid contact of this pass. Called after
|
|
78
|
+
* detection and before island building, so a contact the modifier disables
|
|
79
|
+
* neither reaches the solver nor couples its two bodies into one sleeping
|
|
80
|
+
* island. A disabled contact's warm-start cache is dropped, so re-enabling it
|
|
81
|
+
* later starts from zero instead of releasing a stale impulse.
|
|
82
|
+
*/
|
|
83
|
+
applyModifier(modifier: ContactModifier): void;
|
|
84
|
+
/**
|
|
85
|
+
* Remove every record referencing `collider` (called when a collider is
|
|
86
|
+
* destroyed). Passing an authored chain collider also drops the records of
|
|
87
|
+
* every edge proxy it owns.
|
|
88
|
+
*/
|
|
53
89
|
removeCollider(collider: Collider): void;
|
|
54
90
|
/** Drop all records (world reset/destroy). */
|
|
55
91
|
clear(): void;
|
|
56
92
|
private _emitBegin;
|
|
57
93
|
private _emitEnd;
|
|
58
94
|
/**
|
|
59
|
-
*
|
|
95
|
+
* Count one more solver contact against the authored pair, reporting whether
|
|
96
|
+
* it is the first - the only one that may emit a begin event. A record whose
|
|
97
|
+
* colliders are the authored ones needs no counting at all, so a world without
|
|
98
|
+
* chains never touches the map.
|
|
99
|
+
*/
|
|
100
|
+
private _retainAuthoredPair;
|
|
101
|
+
/** Counterpart of {@link _retainAuthoredPair}: `true` on the last contact of the pair. */
|
|
102
|
+
private _releaseAuthoredPair;
|
|
103
|
+
/**
|
|
104
|
+
* `Map.forEach` callback (its `this` bound via the forEach thisArg) - drops a
|
|
60
105
|
* record the latest pass did not see, firing an end event if it was touching.
|
|
61
106
|
* A method reference + thisArg keeps the per-step iteration allocation-free,
|
|
62
107
|
* unlike `for (const [key, record] of map)` which allocates an entry tuple per
|
|
@@ -78,3 +123,4 @@ export declare const pairKeyStride = 67108864;
|
|
|
78
123
|
* @internal
|
|
79
124
|
*/
|
|
80
125
|
export declare const pairKey: (aId: number, bId: number) => number;
|
|
126
|
+
//# sourceMappingURL=ContactGraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContactGraph.d.ts","sourceRoot":"","sources":["../../src/ContactGraph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAgB,WAAW,EAAE,MAAM,UAAU,CAAC;AAI1E;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,uFAAuF;IACvF,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,wFAAwF;IACxF,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAY;IACvB,qFAAqF;IACrF,SAAgB,cAAc,EAAE,cAAc,EAAE,CAAM;IACtD,mFAAmF;IACnF,SAAgB,YAAY,EAAE,cAAc,EAAE,CAAM;IACpD,8EAA8E;IAC9E,SAAgB,WAAW,EAAE,WAAW,EAAE,CAAM;IAChD,6EAA6E;IAC7E,SAAgB,UAAU,EAAE,WAAW,EAAE,CAAM;IAC/C,0FAA0F;IAC1F,SAAgB,aAAa,EAAE,aAAa,EAAE,CAAM;IAIpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAG7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAC5D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuC;IAExE,yDAAyD;IACzD,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,uGAAuG;IAChG,MAAM,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IAyEpD;;;;;;OAMG;IACI,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAmBrD;;;;OAIG;IACI,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAY/C,8CAA8C;IACvC,KAAK,IAAI,IAAI;IAKpB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,QAAQ;IAYhB;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAa3B,0FAA0F;IAC1F,OAAO,CAAC,oBAAoB;IAmB5B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;CASxB;AAOD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAY,CAAC;AAEvC;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,MAAmC,CAAC"}
|