@spearwolf/twopoint5d
Version:
Create 2.5D realtime graphics and pixelart with WebGL and three.js
98 lines • 3.03 kB
JavaScript
import { emit, eventize, off, on, once } from '@spearwolf/eventize';
import { OnDisplayDispose, OnDisplayRenderFrame } from '../events.js';
const OnTick = Symbol.for('twopoint5d:FixedFrameLoop.OnTick');
const OnRender = Symbol.for('twopoint5d:FixedFrameLoop.OnRender');
export class FixedFrameLoop {
static { this.OnTick = OnTick; }
static { this.OnRender = OnRender; }
static { this.DefaultFps = 60; }
static { this.DefaultMaxStepsPerFrame = 5; }
#fps;
#fixedDelta;
#accumulator;
#tickTime;
#tickNo;
#alpha;
#disposed;
get fps() {
return this.#fps;
}
set fps(value) {
if (!Number.isFinite(value) || value <= 0)
return;
this.#fps = value;
this.#fixedDelta = 1 / value;
}
get fixedDelta() {
return this.#fixedDelta;
}
get tickTime() {
return this.#tickTime;
}
get tickNo() {
return this.#tickNo;
}
get alpha() {
return this.#alpha;
}
get isDisposed() {
return this.#disposed;
}
constructor(display, options) {
this.#accumulator = 0;
this.#tickTime = 0;
this.#tickNo = 0;
this.#alpha = 0;
this.#disposed = false;
this.onTick = on.bind(undefined, this, OnTick);
this.onRender = on.bind(undefined, this, OnRender);
eventize(this);
this.display = display;
this.#fps = options?.fps ?? FixedFrameLoop.DefaultFps;
this.#fixedDelta = 1 / this.#fps;
this.maxStepsPerFrame = options?.maxStepsPerFrame ?? FixedFrameLoop.DefaultMaxStepsPerFrame;
on(display, OnDisplayRenderFrame, this);
once(display, OnDisplayDispose, () => this.dispose());
}
[OnDisplayRenderFrame](props) {
if (this.#disposed)
return;
this.#accumulator += props.deltaTime;
let steps = 0;
while (this.#accumulator >= this.#fixedDelta && steps < this.maxStepsPerFrame) {
emit(this, OnTick, {
fixedDelta: this.#fixedDelta,
tickTime: this.#tickTime,
tickNo: this.#tickNo,
});
this.#accumulator -= this.#fixedDelta;
this.#tickTime += this.#fixedDelta;
this.#tickNo += 1;
steps += 1;
}
if (steps >= this.maxStepsPerFrame && this.#accumulator >= this.#fixedDelta) {
this.#accumulator = 0;
}
this.#alpha = this.#accumulator / this.#fixedDelta;
emit(this, OnRender, {
...props,
alpha: this.#alpha,
tickTime: this.#tickTime,
tickNo: this.#tickNo,
});
}
reset() {
this.#accumulator = 0;
this.#tickTime = 0;
this.#tickNo = 0;
this.#alpha = 0;
}
dispose() {
if (this.#disposed)
return;
this.#disposed = true;
off(this.display, OnDisplayRenderFrame, this);
off(this);
}
}
//# sourceMappingURL=FixedFrameLoop.js.map