@datamoc/mw_games 0.36.0 → 0.37.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/CHANGELOG.md +49 -0
- package/README.md +6 -2
- package/api-surface.json +234 -0
- package/dist/assets/paths.d.ts.map +1 -1
- package/dist/assets/paths.js +3 -0
- package/dist/assets/paths.js.map +1 -1
- package/dist/audio/Playable.d.ts.map +1 -1
- package/dist/audio/Playable.js +14 -1
- package/dist/audio/Playable.js.map +1 -1
- package/dist/audio/Synth.d.ts +14 -0
- package/dist/audio/Synth.d.ts.map +1 -1
- package/dist/audio/Synth.js +16 -0
- package/dist/audio/Synth.js.map +1 -1
- package/dist/audio/index.d.ts +1 -1
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +1 -1
- package/dist/audio/index.js.map +1 -1
- package/dist/core/FixedStepper.d.ts +38 -0
- package/dist/core/FixedStepper.d.ts.map +1 -0
- package/dist/core/FixedStepper.js +56 -0
- package/dist/core/FixedStepper.js.map +1 -0
- package/dist/core/Input.d.ts +61 -0
- package/dist/core/Input.d.ts.map +1 -1
- package/dist/core/Input.js +101 -0
- package/dist/core/Input.js.map +1 -1
- package/dist/core/StoredValue.d.ts +11 -2
- package/dist/core/StoredValue.d.ts.map +1 -1
- package/dist/core/StoredValue.js +11 -2
- package/dist/core/StoredValue.js.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/mw_games.global.js +121 -121
- package/dist/physics/PhysicsWorld.d.ts +123 -0
- package/dist/physics/PhysicsWorld.d.ts.map +1 -0
- package/dist/physics/PhysicsWorld.js +137 -0
- package/dist/physics/PhysicsWorld.js.map +1 -0
- package/dist/physics/XpbdWorld.d.ts +139 -0
- package/dist/physics/XpbdWorld.d.ts.map +1 -0
- package/dist/physics/XpbdWorld.js +207 -0
- package/dist/physics/XpbdWorld.js.map +1 -0
- package/dist/physics/index.d.ts +3 -0
- package/dist/physics/index.d.ts.map +1 -0
- package/dist/physics/index.js +2 -0
- package/dist/physics/index.js.map +1 -0
- package/dist/physics/xpbd.d.ts +3 -0
- package/dist/physics/xpbd.d.ts.map +1 -0
- package/dist/physics/xpbd.js +2 -0
- package/dist/physics/xpbd.js.map +1 -0
- package/dist/two-d/render/Camera.d.ts +6 -0
- package/dist/two-d/render/Camera.d.ts.map +1 -1
- package/dist/two-d/render/Camera.js +9 -0
- package/dist/two-d/render/Camera.js.map +1 -1
- package/dist/two-d/render/Particles.d.ts +10 -1
- package/dist/two-d/render/Particles.d.ts.map +1 -1
- package/dist/two-d/render/Particles.js +14 -7
- package/dist/two-d/render/Particles.js.map +1 -1
- package/dist/two-d/render/Shape2D.d.ts +7 -0
- package/dist/two-d/render/Shape2D.d.ts.map +1 -1
- package/dist/two-d/render/Shape2D.js +18 -0
- package/dist/two-d/render/Shape2D.js.map +1 -1
- package/dist/two-d/render/SpriteSheet.d.ts +5 -0
- package/dist/two-d/render/SpriteSheet.d.ts.map +1 -1
- package/dist/two-d/render/SpriteSheet.js +15 -0
- package/dist/two-d/render/SpriteSheet.js.map +1 -1
- package/dist/two-d/ui/Button.d.ts +7 -0
- package/dist/two-d/ui/Button.d.ts.map +1 -1
- package/dist/two-d/ui/Button.js +16 -2
- package/dist/two-d/ui/Button.js.map +1 -1
- package/dist/two-d/ui/Dropdown.d.ts +3 -0
- package/dist/two-d/ui/Dropdown.d.ts.map +1 -1
- package/dist/two-d/ui/Dropdown.js +3 -0
- package/dist/two-d/ui/Dropdown.js.map +1 -1
- package/dist/two-d/ui/DropdownView.d.ts +40 -0
- package/dist/two-d/ui/DropdownView.d.ts.map +1 -0
- package/dist/two-d/ui/DropdownView.js +75 -0
- package/dist/two-d/ui/DropdownView.js.map +1 -0
- package/dist/two-d/ui/Label.d.ts +2 -0
- package/dist/two-d/ui/Label.d.ts.map +1 -1
- package/dist/two-d/ui/Label.js +7 -0
- package/dist/two-d/ui/Label.js.map +1 -1
- package/dist/two-d/ui/Layout.d.ts +34 -0
- package/dist/two-d/ui/Layout.d.ts.map +1 -1
- package/dist/two-d/ui/Layout.js +47 -0
- package/dist/two-d/ui/Layout.js.map +1 -1
- package/dist/two-d/ui/Window.d.ts +7 -0
- package/dist/two-d/ui/Window.d.ts.map +1 -1
- package/dist/two-d/ui/Window.js +13 -0
- package/dist/two-d/ui/Window.js.map +1 -1
- package/dist/two-d/ui/index.d.ts +4 -2
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +2 -1
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +22 -3
- package/sbom.cdx.json +64 -12
- package/tools/browser-driver.d.mts +14 -0
- package/tools/browser-driver.mjs +86 -10
- package/tools/build-tablebases.mjs +6 -2
- package/tools/classic-html.mjs +9 -1
- package/tools/compile-openings.mjs +6 -2
- package/tools/compile-resources.d.mts +5 -0
- package/tools/compile-resources.mjs +45 -4
- package/tools/compress-dist.mjs +15 -3
- package/tools/emit-page.mjs +5 -1
- package/tools/init.d.mts +5 -0
- package/tools/init.mjs +145 -0
- package/tools/play-uci.mjs +6 -3
- package/tools/sbom.mjs +5 -1
- package/tools/single-file.mjs +9 -1
- package/tools/vite.mjs +5 -0
- package/tools/webp-convert.mjs +9 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import Matter from 'matter-js';
|
|
2
|
+
import { Signal } from '../core/Signal.ts';
|
|
3
|
+
export interface PhysicsOptions {
|
|
4
|
+
/** gravity strength per axis; y grows downward. { x: 0, y: 9.8 } (the default) matches matter-js's own default pull */
|
|
5
|
+
gravity?: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
};
|
|
9
|
+
/** the fixed simulation step in seconds; 1/60 when omitted */
|
|
10
|
+
step?: number;
|
|
11
|
+
/** steps one `update` may run before it drops the backlog; 5 when omitted */
|
|
12
|
+
maxSubsteps?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface BodyOptions {
|
|
15
|
+
/** an immovable body: ground, anchors */
|
|
16
|
+
isStatic?: boolean;
|
|
17
|
+
/** 0 to 1, how much of its speed a bounce keeps; 0 when omitted */
|
|
18
|
+
restitution?: number;
|
|
19
|
+
friction?: number;
|
|
20
|
+
/** mass per unit area; matter-js's default when omitted */
|
|
21
|
+
density?: number;
|
|
22
|
+
angle?: number;
|
|
23
|
+
/** a name for collision callbacks and lookups */
|
|
24
|
+
label?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ConstraintOptions {
|
|
27
|
+
/** 0 to 1, how rigidly the ends are held: 1 is a rod, a small value a spring; 1 when omitted */
|
|
28
|
+
stiffness?: number;
|
|
29
|
+
damping?: number;
|
|
30
|
+
/** rest length; the distance between the attachment points when omitted */
|
|
31
|
+
length?: number;
|
|
32
|
+
/** attachment points in each body's local space; the body centre when omitted */
|
|
33
|
+
pointA?: {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
};
|
|
37
|
+
pointB?: {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Makes the joint breakable: once its two ends are further apart than the rest length times
|
|
43
|
+
* `1 + maxStretch`, the constraint is removed and `onBreak` fires. 0.2 lets a beam stretch 20%
|
|
44
|
+
* before it snaps. For a zero-length joint (a pin) it is the absolute distance instead.
|
|
45
|
+
* The strain is read after each step's solve, so a fully rigid joint (`stiffness` 1) is pulled
|
|
46
|
+
* back before it is measured under a light load: use a stiffness below 1, as a real beam has.
|
|
47
|
+
* Unbreakable when omitted.
|
|
48
|
+
*/
|
|
49
|
+
maxStretch?: number;
|
|
50
|
+
}
|
|
51
|
+
export type PhysicsBody = Matter.Body;
|
|
52
|
+
export type PhysicsConstraint = Matter.Constraint;
|
|
53
|
+
/**
|
|
54
|
+
* Rigid bodies and constraints through matter-js, stepped on a fixed clock.
|
|
55
|
+
*
|
|
56
|
+
* The adapter is the framework side of using matter-js in a mwg game: it owns the `Engine`,
|
|
57
|
+
* steps it with a `FixedStepper` so the simulation is the same at any display refresh rate,
|
|
58
|
+
* and reports contacts through a `Signal`, while leaving the bodies themselves as plain
|
|
59
|
+
* matter-js objects a game reads `position` and `angle` from to place its sprites. It is
|
|
60
|
+
* renderer-free, so a game's headless tests can run the same world.
|
|
61
|
+
*
|
|
62
|
+
* `matter-js` is an optional peer dependency (`npm install matter-js`), imported only by this
|
|
63
|
+
* module (`@datamoc/mw_games/physics`), so a game that never simulates physics never bundles it.
|
|
64
|
+
* Constraints are springs and rods. Give one a `maxStretch` and it breaks when pulled that far
|
|
65
|
+
* past its rest length (`onBreak`); a game with a different stress rule reads `stretchOf` itself
|
|
66
|
+
* and calls `remove`.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { PhysicsWorld } from '@datamoc/mw_games/physics';
|
|
71
|
+
*
|
|
72
|
+
* const world = new PhysicsWorld();
|
|
73
|
+
* world.addBox(0, 300, 800, 20, { isStatic: true });
|
|
74
|
+
* const crate = world.addBox(100, 0, 40, 40, { restitution: 0.3 });
|
|
75
|
+
* world.update(1 / 30); // two fixed steps
|
|
76
|
+
* console.log(crate.position.y > 0); // true: it has started to fall
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare class PhysicsWorld {
|
|
80
|
+
readonly engine: Matter.Engine;
|
|
81
|
+
/** fires once per new contact between two bodies, with the matter-js bodies of the pair */
|
|
82
|
+
readonly onContact: Signal<{
|
|
83
|
+
a: PhysicsBody;
|
|
84
|
+
b: PhysicsBody;
|
|
85
|
+
}>;
|
|
86
|
+
/** fires when a breakable constraint passes its `maxStretch`; it is already removed from the world */
|
|
87
|
+
readonly onBreak: Signal<{
|
|
88
|
+
constraint: PhysicsConstraint;
|
|
89
|
+
stretch: number;
|
|
90
|
+
}>;
|
|
91
|
+
private readonly stepper;
|
|
92
|
+
private readonly breakable;
|
|
93
|
+
constructor(options?: PhysicsOptions);
|
|
94
|
+
get bodies(): readonly PhysicsBody[];
|
|
95
|
+
get constraints(): readonly PhysicsConstraint[];
|
|
96
|
+
/** how far into the next fixed step the clock is, 0 to 1, for interpolated drawing */
|
|
97
|
+
get alpha(): number;
|
|
98
|
+
/** a box centred on (x, y) */
|
|
99
|
+
addBox(x: number, y: number, width: number, height: number, options?: BodyOptions): PhysicsBody;
|
|
100
|
+
addCircle(x: number, y: number, radius: number, options?: BodyOptions): PhysicsBody;
|
|
101
|
+
/** joins two bodies, or a body to a fixed point in the world when `b` is a point */
|
|
102
|
+
addConstraint(a: PhysicsBody, b: PhysicsBody | {
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
}, options?: ConstraintOptions): PhysicsConstraint;
|
|
106
|
+
/** removes a body, or a constraint, from the simulation */
|
|
107
|
+
remove(item: PhysicsBody | PhysicsConstraint): void;
|
|
108
|
+
/**
|
|
109
|
+
* How far a constraint is stretched past its rest length, as a fraction of it (0.1 is 10%
|
|
110
|
+
* longer); for a zero-length joint, the distance between its ends. Negative when compressed.
|
|
111
|
+
*/
|
|
112
|
+
stretchOf(constraint: PhysicsConstraint): number;
|
|
113
|
+
/**
|
|
114
|
+
* Advances the simulation by `dt` seconds of real time, running as many fixed steps as that
|
|
115
|
+
* covers; call it from `Scene.update(dt)`.
|
|
116
|
+
*
|
|
117
|
+
* @returns how many fixed steps ran
|
|
118
|
+
*/
|
|
119
|
+
update(dt: number): number;
|
|
120
|
+
private breakOverstretched;
|
|
121
|
+
private add;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=PhysicsWorld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicsWorld.d.ts","sourceRoot":"","sources":["../../src/physics/PhysicsWorld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import Matter from 'matter-js';
|
|
2
|
+
import { FixedStepper } from '../core/FixedStepper.js';
|
|
3
|
+
import { Signal } from '../core/Signal.js';
|
|
4
|
+
/**
|
|
5
|
+
* Rigid bodies and constraints through matter-js, stepped on a fixed clock.
|
|
6
|
+
*
|
|
7
|
+
* The adapter is the framework side of using matter-js in a mwg game: it owns the `Engine`,
|
|
8
|
+
* steps it with a `FixedStepper` so the simulation is the same at any display refresh rate,
|
|
9
|
+
* and reports contacts through a `Signal`, while leaving the bodies themselves as plain
|
|
10
|
+
* matter-js objects a game reads `position` and `angle` from to place its sprites. It is
|
|
11
|
+
* renderer-free, so a game's headless tests can run the same world.
|
|
12
|
+
*
|
|
13
|
+
* `matter-js` is an optional peer dependency (`npm install matter-js`), imported only by this
|
|
14
|
+
* module (`@datamoc/mw_games/physics`), so a game that never simulates physics never bundles it.
|
|
15
|
+
* Constraints are springs and rods. Give one a `maxStretch` and it breaks when pulled that far
|
|
16
|
+
* past its rest length (`onBreak`); a game with a different stress rule reads `stretchOf` itself
|
|
17
|
+
* and calls `remove`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { PhysicsWorld } from '@datamoc/mw_games/physics';
|
|
22
|
+
*
|
|
23
|
+
* const world = new PhysicsWorld();
|
|
24
|
+
* world.addBox(0, 300, 800, 20, { isStatic: true });
|
|
25
|
+
* const crate = world.addBox(100, 0, 40, 40, { restitution: 0.3 });
|
|
26
|
+
* world.update(1 / 30); // two fixed steps
|
|
27
|
+
* console.log(crate.position.y > 0); // true: it has started to fall
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class PhysicsWorld {
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
/** fires once per new contact between two bodies, with the matter-js bodies of the pair */
|
|
33
|
+
this.onContact = new Signal();
|
|
34
|
+
/** fires when a breakable constraint passes its `maxStretch`; it is already removed from the world */
|
|
35
|
+
this.onBreak = new Signal();
|
|
36
|
+
this.breakable = new Map();
|
|
37
|
+
this.engine = Matter.Engine.create();
|
|
38
|
+
const gravity = options.gravity ?? { x: 0, y: 9.8 };
|
|
39
|
+
//matter's gravity is a direction times `scale`; 9.8 maps to its own default scale of 0.001
|
|
40
|
+
this.engine.gravity.x = Math.sign(gravity.x);
|
|
41
|
+
this.engine.gravity.y = Math.sign(gravity.y);
|
|
42
|
+
this.engine.gravity.scale = Math.max(Math.abs(gravity.x), Math.abs(gravity.y)) * 0.0001;
|
|
43
|
+
this.stepper = new FixedStepper(options.step ?? 1 / 60, options.maxSubsteps ?? 5);
|
|
44
|
+
Matter.Events.on(this.engine, 'collisionStart', (event) => {
|
|
45
|
+
for (const pair of event.pairs)
|
|
46
|
+
this.onContact.dispatch({ a: pair.bodyA, b: pair.bodyB });
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
get bodies() {
|
|
50
|
+
return Matter.Composite.allBodies(this.engine.world);
|
|
51
|
+
}
|
|
52
|
+
get constraints() {
|
|
53
|
+
return Matter.Composite.allConstraints(this.engine.world);
|
|
54
|
+
}
|
|
55
|
+
/** how far into the next fixed step the clock is, 0 to 1, for interpolated drawing */
|
|
56
|
+
get alpha() {
|
|
57
|
+
return this.stepper.alpha;
|
|
58
|
+
}
|
|
59
|
+
/** a box centred on (x, y) */
|
|
60
|
+
addBox(x, y, width, height, options = {}) {
|
|
61
|
+
return this.add(Matter.Bodies.rectangle(x, y, width, height, options));
|
|
62
|
+
}
|
|
63
|
+
addCircle(x, y, radius, options = {}) {
|
|
64
|
+
return this.add(Matter.Bodies.circle(x, y, radius, options));
|
|
65
|
+
}
|
|
66
|
+
/** joins two bodies, or a body to a fixed point in the world when `b` is a point */
|
|
67
|
+
addConstraint(a, b, options = {}) {
|
|
68
|
+
const isBody = (value) => 'position' in value;
|
|
69
|
+
const constraint = Matter.Constraint.create({
|
|
70
|
+
bodyA: a,
|
|
71
|
+
...(isBody(b) ? { bodyB: b } : { pointB: b }),
|
|
72
|
+
...(options.pointA ? { pointA: options.pointA } : {}),
|
|
73
|
+
...(isBody(b) && options.pointB ? { pointB: options.pointB } : {}),
|
|
74
|
+
stiffness: options.stiffness ?? 1,
|
|
75
|
+
damping: options.damping ?? 0,
|
|
76
|
+
...(options.length !== undefined ? { length: options.length } : {}),
|
|
77
|
+
});
|
|
78
|
+
Matter.Composite.add(this.engine.world, constraint);
|
|
79
|
+
if (options.maxStretch !== undefined)
|
|
80
|
+
this.breakable.set(constraint, options.maxStretch);
|
|
81
|
+
return constraint;
|
|
82
|
+
}
|
|
83
|
+
/** removes a body, or a constraint, from the simulation */
|
|
84
|
+
remove(item) {
|
|
85
|
+
Matter.Composite.remove(this.engine.world, item);
|
|
86
|
+
this.breakable.delete(item);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* How far a constraint is stretched past its rest length, as a fraction of it (0.1 is 10%
|
|
90
|
+
* longer); for a zero-length joint, the distance between its ends. Negative when compressed.
|
|
91
|
+
*/
|
|
92
|
+
stretchOf(constraint) {
|
|
93
|
+
const a = endPoint(constraint.bodyA, constraint.pointA);
|
|
94
|
+
const b = endPoint(constraint.bodyB, constraint.pointB);
|
|
95
|
+
const distance = Math.hypot(a.x - b.x, a.y - b.y);
|
|
96
|
+
return constraint.length > 0 ? distance / constraint.length - 1 : distance;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Advances the simulation by `dt` seconds of real time, running as many fixed steps as that
|
|
100
|
+
* covers; call it from `Scene.update(dt)`.
|
|
101
|
+
*
|
|
102
|
+
* @returns how many fixed steps ran
|
|
103
|
+
*/
|
|
104
|
+
update(dt) {
|
|
105
|
+
return this.stepper.advance(dt, (step) => {
|
|
106
|
+
Matter.Engine.update(this.engine, step * 1000);
|
|
107
|
+
this.breakOverstretched();
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
breakOverstretched() {
|
|
111
|
+
//collected first: removing while iterating the map would skip entries
|
|
112
|
+
const snapped = [];
|
|
113
|
+
for (const [constraint, limit] of this.breakable) {
|
|
114
|
+
const stretch = this.stretchOf(constraint);
|
|
115
|
+
if (stretch > limit)
|
|
116
|
+
snapped.push([constraint, stretch]);
|
|
117
|
+
}
|
|
118
|
+
for (const [constraint, stretch] of snapped) {
|
|
119
|
+
this.remove(constraint);
|
|
120
|
+
this.onBreak.dispatch({ constraint, stretch });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
add(body) {
|
|
124
|
+
Matter.Composite.add(this.engine.world, body);
|
|
125
|
+
return body;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** a constraint end in world space: the body's attachment point turned and moved with it, or the fixed point itself */
|
|
129
|
+
function endPoint(body, point) {
|
|
130
|
+
const local = point ?? { x: 0, y: 0 };
|
|
131
|
+
if (!body)
|
|
132
|
+
return local;
|
|
133
|
+
const cos = Math.cos(body.angle);
|
|
134
|
+
const sin = Math.sin(body.angle);
|
|
135
|
+
return { x: body.position.x + local.x * cos - local.y * sin, y: body.position.y + local.x * sin + local.y * cos };
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=PhysicsWorld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicsWorld.js","sourceRoot":"","sources":["../../src/physics/PhysicsWorld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.ts';
|
|
2
|
+
export interface XpbdOptions {
|
|
3
|
+
/** downward acceleration in units per second squared; 520 when omitted (a 1-unit-per-pixel scale) */
|
|
4
|
+
gravity?: number;
|
|
5
|
+
/** substeps per `step`; 16 when omitted. More is stiffer and steadier, and costs linearly */
|
|
6
|
+
substeps?: number;
|
|
7
|
+
/** constraint iterations per substep; 2 when omitted */
|
|
8
|
+
iterations?: number;
|
|
9
|
+
/** the frame time one `step` advances, in seconds; 1/60 when omitted */
|
|
10
|
+
step?: number;
|
|
11
|
+
/** velocity damping per second (exponential); 2.5 when omitted. Raise it while a structure settles */
|
|
12
|
+
damping?: number;
|
|
13
|
+
/** time constant of the load smoothing used for breaking, in seconds; 0.06 when omitted */
|
|
14
|
+
smoothing?: number;
|
|
15
|
+
/** how much of a node's sideways motion the ground removes while it touches, 0 to 1; 0.5 when omitted */
|
|
16
|
+
groundFriction?: number;
|
|
17
|
+
}
|
|
18
|
+
/** the ground a node cannot sink below: a height (y grows downward), or a height at each x */
|
|
19
|
+
export type XpbdGround = number | ((x: number) => number);
|
|
20
|
+
export interface XpbdNodeSpec {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
/** an anchor that never moves */
|
|
24
|
+
fixed?: boolean;
|
|
25
|
+
/** point mass; 1 when omitted. Link `mass` is added on top */
|
|
26
|
+
mass?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface XpbdLinkSpec {
|
|
29
|
+
a: number;
|
|
30
|
+
b: number;
|
|
31
|
+
/** spring stiffness: force per unit of stretch ratio. Higher is more rigid */
|
|
32
|
+
stiffness: number;
|
|
33
|
+
/** rest length; the current distance between the nodes when omitted */
|
|
34
|
+
rest?: number;
|
|
35
|
+
/** mass of the link itself, shared evenly between its two nodes */
|
|
36
|
+
mass?: number;
|
|
37
|
+
/** a cable: pulls when stretched and goes slack, without pushing, when compressed */
|
|
38
|
+
tensionOnly?: boolean;
|
|
39
|
+
/** the load it carries in compression before breaking; also in tension unless `tensionStrength` is set. Unbreakable when omitted */
|
|
40
|
+
strength?: number;
|
|
41
|
+
/** the load it carries in tension before breaking, when that differs from `strength` */
|
|
42
|
+
tensionStrength?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface XpbdNode {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
fixed: boolean;
|
|
48
|
+
vx: number;
|
|
49
|
+
vy: number;
|
|
50
|
+
/** inverse mass, 0 for a fixed node */
|
|
51
|
+
w: number;
|
|
52
|
+
}
|
|
53
|
+
export interface XpbdLink {
|
|
54
|
+
a: number;
|
|
55
|
+
b: number;
|
|
56
|
+
stiffness: number;
|
|
57
|
+
rest: number;
|
|
58
|
+
tensionOnly: boolean;
|
|
59
|
+
strength: number | undefined;
|
|
60
|
+
tensionStrength: number | undefined;
|
|
61
|
+
broken: boolean;
|
|
62
|
+
/** the force it carried over the last step, positive in tension, negative in compression */
|
|
63
|
+
force: number;
|
|
64
|
+
/** smoothed load as a fraction of what it can carry; it breaks above 1 */
|
|
65
|
+
ratio: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A deterministic structure solver: point masses joined by springs, solved with extended
|
|
69
|
+
* position-based dynamics (XPBD), with the force in every link read back so a link can break
|
|
70
|
+
* at a real load rather than at a stretch.
|
|
71
|
+
*
|
|
72
|
+
* The method (Macklin, Muller and Chentanaput's XPBD) moves each node freely for a substep,
|
|
73
|
+
* then corrects positions so every link returns to its rest length, with a compliance of
|
|
74
|
+
* `rest / stiffness / dt^2`: a link behaves as a spring of the stated stiffness whatever the
|
|
75
|
+
* step or iteration count, and the correction's Lagrange multiplier divided by `dt^2` is the
|
|
76
|
+
* force it carried. Steps are fixed and nothing is random, so the same structure and the same
|
|
77
|
+
* calls give the same result on every machine, which is what replaying or validating a
|
|
78
|
+
* player's bridge needs.
|
|
79
|
+
*
|
|
80
|
+
* It is the engine of Pontifex (a bridge-building game), generalised: the vehicle, the water
|
|
81
|
+
* and the levels stay in the game, and what is here is only nodes, links, forces and breaking.
|
|
82
|
+
* Unlike `PhysicsWorld` it has no rigid bodies or collisions and no `matter-js` dependency.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { XpbdWorld } from '@datamoc/mw_games/physics/xpbd';
|
|
87
|
+
*
|
|
88
|
+
* const world = new XpbdWorld({ gravity: 520 });
|
|
89
|
+
* const wall = world.addNode({ x: 0, y: 0, fixed: true });
|
|
90
|
+
* const weight = world.addNode({ x: 40, y: 0, mass: 1 });
|
|
91
|
+
* const rope = world.addLink({ a: wall, b: weight, stiffness: 2e4, strength: 900 });
|
|
92
|
+
* world.breaking = true;
|
|
93
|
+
* for (let i = 0; i < 120; i++) world.step();
|
|
94
|
+
* console.log(world.links[rope].broken, world.nodes[weight].y > 0);
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare class XpbdWorld {
|
|
98
|
+
readonly nodes: XpbdNode[];
|
|
99
|
+
readonly links: XpbdLink[];
|
|
100
|
+
/** fires once for a link that passed its strength, which has already stopped carrying load */
|
|
101
|
+
readonly onBreak: Signal<{
|
|
102
|
+
link: number;
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
}>;
|
|
106
|
+
/** links break only while this is true, so a structure can settle under its own weight first */
|
|
107
|
+
breaking: boolean;
|
|
108
|
+
/** the highest smoothed load ratio across the links at the last step, for a strain gauge */
|
|
109
|
+
peakRatio: number;
|
|
110
|
+
gravity: number;
|
|
111
|
+
damping: number;
|
|
112
|
+
/** nodes are held on or above this; null for none. Water, a gorge or a cliff face is the game's own business */
|
|
113
|
+
ground: XpbdGround | null;
|
|
114
|
+
groundFriction: number;
|
|
115
|
+
private readonly frame;
|
|
116
|
+
private readonly substeps;
|
|
117
|
+
private readonly iterations;
|
|
118
|
+
private readonly smoothing;
|
|
119
|
+
private readonly forces;
|
|
120
|
+
private readonly masses;
|
|
121
|
+
private readonly lambda;
|
|
122
|
+
private readonly accumulated;
|
|
123
|
+
constructor(options?: XpbdOptions);
|
|
124
|
+
/** adds a node and returns its index */
|
|
125
|
+
addNode(spec: XpbdNodeSpec): number;
|
|
126
|
+
/** adds a link between two existing nodes and returns its index */
|
|
127
|
+
addLink(spec: XpbdLinkSpec): number;
|
|
128
|
+
/** an external force on a node for the next `step` only (a wheel's weight, wind) */
|
|
129
|
+
applyForce(node: number, fx: number, fy: number): void;
|
|
130
|
+
/** advances one frame: the substeps, then the link loads and any breaking */
|
|
131
|
+
step(): void;
|
|
132
|
+
private refreshInverseMass;
|
|
133
|
+
private substep;
|
|
134
|
+
/** lifts any node that sank below the ground back onto it, and takes some of its sideways motion with it */
|
|
135
|
+
private collideWithGround;
|
|
136
|
+
/** averages each link's force over the substeps, smooths the load ratio and breaks what passed its strength */
|
|
137
|
+
private settleLoads;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=XpbdWorld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XpbdWorld.d.ts","sourceRoot":"","sources":["../../src/physics/XpbdWorld.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC3B,qGAAqG;IACrG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sGAAsG;IACtG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yGAAyG;IACzG,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,8FAA8F;AAC9F,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,iCAAiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oIAAoI;IACpI,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,CAAC,EAAE,MAAM,CAAC;CACV;AAED,MAAM,WAAW,QAAQ;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,SAAS;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAM;IAChC,8FAA8F;IAC9F,QAAQ,CAAC,OAAO;cAAsB,MAAM;WAAK,MAAM;WAAK,MAAM;OAAM;IACxE,gGAAgG;IAChG,QAAQ,UAAS;IACjB,4FAA4F;IAC5F,SAAS,SAAK;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gHAAgH;IAChH,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAE5C,YAAY,OAAO,GAAE,WAAgB,EAQpC;IAED,wCAAwC;IACxC,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAQlC;IAED,mEAAmE;IACnE,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA0BlC;IAED,oFAAoF;IACpF,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAGrD;IAED,6EAA6E;IAC7E,IAAI,IAAI,IAAI,CASX;IAED,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,OAAO;IA8Cf,4GAA4G;IAC5G,OAAO,CAAC,iBAAiB;IAYzB,+GAA+G;IAC/G,OAAO,CAAC,WAAW;CAmBnB"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.js';
|
|
2
|
+
/**
|
|
3
|
+
* A deterministic structure solver: point masses joined by springs, solved with extended
|
|
4
|
+
* position-based dynamics (XPBD), with the force in every link read back so a link can break
|
|
5
|
+
* at a real load rather than at a stretch.
|
|
6
|
+
*
|
|
7
|
+
* The method (Macklin, Muller and Chentanaput's XPBD) moves each node freely for a substep,
|
|
8
|
+
* then corrects positions so every link returns to its rest length, with a compliance of
|
|
9
|
+
* `rest / stiffness / dt^2`: a link behaves as a spring of the stated stiffness whatever the
|
|
10
|
+
* step or iteration count, and the correction's Lagrange multiplier divided by `dt^2` is the
|
|
11
|
+
* force it carried. Steps are fixed and nothing is random, so the same structure and the same
|
|
12
|
+
* calls give the same result on every machine, which is what replaying or validating a
|
|
13
|
+
* player's bridge needs.
|
|
14
|
+
*
|
|
15
|
+
* It is the engine of Pontifex (a bridge-building game), generalised: the vehicle, the water
|
|
16
|
+
* and the levels stay in the game, and what is here is only nodes, links, forces and breaking.
|
|
17
|
+
* Unlike `PhysicsWorld` it has no rigid bodies or collisions and no `matter-js` dependency.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { XpbdWorld } from '@datamoc/mw_games/physics/xpbd';
|
|
22
|
+
*
|
|
23
|
+
* const world = new XpbdWorld({ gravity: 520 });
|
|
24
|
+
* const wall = world.addNode({ x: 0, y: 0, fixed: true });
|
|
25
|
+
* const weight = world.addNode({ x: 40, y: 0, mass: 1 });
|
|
26
|
+
* const rope = world.addLink({ a: wall, b: weight, stiffness: 2e4, strength: 900 });
|
|
27
|
+
* world.breaking = true;
|
|
28
|
+
* for (let i = 0; i < 120; i++) world.step();
|
|
29
|
+
* console.log(world.links[rope].broken, world.nodes[weight].y > 0);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class XpbdWorld {
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.nodes = [];
|
|
35
|
+
this.links = [];
|
|
36
|
+
/** fires once for a link that passed its strength, which has already stopped carrying load */
|
|
37
|
+
this.onBreak = new Signal();
|
|
38
|
+
/** links break only while this is true, so a structure can settle under its own weight first */
|
|
39
|
+
this.breaking = false;
|
|
40
|
+
/** the highest smoothed load ratio across the links at the last step, for a strain gauge */
|
|
41
|
+
this.peakRatio = 0;
|
|
42
|
+
/** nodes are held on or above this; null for none. Water, a gorge or a cliff face is the game's own business */
|
|
43
|
+
this.ground = null;
|
|
44
|
+
this.forces = [];
|
|
45
|
+
this.masses = [];
|
|
46
|
+
this.lambda = [];
|
|
47
|
+
this.accumulated = [];
|
|
48
|
+
this.gravity = options.gravity ?? 520;
|
|
49
|
+
this.damping = options.damping ?? 2.5;
|
|
50
|
+
this.groundFriction = options.groundFriction ?? 0.5;
|
|
51
|
+
this.frame = options.step ?? 1 / 60;
|
|
52
|
+
this.substeps = Math.max(1, Math.floor(options.substeps ?? 16));
|
|
53
|
+
this.iterations = Math.max(1, Math.floor(options.iterations ?? 2));
|
|
54
|
+
this.smoothing = options.smoothing ?? 0.06;
|
|
55
|
+
}
|
|
56
|
+
/** adds a node and returns its index */
|
|
57
|
+
addNode(spec) {
|
|
58
|
+
const mass = spec.mass ?? 1;
|
|
59
|
+
if (!(mass > 0) && !spec.fixed)
|
|
60
|
+
throw new Error('a moving node needs a positive mass');
|
|
61
|
+
this.nodes.push({ x: spec.x, y: spec.y, fixed: spec.fixed ?? false, vx: 0, vy: 0, w: 0 });
|
|
62
|
+
this.masses.push(mass);
|
|
63
|
+
this.forces.push({ x: 0, y: 0 });
|
|
64
|
+
this.refreshInverseMass();
|
|
65
|
+
return this.nodes.length - 1;
|
|
66
|
+
}
|
|
67
|
+
/** adds a link between two existing nodes and returns its index */
|
|
68
|
+
addLink(spec) {
|
|
69
|
+
const a = this.nodes[spec.a];
|
|
70
|
+
const b = this.nodes[spec.b];
|
|
71
|
+
if (!a || !b)
|
|
72
|
+
throw new Error('a link needs two existing nodes');
|
|
73
|
+
const rest = spec.rest ?? Math.hypot(a.x - b.x, a.y - b.y);
|
|
74
|
+
if (!(rest > 0))
|
|
75
|
+
throw new Error('a link needs a positive rest length');
|
|
76
|
+
if (!(spec.stiffness > 0))
|
|
77
|
+
throw new Error('a link needs a positive stiffness');
|
|
78
|
+
const share = (spec.mass ?? 0) / 2;
|
|
79
|
+
this.masses[spec.a] += share;
|
|
80
|
+
this.masses[spec.b] += share;
|
|
81
|
+
this.links.push({
|
|
82
|
+
a: spec.a,
|
|
83
|
+
b: spec.b,
|
|
84
|
+
stiffness: spec.stiffness,
|
|
85
|
+
rest,
|
|
86
|
+
tensionOnly: spec.tensionOnly ?? false,
|
|
87
|
+
strength: spec.strength,
|
|
88
|
+
tensionStrength: spec.tensionStrength,
|
|
89
|
+
broken: false,
|
|
90
|
+
force: 0,
|
|
91
|
+
ratio: 0,
|
|
92
|
+
});
|
|
93
|
+
this.lambda.push(0);
|
|
94
|
+
this.accumulated.push(0);
|
|
95
|
+
this.refreshInverseMass();
|
|
96
|
+
return this.links.length - 1;
|
|
97
|
+
}
|
|
98
|
+
/** an external force on a node for the next `step` only (a wheel's weight, wind) */
|
|
99
|
+
applyForce(node, fx, fy) {
|
|
100
|
+
this.forces[node].x += fx;
|
|
101
|
+
this.forces[node].y += fy;
|
|
102
|
+
}
|
|
103
|
+
/** advances one frame: the substeps, then the link loads and any breaking */
|
|
104
|
+
step() {
|
|
105
|
+
const dt = this.frame / this.substeps;
|
|
106
|
+
this.accumulated.fill(0);
|
|
107
|
+
for (let s = 0; s < this.substeps; s++)
|
|
108
|
+
this.substep(dt);
|
|
109
|
+
for (const force of this.forces) {
|
|
110
|
+
force.x = 0;
|
|
111
|
+
force.y = 0;
|
|
112
|
+
}
|
|
113
|
+
this.settleLoads();
|
|
114
|
+
}
|
|
115
|
+
refreshInverseMass() {
|
|
116
|
+
this.nodes.forEach((node, i) => {
|
|
117
|
+
node.w = node.fixed ? 0 : 1 / this.masses[i];
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
substep(dt) {
|
|
121
|
+
const damp = Math.exp(-this.damping * dt);
|
|
122
|
+
const previous = this.nodes.map((node) => ({ x: node.x, y: node.y }));
|
|
123
|
+
this.nodes.forEach((node, i) => {
|
|
124
|
+
if (node.fixed)
|
|
125
|
+
return;
|
|
126
|
+
const force = this.forces[i];
|
|
127
|
+
node.vx = (node.vx + force.x * node.w * dt) * damp;
|
|
128
|
+
node.vy = (node.vy + (force.y * node.w + this.gravity) * dt) * damp;
|
|
129
|
+
node.x += node.vx * dt;
|
|
130
|
+
node.y += node.vy * dt;
|
|
131
|
+
});
|
|
132
|
+
this.lambda.fill(0);
|
|
133
|
+
for (let iteration = 0; iteration < this.iterations; iteration++) {
|
|
134
|
+
this.links.forEach((link, i) => {
|
|
135
|
+
if (link.broken)
|
|
136
|
+
return;
|
|
137
|
+
const p = this.nodes[link.a];
|
|
138
|
+
const q = this.nodes[link.b];
|
|
139
|
+
const w = p.w + q.w;
|
|
140
|
+
if (w === 0)
|
|
141
|
+
return;
|
|
142
|
+
const dx = q.x - p.x;
|
|
143
|
+
const dy = q.y - p.y;
|
|
144
|
+
const length = Math.hypot(dx, dy) || 1e-9;
|
|
145
|
+
const c = length - link.rest;
|
|
146
|
+
if (link.tensionOnly && c < 0 && this.lambda[i] >= 0)
|
|
147
|
+
return;
|
|
148
|
+
const alpha = link.rest / link.stiffness / (dt * dt);
|
|
149
|
+
const delta = (-c - alpha * this.lambda[i]) / (w + alpha);
|
|
150
|
+
this.lambda[i] += delta;
|
|
151
|
+
const nx = dx / length;
|
|
152
|
+
const ny = dy / length;
|
|
153
|
+
p.x -= p.w * delta * nx;
|
|
154
|
+
p.y -= p.w * delta * ny;
|
|
155
|
+
q.x += q.w * delta * nx;
|
|
156
|
+
q.y += q.w * delta * ny;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
this.collideWithGround(previous);
|
|
160
|
+
this.nodes.forEach((node, i) => {
|
|
161
|
+
if (node.fixed)
|
|
162
|
+
return;
|
|
163
|
+
node.vx = (node.x - previous[i].x) / dt;
|
|
164
|
+
node.vy = (node.y - previous[i].y) / dt;
|
|
165
|
+
});
|
|
166
|
+
this.links.forEach((_, i) => {
|
|
167
|
+
this.accumulated[i] += -this.lambda[i] / (dt * dt);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/** lifts any node that sank below the ground back onto it, and takes some of its sideways motion with it */
|
|
171
|
+
collideWithGround(previous) {
|
|
172
|
+
const ground = this.ground;
|
|
173
|
+
if (ground === null)
|
|
174
|
+
return;
|
|
175
|
+
this.nodes.forEach((node, i) => {
|
|
176
|
+
if (node.fixed)
|
|
177
|
+
return;
|
|
178
|
+
const surface = typeof ground === 'number' ? ground : ground(node.x);
|
|
179
|
+
if (node.y <= surface)
|
|
180
|
+
return;
|
|
181
|
+
node.y = surface;
|
|
182
|
+
node.x -= (node.x - previous[i].x) * this.groundFriction;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/** averages each link's force over the substeps, smooths the load ratio and breaks what passed its strength */
|
|
186
|
+
settleLoads() {
|
|
187
|
+
const blend = 1 - Math.exp(-this.frame / this.smoothing);
|
|
188
|
+
let peak = 0;
|
|
189
|
+
this.links.forEach((link, i) => {
|
|
190
|
+
if (link.broken)
|
|
191
|
+
return;
|
|
192
|
+
link.force = this.accumulated[i] / this.substeps;
|
|
193
|
+
const limit = link.force > 0 ? (link.tensionStrength ?? link.strength) : link.strength;
|
|
194
|
+
const instant = limit === undefined ? 0 : Math.abs(link.force) / limit;
|
|
195
|
+
link.ratio += (instant - link.ratio) * blend;
|
|
196
|
+
peak = Math.max(peak, link.ratio);
|
|
197
|
+
if (this.breaking && link.ratio > 1) {
|
|
198
|
+
link.broken = true;
|
|
199
|
+
const p = this.nodes[link.a];
|
|
200
|
+
const q = this.nodes[link.b];
|
|
201
|
+
this.onBreak.dispatch({ link: i, x: (p.x + q.x) / 2, y: (p.y + q.y) / 2 });
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
this.peakRatio = peak;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=XpbdWorld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XpbdWorld.js","sourceRoot":"","sources":["../../src/physics/XpbdWorld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/physics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|