@codexo/exojs-physics 0.14.0 → 0.15.1
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/esm/PhysicsBody.d.ts +32 -0
- package/dist/esm/PhysicsBody.js +60 -2
- package/dist/esm/PhysicsBody.js.map +1 -1
- package/dist/esm/PhysicsWorld.d.ts +74 -8
- package/dist/esm/PhysicsWorld.js +279 -7
- package/dist/esm/PhysicsWorld.js.map +1 -1
- package/dist/esm/binding/BindingRegistry.d.ts +1 -2
- package/dist/esm/binding/BindingRegistry.js +2 -2
- package/dist/esm/binding/BindingRegistry.js.map +1 -1
- package/dist/esm/binding/PhysicsBinding.d.ts +1 -12
- package/dist/esm/binding/PhysicsBinding.js +1 -3
- package/dist/esm/binding/PhysicsBinding.js.map +1 -1
- package/dist/esm/debug/PhysicsDebugDraw.d.ts +6 -0
- package/dist/esm/debug/PhysicsDebugDraw.js +24 -1
- package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/joints/DistanceJoint.d.ts +71 -0
- package/dist/esm/joints/DistanceJoint.js +176 -0
- package/dist/esm/joints/DistanceJoint.js.map +1 -0
- package/dist/esm/joints/Joint.d.ts +25 -0
- package/dist/esm/joints/Joint.js +24 -0
- package/dist/esm/joints/Joint.js.map +1 -0
- package/dist/esm/joints/MouseJoint.d.ts +57 -0
- package/dist/esm/joints/MouseJoint.js +137 -0
- package/dist/esm/joints/MouseJoint.js.map +1 -0
- package/dist/esm/joints/PrismaticJoint.d.ts +85 -0
- package/dist/esm/joints/PrismaticJoint.js +241 -0
- package/dist/esm/joints/PrismaticJoint.js.map +1 -0
- package/dist/esm/joints/RevoluteJoint.d.ts +81 -0
- package/dist/esm/joints/RevoluteJoint.js +217 -0
- package/dist/esm/joints/RevoluteJoint.js.map +1 -0
- package/dist/esm/joints/WeldJoint.d.ts +61 -0
- package/dist/esm/joints/WeldJoint.js +159 -0
- package/dist/esm/joints/WeldJoint.js.map +1 -0
- package/dist/esm/joints/WheelJoint.d.ts +92 -0
- package/dist/esm/joints/WheelJoint.js +256 -0
- package/dist/esm/joints/WheelJoint.js.map +1 -0
- package/dist/esm/math.js +15 -1
- package/dist/esm/math.js.map +1 -1
- package/dist/esm/physicsBuildInfo.js +2 -2
- package/dist/esm/public.d.ts +7 -1
- package/dist/esm/solver/ContactSolver.js +7 -0
- package/dist/esm/solver/ContactSolver.js.map +1 -1
- package/package.json +4 -4
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export { PhysicsBinding } from './binding/PhysicsBinding.js';
|
|
2
2
|
export { Collider } from './Collider.js';
|
|
3
|
+
export { DistanceJoint } from './joints/DistanceJoint.js';
|
|
4
|
+
export { Joint } from './joints/Joint.js';
|
|
5
|
+
export { MouseJoint } from './joints/MouseJoint.js';
|
|
6
|
+
export { PrismaticJoint } from './joints/PrismaticJoint.js';
|
|
7
|
+
export { RevoluteJoint } from './joints/RevoluteJoint.js';
|
|
8
|
+
export { WeldJoint } from './joints/WeldJoint.js';
|
|
9
|
+
export { WheelJoint } from './joints/WheelJoint.js';
|
|
3
10
|
export { PhysicsBody } from './PhysicsBody.js';
|
|
4
11
|
export { physicsBuildInfo } from './physicsBuildInfo.js';
|
|
5
12
|
export { PhysicsWorld } from './PhysicsWorld.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { PhysicsBody } from '../PhysicsBody';
|
|
2
|
+
import type { VectorLike } from '../types';
|
|
3
|
+
import { Joint } from './Joint';
|
|
4
|
+
/** Construction options for a {@link DistanceJoint}. */
|
|
5
|
+
export interface DistanceJointOptions {
|
|
6
|
+
/** First body (often a static anchor). */
|
|
7
|
+
bodyA: PhysicsBody;
|
|
8
|
+
/** Second body. */
|
|
9
|
+
bodyB: PhysicsBody;
|
|
10
|
+
/** World-space anchor on body A at creation. Default: body A's position. */
|
|
11
|
+
anchorA?: VectorLike;
|
|
12
|
+
/** World-space anchor on body B at creation. Default: body B's position. */
|
|
13
|
+
anchorB?: VectorLike;
|
|
14
|
+
/** Target distance between the anchors. Default: their initial distance. */
|
|
15
|
+
length?: number;
|
|
16
|
+
/** Soft-spring frequency in Hz; `0` (default) makes it a rigid constraint. */
|
|
17
|
+
hertz?: number;
|
|
18
|
+
/** Soft-spring damping ratio (used when `hertz > 0`). Default `1`. */
|
|
19
|
+
dampingRatio?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Minimum allowed distance. Specifying `minLength` and/or `maxLength` turns the
|
|
22
|
+
* joint into a **rope/limit** (distance kept within `[minLength, maxLength]`,
|
|
23
|
+
* slack between, rigid limits). Otherwise the joint is a rigid/soft **equality**
|
|
24
|
+
* at `length`. Defaults to `0` in limit mode.
|
|
25
|
+
*/
|
|
26
|
+
minLength?: number;
|
|
27
|
+
/** Maximum allowed distance (the rope length). See {@link minLength}. Defaults to `Infinity` in limit mode. */
|
|
28
|
+
maxLength?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Holds the anchor points on two bodies at a target {@link length} along their
|
|
32
|
+
* connecting axis. With `hertz === 0` it is rigid; with `hertz > 0` it behaves
|
|
33
|
+
* as a damped spring. Solved as a soft constraint in the sub-step loop, warm-
|
|
34
|
+
* started across frames.
|
|
35
|
+
*/
|
|
36
|
+
export declare class DistanceJoint extends Joint {
|
|
37
|
+
/** Target distance between the anchors. */
|
|
38
|
+
length: number;
|
|
39
|
+
/** Soft-spring frequency in Hz (`0` = rigid). */
|
|
40
|
+
hertz: number;
|
|
41
|
+
/** Soft-spring damping ratio. */
|
|
42
|
+
dampingRatio: number;
|
|
43
|
+
/** Minimum allowed distance (rope/limit mode). */
|
|
44
|
+
minLength: number;
|
|
45
|
+
/** Maximum allowed distance (rope/limit mode). */
|
|
46
|
+
maxLength: number;
|
|
47
|
+
private readonly _limited;
|
|
48
|
+
private _minImpulse;
|
|
49
|
+
private _maxImpulse;
|
|
50
|
+
private readonly _localAnchorAx;
|
|
51
|
+
private readonly _localAnchorAy;
|
|
52
|
+
private readonly _localAnchorBx;
|
|
53
|
+
private readonly _localAnchorBy;
|
|
54
|
+
private _rAx;
|
|
55
|
+
private _rAy;
|
|
56
|
+
private _rBx;
|
|
57
|
+
private _rBy;
|
|
58
|
+
private _nx;
|
|
59
|
+
private _ny;
|
|
60
|
+
private _separation;
|
|
61
|
+
private _effMass;
|
|
62
|
+
private _biasRate;
|
|
63
|
+
private _massScale;
|
|
64
|
+
private _impulseScale;
|
|
65
|
+
private _impulse;
|
|
66
|
+
constructor(options: DistanceJointOptions);
|
|
67
|
+
_prepare(h: number): void;
|
|
68
|
+
_warmStart(): void;
|
|
69
|
+
_solve(useBias: boolean): void;
|
|
70
|
+
private _applyAxisImpulse;
|
|
71
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { applyInverseTransform, applyTransform } from '../math.js';
|
|
2
|
+
import { Joint } from './Joint.js';
|
|
3
|
+
|
|
4
|
+
/** Reused output sink — physics steps single-threaded, so a shared scratch is safe. */
|
|
5
|
+
const scratch = { x: 0, y: 0 };
|
|
6
|
+
/**
|
|
7
|
+
* Holds the anchor points on two bodies at a target {@link length} along their
|
|
8
|
+
* connecting axis. With `hertz === 0` it is rigid; with `hertz > 0` it behaves
|
|
9
|
+
* as a damped spring. Solved as a soft constraint in the sub-step loop, warm-
|
|
10
|
+
* started across frames.
|
|
11
|
+
*/
|
|
12
|
+
class DistanceJoint extends Joint {
|
|
13
|
+
/** Target distance between the anchors. */
|
|
14
|
+
length;
|
|
15
|
+
/** Soft-spring frequency in Hz (`0` = rigid). */
|
|
16
|
+
hertz;
|
|
17
|
+
/** Soft-spring damping ratio. */
|
|
18
|
+
dampingRatio;
|
|
19
|
+
/** Minimum allowed distance (rope/limit mode). */
|
|
20
|
+
minLength;
|
|
21
|
+
/** Maximum allowed distance (rope/limit mode). */
|
|
22
|
+
maxLength;
|
|
23
|
+
_limited;
|
|
24
|
+
_minImpulse = -Infinity;
|
|
25
|
+
_maxImpulse = Infinity;
|
|
26
|
+
_localAnchorAx;
|
|
27
|
+
_localAnchorAy;
|
|
28
|
+
_localAnchorBx;
|
|
29
|
+
_localAnchorBy;
|
|
30
|
+
_rAx = 0;
|
|
31
|
+
_rAy = 0;
|
|
32
|
+
_rBx = 0;
|
|
33
|
+
_rBy = 0;
|
|
34
|
+
_nx = 0;
|
|
35
|
+
_ny = 0;
|
|
36
|
+
_separation = 0;
|
|
37
|
+
_effMass = 0;
|
|
38
|
+
_biasRate = 0;
|
|
39
|
+
_massScale = 1;
|
|
40
|
+
_impulseScale = 0;
|
|
41
|
+
_impulse = 0;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
super(options.bodyA, options.bodyB);
|
|
44
|
+
const ax = options.anchorA?.x ?? options.bodyA.x;
|
|
45
|
+
const ay = options.anchorA?.y ?? options.bodyA.y;
|
|
46
|
+
const bx = options.anchorB?.x ?? options.bodyB.x;
|
|
47
|
+
const by = options.anchorB?.y ?? options.bodyB.y;
|
|
48
|
+
applyInverseTransform(options.bodyA.transform, ax, ay, scratch);
|
|
49
|
+
this._localAnchorAx = scratch.x;
|
|
50
|
+
this._localAnchorAy = scratch.y;
|
|
51
|
+
applyInverseTransform(options.bodyB.transform, bx, by, scratch);
|
|
52
|
+
this._localAnchorBx = scratch.x;
|
|
53
|
+
this._localAnchorBy = scratch.y;
|
|
54
|
+
this.length = options.length ?? Math.hypot(bx - ax, by - ay);
|
|
55
|
+
this.hertz = options.hertz ?? 0;
|
|
56
|
+
this.dampingRatio = options.dampingRatio ?? 1;
|
|
57
|
+
this._limited = options.minLength !== undefined || options.maxLength !== undefined;
|
|
58
|
+
this.minLength = options.minLength ?? (this._limited ? 0 : this.length);
|
|
59
|
+
this.maxLength = options.maxLength ?? (this._limited ? Infinity : this.length);
|
|
60
|
+
}
|
|
61
|
+
_prepare(h) {
|
|
62
|
+
const bodyA = this.bodyA;
|
|
63
|
+
const bodyB = this.bodyB;
|
|
64
|
+
this._active = this.enabled && !bodyA.isSleeping && !bodyB.isSleeping && (bodyA.invMass > 0 || bodyB.invMass > 0);
|
|
65
|
+
if (!this._active) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
applyTransform(bodyA.transform, this._localAnchorAx, this._localAnchorAy, scratch);
|
|
69
|
+
const pAx = scratch.x;
|
|
70
|
+
const pAy = scratch.y;
|
|
71
|
+
applyTransform(bodyB.transform, this._localAnchorBx, this._localAnchorBy, scratch);
|
|
72
|
+
const pBx = scratch.x;
|
|
73
|
+
const pBy = scratch.y;
|
|
74
|
+
this._rAx = pAx - bodyA.worldCenterOfMassX;
|
|
75
|
+
this._rAy = pAy - bodyA.worldCenterOfMassY;
|
|
76
|
+
this._rBx = pBx - bodyB.worldCenterOfMassX;
|
|
77
|
+
this._rBy = pBy - bodyB.worldCenterOfMassY;
|
|
78
|
+
let dx = pBx - pAx;
|
|
79
|
+
let dy = pBy - pAy;
|
|
80
|
+
const len = Math.hypot(dx, dy);
|
|
81
|
+
if (len > 1e-9) {
|
|
82
|
+
dx /= len;
|
|
83
|
+
dy /= len;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
dx = 1;
|
|
87
|
+
dy = 0;
|
|
88
|
+
}
|
|
89
|
+
this._nx = dx;
|
|
90
|
+
this._ny = dy;
|
|
91
|
+
const crA = this._rAx * dy - this._rAy * dx;
|
|
92
|
+
const crB = this._rBx * dy - this._rBy * dx;
|
|
93
|
+
const k = bodyA.invMass + bodyB.invMass + bodyA.invInertia * crA * crA + bodyB.invInertia * crB * crB;
|
|
94
|
+
this._effMass = k > 0 ? 1 / k : 0;
|
|
95
|
+
if (this._limited) {
|
|
96
|
+
// Rope/limit: solve only the violated bound; slack between min and max.
|
|
97
|
+
if (len > this.maxLength) {
|
|
98
|
+
this._separation = len - this.maxLength;
|
|
99
|
+
this._minImpulse = -Infinity; // pull together only (tension)
|
|
100
|
+
this._maxImpulse = 0;
|
|
101
|
+
}
|
|
102
|
+
else if (len < this.minLength) {
|
|
103
|
+
this._separation = len - this.minLength;
|
|
104
|
+
this._minImpulse = 0; // push apart only (compression)
|
|
105
|
+
this._maxImpulse = Infinity;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this._active = false; // slack — nothing to solve this frame
|
|
109
|
+
this._impulse = 0;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this._separation = len - this.length;
|
|
115
|
+
this._minImpulse = -Infinity;
|
|
116
|
+
this._maxImpulse = Infinity;
|
|
117
|
+
}
|
|
118
|
+
// Soft spring only for the equality joint; rope limits are rigid.
|
|
119
|
+
if (this.hertz > 0 && !this._limited) {
|
|
120
|
+
// Box2D-v3 soft factors from a damped spring at the sub-step `h`.
|
|
121
|
+
const omega = 2 * Math.PI * this.hertz;
|
|
122
|
+
const a1 = 2 * this.dampingRatio + h * omega;
|
|
123
|
+
const a2 = h * omega * a1;
|
|
124
|
+
const a3 = 1 / (1 + a2);
|
|
125
|
+
this._biasRate = omega / a1;
|
|
126
|
+
this._massScale = a2 * a3;
|
|
127
|
+
this._impulseScale = a3;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Rigid: full mass, Baumgarte position bias, no impulse decay.
|
|
131
|
+
this._biasRate = 0.2 / h;
|
|
132
|
+
this._massScale = 1;
|
|
133
|
+
this._impulseScale = 0;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
_warmStart() {
|
|
137
|
+
if (this._active) {
|
|
138
|
+
this._applyAxisImpulse(this._impulse);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
_solve(useBias) {
|
|
142
|
+
if (!this._active) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const bodyA = this.bodyA;
|
|
146
|
+
const bodyB = this.bodyB;
|
|
147
|
+
// Relative velocity of the anchors projected onto the axis.
|
|
148
|
+
const vax = bodyA.linearVelocityX - bodyA.angularVelocity * this._rAy;
|
|
149
|
+
const vay = bodyA.linearVelocityY + bodyA.angularVelocity * this._rAx;
|
|
150
|
+
const vbx = bodyB.linearVelocityX - bodyB.angularVelocity * this._rBy;
|
|
151
|
+
const vby = bodyB.linearVelocityY + bodyB.angularVelocity * this._rBx;
|
|
152
|
+
const cdot = (vbx - vax) * this._nx + (vby - vay) * this._ny;
|
|
153
|
+
const bias = useBias ? this._biasRate * this._separation : 0;
|
|
154
|
+
const raw = -this._effMass * this._massScale * (cdot + bias) - this._impulseScale * this._impulse;
|
|
155
|
+
// Clamp the accumulated impulse to the limit's sign range (±Infinity = equality, no clamp).
|
|
156
|
+
const clamped = Math.min(this._maxImpulse, Math.max(this._minImpulse, this._impulse + raw));
|
|
157
|
+
const applied = clamped - this._impulse;
|
|
158
|
+
this._impulse = clamped;
|
|
159
|
+
this._applyAxisImpulse(applied);
|
|
160
|
+
}
|
|
161
|
+
_applyAxisImpulse(impulse) {
|
|
162
|
+
const jx = impulse * this._nx;
|
|
163
|
+
const jy = impulse * this._ny;
|
|
164
|
+
const bodyA = this.bodyA;
|
|
165
|
+
const bodyB = this.bodyB;
|
|
166
|
+
bodyA.linearVelocityX -= bodyA.invMass * jx;
|
|
167
|
+
bodyA.linearVelocityY -= bodyA.invMass * jy;
|
|
168
|
+
bodyA.angularVelocity -= bodyA.invInertia * (this._rAx * jy - this._rAy * jx);
|
|
169
|
+
bodyB.linearVelocityX += bodyB.invMass * jx;
|
|
170
|
+
bodyB.linearVelocityY += bodyB.invMass * jy;
|
|
171
|
+
bodyB.angularVelocity += bodyB.invInertia * (this._rBx * jy - this._rBy * jx);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { DistanceJoint };
|
|
176
|
+
//# sourceMappingURL=DistanceJoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DistanceJoint.js","sources":["../../../../src/joints/DistanceJoint.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PhysicsBody } from '../PhysicsBody';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for a two-body constraint solved alongside contacts in the
|
|
4
|
+
* sub-step loop. Concrete joints (distance, revolute, weld) implement the
|
|
5
|
+
* three solver hooks; the world owns the joint list and drives them, and joins
|
|
6
|
+
* the two bodies into one sleep island so a jointed pair sleeps and wakes
|
|
7
|
+
* together.
|
|
8
|
+
*/
|
|
9
|
+
export declare abstract class Joint {
|
|
10
|
+
/** First constrained body. */
|
|
11
|
+
readonly bodyA: PhysicsBody;
|
|
12
|
+
/** Second constrained body. */
|
|
13
|
+
readonly bodyB: PhysicsBody;
|
|
14
|
+
/** When `false`, the joint is skipped by the solver (but still tracked by the world). */
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
/** Whether this joint solves this frame — set in {@link _prepare} (disabled, sleeping or two static bodies → `false`). */
|
|
17
|
+
protected _active: boolean;
|
|
18
|
+
protected constructor(bodyA: PhysicsBody, bodyB: PhysicsBody);
|
|
19
|
+
/** @internal — build this frame's constraint data; called once per fixed step after detection. */
|
|
20
|
+
abstract _prepare(h: number): void;
|
|
21
|
+
/** @internal — re-apply the accumulated impulse; called each sub-step (TGS-Soft warm-start). */
|
|
22
|
+
abstract _warmStart(): void;
|
|
23
|
+
/** @internal — one velocity pass; `useBias` is the soft-bias pass, `false` the relax pass. */
|
|
24
|
+
abstract _solve(useBias: boolean): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for a two-body constraint solved alongside contacts in the
|
|
3
|
+
* sub-step loop. Concrete joints (distance, revolute, weld) implement the
|
|
4
|
+
* three solver hooks; the world owns the joint list and drives them, and joins
|
|
5
|
+
* the two bodies into one sleep island so a jointed pair sleeps and wakes
|
|
6
|
+
* together.
|
|
7
|
+
*/
|
|
8
|
+
class Joint {
|
|
9
|
+
/** First constrained body. */
|
|
10
|
+
bodyA;
|
|
11
|
+
/** Second constrained body. */
|
|
12
|
+
bodyB;
|
|
13
|
+
/** When `false`, the joint is skipped by the solver (but still tracked by the world). */
|
|
14
|
+
enabled = true;
|
|
15
|
+
/** Whether this joint solves this frame — set in {@link _prepare} (disabled, sleeping or two static bodies → `false`). */
|
|
16
|
+
_active = false;
|
|
17
|
+
constructor(bodyA, bodyB) {
|
|
18
|
+
this.bodyA = bodyA;
|
|
19
|
+
this.bodyB = bodyB;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { Joint };
|
|
24
|
+
//# sourceMappingURL=Joint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Joint.js","sources":["../../../../src/joints/Joint.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEA;;;;;;AAMG;MACmB,KAAK,CAAA;;AAET,IAAA,KAAK;;AAEL,IAAA,KAAK;;IAEd,OAAO,GAAG,IAAI;;IAGX,OAAO,GAAG,KAAK;IAEzB,WAAA,CAAsB,KAAkB,EAAE,KAAkB,EAAA;AAC1D,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;IACpB;AAQD;;;;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PhysicsBody } from '../PhysicsBody';
|
|
2
|
+
import type { VectorLike } from '../types';
|
|
3
|
+
import { Joint } from './Joint';
|
|
4
|
+
/** Construction options for a {@link MouseJoint}. */
|
|
5
|
+
export interface MouseJointOptions {
|
|
6
|
+
/** The body to drag. */
|
|
7
|
+
body: PhysicsBody;
|
|
8
|
+
/** World point to pull the body toward — also the grab point on the body at creation. */
|
|
9
|
+
target: VectorLike;
|
|
10
|
+
/** Soft-spring frequency in Hz (higher = snappier). Default `5`. */
|
|
11
|
+
hertz?: number;
|
|
12
|
+
/** Soft-spring damping ratio. Default `0.7`. */
|
|
13
|
+
dampingRatio?: number;
|
|
14
|
+
/** Maximum pulling force — clamps the per-step impulse so heavy bodies lag. Default `Infinity`. */
|
|
15
|
+
maxForce?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Softly pulls a single body's grab point toward a movable **target** point
|
|
19
|
+
* (typically the mouse cursor). The grab point is fixed on the body at creation;
|
|
20
|
+
* update {@link target} each frame to drag. A soft constraint bounded by
|
|
21
|
+
* {@link maxForce} — solved in the sub-step loop, warm-started. Internally the
|
|
22
|
+
* "other" body is a private static ground sentinel, so this is a single-body
|
|
23
|
+
* constraint that touches only the dragged body.
|
|
24
|
+
*/
|
|
25
|
+
export declare class MouseJoint extends Joint {
|
|
26
|
+
/** Soft-spring frequency in Hz. */
|
|
27
|
+
hertz: number;
|
|
28
|
+
/** Soft-spring damping ratio. */
|
|
29
|
+
dampingRatio: number;
|
|
30
|
+
/** Maximum pulling force. */
|
|
31
|
+
maxForce: number;
|
|
32
|
+
private readonly _localAnchorX;
|
|
33
|
+
private readonly _localAnchorY;
|
|
34
|
+
private _targetX;
|
|
35
|
+
private _targetY;
|
|
36
|
+
private _rx;
|
|
37
|
+
private _ry;
|
|
38
|
+
private _cx;
|
|
39
|
+
private _cy;
|
|
40
|
+
private _invK11;
|
|
41
|
+
private _invK12;
|
|
42
|
+
private _invK22;
|
|
43
|
+
private _biasRate;
|
|
44
|
+
private _massScale;
|
|
45
|
+
private _impulseScale;
|
|
46
|
+
private _impulseX;
|
|
47
|
+
private _impulseY;
|
|
48
|
+
private _maxImpulse;
|
|
49
|
+
constructor(options: MouseJointOptions);
|
|
50
|
+
/** The world point the body is pulled toward. Reassigning wakes the body so a drag tracks live. */
|
|
51
|
+
get target(): VectorLike;
|
|
52
|
+
set target(value: VectorLike);
|
|
53
|
+
_prepare(h: number): void;
|
|
54
|
+
_warmStart(): void;
|
|
55
|
+
_solve(useBias: boolean): void;
|
|
56
|
+
private _applyImpulse;
|
|
57
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { applyInverseTransform, applyTransform } from '../math.js';
|
|
2
|
+
import { PhysicsBody } from '../PhysicsBody.js';
|
|
3
|
+
import { Joint } from './Joint.js';
|
|
4
|
+
|
|
5
|
+
/** Reused output sink — physics steps single-threaded, so a shared scratch is safe. */
|
|
6
|
+
const scratch = { x: 0, y: 0 };
|
|
7
|
+
/**
|
|
8
|
+
* Softly pulls a single body's grab point toward a movable **target** point
|
|
9
|
+
* (typically the mouse cursor). The grab point is fixed on the body at creation;
|
|
10
|
+
* update {@link target} each frame to drag. A soft constraint bounded by
|
|
11
|
+
* {@link maxForce} — solved in the sub-step loop, warm-started. Internally the
|
|
12
|
+
* "other" body is a private static ground sentinel, so this is a single-body
|
|
13
|
+
* constraint that touches only the dragged body.
|
|
14
|
+
*/
|
|
15
|
+
class MouseJoint extends Joint {
|
|
16
|
+
/** Soft-spring frequency in Hz. */
|
|
17
|
+
hertz;
|
|
18
|
+
/** Soft-spring damping ratio. */
|
|
19
|
+
dampingRatio;
|
|
20
|
+
/** Maximum pulling force. */
|
|
21
|
+
maxForce;
|
|
22
|
+
_localAnchorX;
|
|
23
|
+
_localAnchorY;
|
|
24
|
+
_targetX;
|
|
25
|
+
_targetY;
|
|
26
|
+
_rx = 0;
|
|
27
|
+
_ry = 0;
|
|
28
|
+
_cx = 0;
|
|
29
|
+
_cy = 0;
|
|
30
|
+
_invK11 = 0;
|
|
31
|
+
_invK12 = 0;
|
|
32
|
+
_invK22 = 0;
|
|
33
|
+
_biasRate = 0;
|
|
34
|
+
_massScale = 1;
|
|
35
|
+
_impulseScale = 0;
|
|
36
|
+
_impulseX = 0;
|
|
37
|
+
_impulseY = 0;
|
|
38
|
+
_maxImpulse = 0;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
// Single-body constraint: a private static ground stands in for bodyA so the
|
|
41
|
+
// island/solver machinery (which assumes two bodies) sees a static anchor that
|
|
42
|
+
// it never integrates, unions or mutates.
|
|
43
|
+
super(new PhysicsBody({ type: 'static', position: options.target }), options.body);
|
|
44
|
+
applyInverseTransform(options.body.transform, options.target.x, options.target.y, scratch);
|
|
45
|
+
this._localAnchorX = scratch.x;
|
|
46
|
+
this._localAnchorY = scratch.y;
|
|
47
|
+
this._targetX = options.target.x;
|
|
48
|
+
this._targetY = options.target.y;
|
|
49
|
+
this.hertz = options.hertz ?? 5;
|
|
50
|
+
this.dampingRatio = options.dampingRatio ?? 0.7;
|
|
51
|
+
this.maxForce = options.maxForce ?? Infinity;
|
|
52
|
+
}
|
|
53
|
+
/** The world point the body is pulled toward. Reassigning wakes the body so a drag tracks live. */
|
|
54
|
+
get target() {
|
|
55
|
+
return { x: this._targetX, y: this._targetY };
|
|
56
|
+
}
|
|
57
|
+
set target(value) {
|
|
58
|
+
this._targetX = value.x;
|
|
59
|
+
this._targetY = value.y;
|
|
60
|
+
this.bodyB.wake();
|
|
61
|
+
}
|
|
62
|
+
_prepare(h) {
|
|
63
|
+
const body = this.bodyB;
|
|
64
|
+
this._active = this.enabled && !body.isSleeping && body.invMass > 0;
|
|
65
|
+
if (!this._active) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
applyTransform(body.transform, this._localAnchorX, this._localAnchorY, scratch);
|
|
69
|
+
this._rx = scratch.x - body.worldCenterOfMassX;
|
|
70
|
+
this._ry = scratch.y - body.worldCenterOfMassY;
|
|
71
|
+
this._cx = scratch.x - this._targetX;
|
|
72
|
+
this._cy = scratch.y - this._targetY;
|
|
73
|
+
const m = body.invMass;
|
|
74
|
+
const i = body.invInertia;
|
|
75
|
+
// 2×2 effective-mass matrix K (only the dragged body contributes) and its inverse.
|
|
76
|
+
const k11 = m + i * this._ry * this._ry;
|
|
77
|
+
const k12 = -i * this._rx * this._ry;
|
|
78
|
+
const k22 = m + i * this._rx * this._rx;
|
|
79
|
+
const det = k11 * k22 - k12 * k12;
|
|
80
|
+
const invDet = det !== 0 ? 1 / det : 0;
|
|
81
|
+
this._invK11 = invDet * k22;
|
|
82
|
+
this._invK12 = -invDet * k12;
|
|
83
|
+
this._invK22 = invDet * k11;
|
|
84
|
+
this._maxImpulse = this.maxForce * h;
|
|
85
|
+
const omega = 2 * Math.PI * this.hertz;
|
|
86
|
+
const a1 = 2 * this.dampingRatio + h * omega;
|
|
87
|
+
const a2 = h * omega * a1;
|
|
88
|
+
const a3 = 1 / (1 + a2);
|
|
89
|
+
this._biasRate = omega / a1;
|
|
90
|
+
this._massScale = a2 * a3;
|
|
91
|
+
this._impulseScale = a3;
|
|
92
|
+
}
|
|
93
|
+
_warmStart() {
|
|
94
|
+
if (!this._active) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this._applyImpulse(this._impulseX, this._impulseY);
|
|
98
|
+
}
|
|
99
|
+
_solve(useBias) {
|
|
100
|
+
if (!this._active) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const body = this.bodyB;
|
|
104
|
+
// Velocity of the grab point.
|
|
105
|
+
const cdotX = body.linearVelocityX - body.angularVelocity * this._ry;
|
|
106
|
+
const cdotY = body.linearVelocityY + body.angularVelocity * this._rx;
|
|
107
|
+
const rhsX = cdotX + (useBias ? this._biasRate * this._cx : 0);
|
|
108
|
+
const rhsY = cdotY + (useBias ? this._biasRate * this._cy : 0);
|
|
109
|
+
const solvedX = this._invK11 * rhsX + this._invK12 * rhsY;
|
|
110
|
+
const solvedY = this._invK12 * rhsX + this._invK22 * rhsY;
|
|
111
|
+
let impulseX = -this._massScale * solvedX - this._impulseScale * this._impulseX;
|
|
112
|
+
let impulseY = -this._massScale * solvedY - this._impulseScale * this._impulseY;
|
|
113
|
+
// Clamp the accumulated impulse magnitude to maxForce·h (a heavy body lags).
|
|
114
|
+
const oldX = this._impulseX;
|
|
115
|
+
const oldY = this._impulseY;
|
|
116
|
+
this._impulseX += impulseX;
|
|
117
|
+
this._impulseY += impulseY;
|
|
118
|
+
const magnitude = Math.hypot(this._impulseX, this._impulseY);
|
|
119
|
+
if (magnitude > this._maxImpulse) {
|
|
120
|
+
const scale = this._maxImpulse / magnitude;
|
|
121
|
+
this._impulseX *= scale;
|
|
122
|
+
this._impulseY *= scale;
|
|
123
|
+
}
|
|
124
|
+
impulseX = this._impulseX - oldX;
|
|
125
|
+
impulseY = this._impulseY - oldY;
|
|
126
|
+
this._applyImpulse(impulseX, impulseY);
|
|
127
|
+
}
|
|
128
|
+
_applyImpulse(jx, jy) {
|
|
129
|
+
const body = this.bodyB;
|
|
130
|
+
body.linearVelocityX += body.invMass * jx;
|
|
131
|
+
body.linearVelocityY += body.invMass * jy;
|
|
132
|
+
body.angularVelocity += body.invInertia * (this._rx * jy - this._ry * jx);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { MouseJoint };
|
|
137
|
+
//# sourceMappingURL=MouseJoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MouseJoint.js","sources":["../../../../src/joints/MouseJoint.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { PhysicsBody } from '../PhysicsBody';
|
|
2
|
+
import type { VectorLike } from '../types';
|
|
3
|
+
import { Joint } from './Joint';
|
|
4
|
+
/** Construction options for a {@link PrismaticJoint}. */
|
|
5
|
+
export interface PrismaticJointOptions {
|
|
6
|
+
/** First body (often a static rail anchor). */
|
|
7
|
+
bodyA: PhysicsBody;
|
|
8
|
+
/** Second body (the slider). */
|
|
9
|
+
bodyB: PhysicsBody;
|
|
10
|
+
/** Shared world-space anchor at creation. */
|
|
11
|
+
anchor: VectorLike;
|
|
12
|
+
/** Slide axis in world space at creation (normalised internally). The body may only translate along this axis. */
|
|
13
|
+
axis: VectorLike;
|
|
14
|
+
/** Enable the linear motor (drives translation along the axis toward {@link motorSpeed}). Default `false`. */
|
|
15
|
+
enableMotor?: boolean;
|
|
16
|
+
/** Target translation speed along the axis (px/s). Default `0`. */
|
|
17
|
+
motorSpeed?: number;
|
|
18
|
+
/** Maximum motor force — clamps the per-step motor impulse. Default `0`. */
|
|
19
|
+
maxMotorForce?: number;
|
|
20
|
+
/** Enable the translation limit (keeps the axis translation in `[lowerTranslation, upperTranslation]`). Default `false`. */
|
|
21
|
+
enableLimit?: boolean;
|
|
22
|
+
/** Lower translation limit along the axis (relative to the creation position). Default `0`. */
|
|
23
|
+
lowerTranslation?: number;
|
|
24
|
+
/** Upper translation limit along the axis. Default `0`. */
|
|
25
|
+
upperTranslation?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Constrains a body to **slide along a single axis** relative to another: the
|
|
29
|
+
* perpendicular translation and the relative rotation are locked (a 2×2 block);
|
|
30
|
+
* only translation along the axis is free, optionally driven by a motor and/or
|
|
31
|
+
* bounded by a translation limit. Solved in the sub-step loop, warm-started.
|
|
32
|
+
*/
|
|
33
|
+
export declare class PrismaticJoint extends Joint {
|
|
34
|
+
/** When `true`, the motor drives the axis translation toward {@link motorSpeed}. */
|
|
35
|
+
enableMotor: boolean;
|
|
36
|
+
/** Target translation speed along the axis (px/s). */
|
|
37
|
+
motorSpeed: number;
|
|
38
|
+
/** Maximum motor force. */
|
|
39
|
+
maxMotorForce: number;
|
|
40
|
+
/** When `true`, the axis translation is constrained to `[lowerTranslation, upperTranslation]`. */
|
|
41
|
+
enableLimit: boolean;
|
|
42
|
+
/** Lower translation limit along the axis. */
|
|
43
|
+
lowerTranslation: number;
|
|
44
|
+
/** Upper translation limit along the axis. */
|
|
45
|
+
upperTranslation: number;
|
|
46
|
+
private readonly _localAnchorAx;
|
|
47
|
+
private readonly _localAnchorAy;
|
|
48
|
+
private readonly _localAnchorBx;
|
|
49
|
+
private readonly _localAnchorBy;
|
|
50
|
+
private readonly _localAxisAx;
|
|
51
|
+
private readonly _localAxisAy;
|
|
52
|
+
private readonly _referenceAngle;
|
|
53
|
+
private _axisX;
|
|
54
|
+
private _axisY;
|
|
55
|
+
private _perpX;
|
|
56
|
+
private _perpY;
|
|
57
|
+
private _a1;
|
|
58
|
+
private _a2;
|
|
59
|
+
private _s1;
|
|
60
|
+
private _s2;
|
|
61
|
+
private _k11;
|
|
62
|
+
private _k12;
|
|
63
|
+
private _k22;
|
|
64
|
+
private _cPerp;
|
|
65
|
+
private _cAngle;
|
|
66
|
+
private _translation;
|
|
67
|
+
private _axialMass;
|
|
68
|
+
private _h;
|
|
69
|
+
private _invH;
|
|
70
|
+
private _perpImpulse;
|
|
71
|
+
private _angularImpulse;
|
|
72
|
+
private _motorImpulse;
|
|
73
|
+
private _lowerImpulse;
|
|
74
|
+
private _upperImpulse;
|
|
75
|
+
constructor(options: PrismaticJointOptions);
|
|
76
|
+
_prepare(h: number): void;
|
|
77
|
+
_warmStart(): void;
|
|
78
|
+
_solve(useBias: boolean): void;
|
|
79
|
+
/** Relative velocity projected onto the axis (plus the rotation cross terms). */
|
|
80
|
+
private _axisVelocity;
|
|
81
|
+
/** Relative velocity projected onto the perpendicular (plus the rotation cross terms). */
|
|
82
|
+
private _perpVelocity;
|
|
83
|
+
private _applyAxial;
|
|
84
|
+
private _applyBlock;
|
|
85
|
+
}
|