@driftengine/physics 4.9.0 → 4.11.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.
@@ -42,7 +42,8 @@ export declare class ClothControl {
42
42
  reset(): void;
43
43
  /**
44
44
  * Advance by `dt` seconds of the caller's time, in whole fixed steps; how many ran. The remainder
45
- * is kept for the next call, and `alpha` says how far into the next step it reaches.
45
+ * is kept for the next call, and `alpha` says how far into the next step it reaches. At most
46
+ * `maxSteps` run, reaching the latest pose all the same; the whole steps past them are dropped.
46
47
  */
47
48
  advance(dt: number): number;
48
49
  /** How far the time handed to `advance` reaches into the next step, 0 to 1. */
@@ -63,13 +63,18 @@ export class ClothControl {
63
63
  }
64
64
  /**
65
65
  * Advance by `dt` seconds of the caller's time, in whole fixed steps; how many ran. The remainder
66
- * is kept for the next call, and `alpha` says how far into the next step it reaches.
66
+ * is kept for the next call, and `alpha` says how far into the next step it reaches. At most
67
+ * `maxSteps` run, reaching the latest pose all the same; the whole steps past them are dropped.
67
68
  */
68
69
  advance(dt) {
69
70
  this.accumulator += dt;
70
71
  const step = this.parameters.step;
71
72
  /* A millionth of a step of slack, so 1/30 is two steps of 1/60 and not one and a remainder. */
72
- const steps = Math.floor((this.accumulator + step * 1e-6) / step);
73
+ const whole = Math.floor((this.accumulator + step * 1e-6) / step);
74
+ const steps = Math.min(whole, this.parameters.maxSteps);
75
+ /* Dropped in one subtraction; the steps that run take theirs one at a time, as they always did. */
76
+ if (whole > steps)
77
+ this.accumulator -= (whole - steps) * step;
73
78
  for (let k = 0; k < steps; k++) {
74
79
  this.accumulator -= step;
75
80
  this.stepAt((k + 1) / steps);
@@ -77,6 +77,13 @@ export interface ClothCollider {
77
77
  export interface SkinnedClothParameters {
78
78
  /** The fixed step, in seconds. The solver runs whole steps whatever the frame. Default 1/60. */
79
79
  readonly step?: number;
80
+ /**
81
+ * The most whole steps one `advance` runs; the time past them is dropped, not owed to the next
82
+ * frame. Default none, so `advance(1)` is a second of cloth. A caller handing it each frame's time
83
+ * wants two to four: unbounded, a slow frame's steps make the next frame slower, which hands it
84
+ * more time again. What it gives up: past the cap the cloth runs slower than the clock.
85
+ */
86
+ readonly maxSteps?: number;
80
87
  /** Substeps a step. Default 1. */
81
88
  readonly substeps?: number;
82
89
  /** Constraint passes a substep. Default 4. */
@@ -140,6 +147,7 @@ export interface SkinnedClothSetup {
140
147
  /** The parameters with every default filled in. */
141
148
  export interface ResolvedClothParameters {
142
149
  readonly step: number;
150
+ readonly maxSteps: number;
143
151
  readonly substeps: number;
144
152
  readonly iterations: number;
145
153
  readonly gravity: readonly [number, number, number];
@@ -14,6 +14,7 @@
14
14
  export function resolveClothParameters(parameters) {
15
15
  return {
16
16
  step: parameters.step ?? 1 / 60,
17
+ maxSteps: Math.max(1, Math.floor(parameters.maxSteps ?? Infinity)),
17
18
  substeps: Math.max(1, Math.floor(parameters.substeps ?? 1)),
18
19
  iterations: Math.max(1, Math.floor(parameters.iterations ?? 4)),
19
20
  gravity: parameters.gravity ?? [0, -9.81, 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@driftengine/physics",
3
- "version": "4.9.0",
3
+ "version": "4.11.0",
4
4
  "description": "Collision shapes, spatial queries and swept kinematic collision",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -86,13 +86,17 @@ export class ClothControl {
86
86
 
87
87
  /**
88
88
  * Advance by `dt` seconds of the caller's time, in whole fixed steps; how many ran. The remainder
89
- * is kept for the next call, and `alpha` says how far into the next step it reaches.
89
+ * is kept for the next call, and `alpha` says how far into the next step it reaches. At most
90
+ * `maxSteps` run, reaching the latest pose all the same; the whole steps past them are dropped.
90
91
  */
91
92
  advance(dt: number): number {
92
93
  this.accumulator += dt;
93
94
  const step = this.parameters.step;
94
95
  /* A millionth of a step of slack, so 1/30 is two steps of 1/60 and not one and a remainder. */
95
- const steps = Math.floor((this.accumulator + step * 1e-6) / step);
96
+ const whole = Math.floor((this.accumulator + step * 1e-6) / step);
97
+ const steps = Math.min(whole, this.parameters.maxSteps);
98
+ /* Dropped in one subtraction; the steps that run take theirs one at a time, as they always did. */
99
+ if (whole > steps) this.accumulator -= (whole - steps) * step;
96
100
  for (let k = 0; k < steps; k++) {
97
101
  this.accumulator -= step;
98
102
  this.stepAt((k + 1) / steps);
@@ -83,6 +83,13 @@ export interface ClothCollider {
83
83
  export interface SkinnedClothParameters {
84
84
  /** The fixed step, in seconds. The solver runs whole steps whatever the frame. Default 1/60. */
85
85
  readonly step?: number;
86
+ /**
87
+ * The most whole steps one `advance` runs; the time past them is dropped, not owed to the next
88
+ * frame. Default none, so `advance(1)` is a second of cloth. A caller handing it each frame's time
89
+ * wants two to four: unbounded, a slow frame's steps make the next frame slower, which hands it
90
+ * more time again. What it gives up: past the cap the cloth runs slower than the clock.
91
+ */
92
+ readonly maxSteps?: number;
86
93
  /** Substeps a step. Default 1. */
87
94
  readonly substeps?: number;
88
95
  /** Constraint passes a substep. Default 4. */
@@ -148,6 +155,7 @@ export interface SkinnedClothSetup {
148
155
  /** The parameters with every default filled in. */
149
156
  export interface ResolvedClothParameters {
150
157
  readonly step: number;
158
+ readonly maxSteps: number;
151
159
  readonly substeps: number;
152
160
  readonly iterations: number;
153
161
  readonly gravity: readonly [number, number, number];
@@ -169,6 +177,7 @@ export function resolveClothParameters(
169
177
  ): ResolvedClothParameters {
170
178
  return {
171
179
  step: parameters.step ?? 1 / 60,
180
+ maxSteps: Math.max(1, Math.floor(parameters.maxSteps ?? Infinity)),
172
181
  substeps: Math.max(1, Math.floor(parameters.substeps ?? 1)),
173
182
  iterations: Math.max(1, Math.floor(parameters.iterations ?? 4)),
174
183
  gravity: parameters.gravity ?? [0, -9.81, 0],