diff --git a/src/world/World.ts b/src/world/World.ts index 03d1e200b..6c6399ba6 100644 --- a/src/world/World.ts +++ b/src/world/World.ts @@ -388,15 +388,13 @@ export class World extends EventTarget { * world.step(1/60); * * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World + * @see https://gafferongames.com/post/fix_your_timestep/ */ - step(dt: number, timeSinceLastCalled = 0, maxSubSteps = 10): void { - if (timeSinceLastCalled === 0) { + step(dt: number, timeSinceLastCalled?: number, maxSubSteps: number = 10): void { + if (timeSinceLastCalled === undefined) { // Fixed, simple stepping this.internalStep(dt) - - // Increment time - this.time += dt } else { this.accumulator += timeSinceLastCalled let substeps = 0 @@ -407,14 +405,16 @@ export class World extends EventTarget { substeps++ } - const t = (this.accumulator % dt) / dt + // prevent the accumulator to build up delay to catch up. The logic being: if the step did not catch up at this frame, it is unlikely to catch up in the next one. Even if it does, it will result in a speed up simulation which is arguably worse that staying behind the real time. + this.accumulator = Math.max(this.accumulator, dt) + + const t = this.accumulator / dt for (let j = 0; j !== this.bodies.length; j++) { const b = this.bodies[j] b.previousPosition.lerp(b.position, t, b.interpolatedPosition) b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion) b.previousQuaternion.normalize() } - this.time += timeSinceLastCalled } }