@ue-too/dynamics 0.9.4 → 0.10.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 +538 -4
- package/collision-filter.d.ts +115 -0
- package/constraint.d.ts +70 -0
- package/dynamic-tree.d.ts +16 -0
- package/index.d.ts +189 -0
- package/index.js +2 -1947
- package/index.js.map +9 -9
- package/package.json +3 -3
- package/pair-manager.d.ts +36 -0
- package/quadtree.d.ts +4 -0
- package/rigidbody.d.ts +21 -0
- package/world.d.ts +51 -0
package/constraint.d.ts
CHANGED
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
import { Point } from "@ue-too/math";
|
|
2
2
|
import { RigidBody } from "./rigidbody";
|
|
3
|
+
/**
|
|
4
|
+
* Physics constraint interface.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Constraints restrict the motion of rigid bodies. Common examples include
|
|
8
|
+
* pin joints, distance constraints, and angle limits.
|
|
9
|
+
*
|
|
10
|
+
* Constraints are solved using iterative methods and Baumgarte stabilization
|
|
11
|
+
* to prevent drift over time.
|
|
12
|
+
*
|
|
13
|
+
* @category Constraints
|
|
14
|
+
*/
|
|
3
15
|
export interface Constraint {
|
|
16
|
+
/**
|
|
17
|
+
* Enforces the constraint for one timestep.
|
|
18
|
+
*
|
|
19
|
+
* @param dt - Timestep in seconds
|
|
20
|
+
*/
|
|
4
21
|
enforce(dt: number): void;
|
|
5
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Pin joint connecting a body to a fixed world point.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* Creates a pendulum-like constraint where a point on the body is pinned
|
|
28
|
+
* to a fixed location in world space. The body can rotate around this point.
|
|
29
|
+
*
|
|
30
|
+
* Uses Baumgarte stabilization to prevent drift.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* Create a pendulum
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const bob = new Circle({ x: 0, y: 100 }, 20, 0, 10, false);
|
|
36
|
+
* const joint = new FixedPinJoint(
|
|
37
|
+
* bob,
|
|
38
|
+
* { x: 0, y: 0 }, // Anchor on bob (center)
|
|
39
|
+
* { x: 0, y: 0 } // World anchor (ceiling)
|
|
40
|
+
* );
|
|
41
|
+
* world.addRigidBody('bob', bob);
|
|
42
|
+
* world.addConstraint(joint);
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @category Constraints
|
|
46
|
+
*/
|
|
6
47
|
export declare class FixedPinJoint implements Constraint {
|
|
7
48
|
private anchorA;
|
|
8
49
|
private worldAnchorA;
|
|
@@ -11,6 +52,35 @@ export declare class FixedPinJoint implements Constraint {
|
|
|
11
52
|
enforce(dt: number): void;
|
|
12
53
|
solveWorldPinJointConstraint(dt: number): void;
|
|
13
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Pin joint connecting two bodies together.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* Connects two bodies at specified anchor points. The bodies can rotate
|
|
60
|
+
* relative to each other around the joint.
|
|
61
|
+
*
|
|
62
|
+
* Useful for creating chains, ragdolls, and mechanical linkages.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* Create a chain
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const link1 = new Circle({ x: 0, y: 0 }, 10);
|
|
68
|
+
* const link2 = new Circle({ x: 30, y: 0 }, 10);
|
|
69
|
+
*
|
|
70
|
+
* const joint = new PinJoint(
|
|
71
|
+
* link1,
|
|
72
|
+
* link2,
|
|
73
|
+
* { x: 10, y: 0 }, // Right edge of link1
|
|
74
|
+
* { x: -10, y: 0 } // Left edge of link2
|
|
75
|
+
* );
|
|
76
|
+
*
|
|
77
|
+
* world.addRigidBody('link1', link1);
|
|
78
|
+
* world.addRigidBody('link2', link2);
|
|
79
|
+
* world.addConstraint(joint);
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @category Constraints
|
|
83
|
+
*/
|
|
14
84
|
export declare class PinJoint implements Constraint {
|
|
15
85
|
private anchorA;
|
|
16
86
|
private anchorB;
|
package/dynamic-tree.d.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import { Point } from "@ue-too/math";
|
|
2
|
+
/**
|
|
3
|
+
* Object that can be indexed spatially via AABB.
|
|
4
|
+
* @category Types
|
|
5
|
+
*/
|
|
2
6
|
export interface SpatialIndexObject {
|
|
3
7
|
AABB: {
|
|
4
8
|
min: Point;
|
|
5
9
|
max: Point;
|
|
6
10
|
};
|
|
7
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Interface for spatial indexing data structures.
|
|
14
|
+
* @category Types
|
|
15
|
+
*/
|
|
8
16
|
export interface SpatialIndex<T extends SpatialIndexObject> {
|
|
9
17
|
clear(): void;
|
|
10
18
|
insert(object: T): void;
|
|
11
19
|
retrieve(object: T): T[];
|
|
12
20
|
draw?(context: CanvasRenderingContext2D): void;
|
|
13
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Sweep and Prune (SAP) spatial indexing algorithm.
|
|
24
|
+
* @category Spatial Indexing
|
|
25
|
+
*/
|
|
14
26
|
export declare class SweepAndPrune<T extends SpatialIndexObject> implements SpatialIndex<T> {
|
|
15
27
|
private xEndpoints;
|
|
16
28
|
private objects;
|
|
@@ -33,6 +45,10 @@ export declare class SweepAndPrune<T extends SpatialIndexObject> implements Spat
|
|
|
33
45
|
objectCount: number;
|
|
34
46
|
};
|
|
35
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Dynamic AABB tree for efficient spatial queries.
|
|
50
|
+
* @category Spatial Indexing
|
|
51
|
+
*/
|
|
36
52
|
export declare class DynamicTree<T extends SpatialIndexObject> implements SpatialIndex<T> {
|
|
37
53
|
private root;
|
|
38
54
|
private nodeCount;
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* 2D physics engine with rigid body dynamics and collision detection.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* The `@ue-too/dynamics` package provides a complete 2D physics simulation engine
|
|
7
|
+
* featuring rigid body dynamics, collision detection, constraint solving, and performance
|
|
8
|
+
* optimizations like spatial indexing and sleeping bodies.
|
|
9
|
+
*
|
|
10
|
+
* ## Core Components
|
|
11
|
+
*
|
|
12
|
+
* - **{@link World}**: Main physics world managing all simulation
|
|
13
|
+
* - **{@link RigidBody}**: Physical objects with mass, velocity, and rotation
|
|
14
|
+
* - **{@link Circle}**: Circular rigid body shape
|
|
15
|
+
* - **{@link Polygon}**: Polygonal rigid body shape
|
|
16
|
+
* - **{@link Constraint}**: Physics constraints (pin joints, etc.)
|
|
17
|
+
*
|
|
18
|
+
* ## Key Features
|
|
19
|
+
*
|
|
20
|
+
* ### Rigid Body Physics
|
|
21
|
+
* - Linear and angular velocity
|
|
22
|
+
* - Mass and moment of inertia
|
|
23
|
+
* - Static, dynamic, and kinematic bodies
|
|
24
|
+
* - Friction simulation (static and dynamic)
|
|
25
|
+
* - Gravity and force application
|
|
26
|
+
*
|
|
27
|
+
* ### Collision Detection
|
|
28
|
+
* - **Broad Phase**: Spatial indexing (QuadTree, Dynamic Tree, Sweep-and-Prune)
|
|
29
|
+
* - **Narrow Phase**: Separating Axis Theorem (SAT) for precise collision
|
|
30
|
+
* - AABB (Axis-Aligned Bounding Box) optimization
|
|
31
|
+
* - Collision filtering by category, mask, and group
|
|
32
|
+
*
|
|
33
|
+
* ### Collision Response
|
|
34
|
+
* - Impulse-based resolution
|
|
35
|
+
* - Rotation and angular momentum
|
|
36
|
+
* - Contact manifold generation
|
|
37
|
+
* - Restitution (bounciness)
|
|
38
|
+
*
|
|
39
|
+
* ### Performance Optimizations
|
|
40
|
+
* - **Sleeping System**: Automatically disable resting bodies
|
|
41
|
+
* - **Spatial Indexing**: Three algorithms with different trade-offs
|
|
42
|
+
* - QuadTree: Good for static worlds
|
|
43
|
+
* - Dynamic Tree: Good for mixed static/dynamic
|
|
44
|
+
* - Sweep-and-Prune: Best for many dynamic bodies
|
|
45
|
+
* - **Pair Management**: Efficient collision pair tracking
|
|
46
|
+
*
|
|
47
|
+
* ### Constraints
|
|
48
|
+
* - Pin joints between bodies
|
|
49
|
+
* - Fixed pin joints to world
|
|
50
|
+
* - Baumgarte stabilization
|
|
51
|
+
*
|
|
52
|
+
* ## Main Exports
|
|
53
|
+
*
|
|
54
|
+
* - {@link World} - Physics world container
|
|
55
|
+
* - {@link RigidBody} - Base rigid body interface
|
|
56
|
+
* - {@link Circle} - Circle shape
|
|
57
|
+
* - {@link Polygon} - Polygon shape
|
|
58
|
+
* - {@link Constraint} - Constraint interface
|
|
59
|
+
* - {@link PinJoint} - Pin joint constraint
|
|
60
|
+
* - {@link CollisionFilter} - Collision filtering system
|
|
61
|
+
* - {@link PairManager} - Collision pair tracking
|
|
62
|
+
* - {@link QuadTree} - QuadTree spatial index
|
|
63
|
+
* - {@link DynamicTree} - Dynamic AABB tree
|
|
64
|
+
* - {@link SweepAndPrune} - Sweep-and-prune algorithm
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* Basic physics simulation
|
|
68
|
+
* ```typescript
|
|
69
|
+
* import { World, Circle, Polygon } from '@ue-too/dynamics';
|
|
70
|
+
*
|
|
71
|
+
* // Create a physics world (2000x2000)
|
|
72
|
+
* const world = new World(2000, 2000, 'dynamictree');
|
|
73
|
+
*
|
|
74
|
+
* // Create a static ground
|
|
75
|
+
* const ground = new Polygon(
|
|
76
|
+
* { x: 0, y: -100 },
|
|
77
|
+
* [{ x: -1000, y: 0 }, { x: 1000, y: 0 }, { x: 1000, y: 50 }, { x: -1000, y: 50 }],
|
|
78
|
+
* 0,
|
|
79
|
+
* 100,
|
|
80
|
+
* true // isStatic
|
|
81
|
+
* );
|
|
82
|
+
* world.addRigidBody('ground', ground);
|
|
83
|
+
*
|
|
84
|
+
* // Create a dynamic circle
|
|
85
|
+
* const ball = new Circle({ x: 0, y: 200 }, 20, 0, 10, false);
|
|
86
|
+
* world.addRigidBody('ball', ball);
|
|
87
|
+
*
|
|
88
|
+
* // Simulation loop
|
|
89
|
+
* function update(deltaTime: number) {
|
|
90
|
+
* world.step(deltaTime);
|
|
91
|
+
* }
|
|
92
|
+
*
|
|
93
|
+
* // Run at 60 FPS
|
|
94
|
+
* setInterval(() => update(1/60), 16);
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* Collision filtering
|
|
99
|
+
* ```typescript
|
|
100
|
+
* import { Circle, CollisionCategory } from '@ue-too/dynamics';
|
|
101
|
+
*
|
|
102
|
+
* // Create player (collides with everything except other players)
|
|
103
|
+
* const player = new Circle({ x: 0, y: 0 }, 20);
|
|
104
|
+
* player.collisionFilter = {
|
|
105
|
+
* category: CollisionCategory.PLAYER,
|
|
106
|
+
* mask: ~CollisionCategory.PLAYER & 0xFFFF,
|
|
107
|
+
* group: 0
|
|
108
|
+
* };
|
|
109
|
+
*
|
|
110
|
+
* // Create enemy (collides with player and static objects)
|
|
111
|
+
* const enemy = new Circle({ x: 100, y: 0 }, 20);
|
|
112
|
+
* enemy.collisionFilter = {
|
|
113
|
+
* category: CollisionCategory.ENEMY,
|
|
114
|
+
* mask: CollisionCategory.PLAYER | CollisionCategory.STATIC,
|
|
115
|
+
* group: 0
|
|
116
|
+
* };
|
|
117
|
+
*
|
|
118
|
+
* // Create sensor (doesn't physically collide, just detects)
|
|
119
|
+
* const sensor = new Circle({ x: 200, y: 0 }, 50);
|
|
120
|
+
* sensor.collisionFilter = {
|
|
121
|
+
* category: CollisionCategory.SENSOR,
|
|
122
|
+
* mask: CollisionCategory.PLAYER,
|
|
123
|
+
* group: -1 // Negative group = never physically collide
|
|
124
|
+
* };
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* Constraints and joints
|
|
129
|
+
* ```typescript
|
|
130
|
+
* import { World, Circle, PinJoint, FixedPinJoint } from '@ue-too/dynamics';
|
|
131
|
+
*
|
|
132
|
+
* const world = new World(2000, 2000);
|
|
133
|
+
*
|
|
134
|
+
* // Create a pendulum with fixed pin joint
|
|
135
|
+
* const bob = new Circle({ x: 0, y: 100 }, 20, 0, 10, false);
|
|
136
|
+
* world.addRigidBody('bob', bob);
|
|
137
|
+
*
|
|
138
|
+
* const fixedJoint = new FixedPinJoint(
|
|
139
|
+
* bob,
|
|
140
|
+
* { x: 0, y: 0 }, // Local anchor on bob (center)
|
|
141
|
+
* { x: 0, y: 0 } // World anchor (fixed point)
|
|
142
|
+
* );
|
|
143
|
+
* world.addConstraint(fixedJoint);
|
|
144
|
+
*
|
|
145
|
+
* // Create a chain with pin joints between bodies
|
|
146
|
+
* const link1 = new Circle({ x: 50, y: 0 }, 10, 0, 5, false);
|
|
147
|
+
* const link2 = new Circle({ x: 100, y: 0 }, 10, 0, 5, false);
|
|
148
|
+
* world.addRigidBody('link1', link1);
|
|
149
|
+
* world.addRigidBody('link2', link2);
|
|
150
|
+
*
|
|
151
|
+
* const joint = new PinJoint(
|
|
152
|
+
* link1,
|
|
153
|
+
* link2,
|
|
154
|
+
* { x: 10, y: 0 }, // Anchor on link1 (right edge)
|
|
155
|
+
* { x: -10, y: 0 } // Anchor on link2 (left edge)
|
|
156
|
+
* );
|
|
157
|
+
* world.addConstraint(joint);
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* Performance tuning
|
|
162
|
+
* ```typescript
|
|
163
|
+
* import { World } from '@ue-too/dynamics';
|
|
164
|
+
*
|
|
165
|
+
* const world = new World(2000, 2000, 'sap'); // Use sweep-and-prune
|
|
166
|
+
*
|
|
167
|
+
* // Enable sleeping for performance
|
|
168
|
+
* world.sleepingEnabled = true;
|
|
169
|
+
*
|
|
170
|
+
* // Adjust sleeping thresholds on individual bodies
|
|
171
|
+
* body.sleepThreshold = 0.01; // Velocity threshold
|
|
172
|
+
* body.sleepTime = 0.5; // Time at rest before sleeping
|
|
173
|
+
*
|
|
174
|
+
* // Change spatial index algorithm at runtime
|
|
175
|
+
* world.setSpatialIndexType('dynamictree');
|
|
176
|
+
*
|
|
177
|
+
* // Get performance statistics
|
|
178
|
+
* const stats = world.getCollisionStats();
|
|
179
|
+
* console.log('Active pairs:', stats.activePairs);
|
|
180
|
+
* console.log('Sleeping bodies:', stats.sleepingBodies);
|
|
181
|
+
*
|
|
182
|
+
* const spatialStats = world.getSpatialIndexStats();
|
|
183
|
+
* console.log('Spatial index:', spatialStats);
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @see {@link World} for the main physics engine
|
|
187
|
+
* @see {@link RigidBody} for physics objects
|
|
188
|
+
* @see {@link Constraint} for joints and constraints
|
|
189
|
+
*/
|
|
1
190
|
export * from "./rigidbody";
|
|
2
191
|
export * from "./quadtree";
|
|
3
192
|
export * from "./dynamic-tree";
|