46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
import { clamp } from './clamp';
|
|
import { exponentialDecay } from './exponential-decay';
|
|
|
|
export class DeltaTimeCalculator {
|
|
private static FPS_EXPONENTIAL_DECAY_STRENGTH = 0.1;
|
|
|
|
private previousTime: DOMHighResTimeStamp | null = null;
|
|
private deltaTimeAccumulator: number | null = null;
|
|
|
|
constructor(
|
|
private readonly maxDeltaTimeInSeconds: number = 1 / 30,
|
|
private readonly minDeltaTimeInSeconds: number = 1 / 240
|
|
) {
|
|
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
|
}
|
|
|
|
public calculateDeltaTimeInSeconds(
|
|
currentTime: DOMHighResTimeStamp
|
|
): DOMHighResTimeStamp {
|
|
if (this.previousTime === null) {
|
|
this.previousTime = currentTime;
|
|
}
|
|
|
|
const delta = currentTime - this.previousTime;
|
|
this.previousTime = currentTime;
|
|
const deltaInSeconds = delta / 1000;
|
|
|
|
this.deltaTimeAccumulator = exponentialDecay({
|
|
accumulator: this.deltaTimeAccumulator ?? deltaInSeconds,
|
|
nextValue: deltaInSeconds,
|
|
biasOfNextValue: DeltaTimeCalculator.FPS_EXPONENTIAL_DECAY_STRENGTH,
|
|
});
|
|
|
|
return clamp(delta / 1000, this.minDeltaTimeInSeconds, this.maxDeltaTimeInSeconds);
|
|
}
|
|
|
|
private handleVisibilityChange() {
|
|
if (!document.hidden) {
|
|
this.previousTime = null;
|
|
}
|
|
}
|
|
|
|
public get fps() {
|
|
return 1 / this.deltaTimeAccumulator;
|
|
}
|
|
}
|