@beetpx/beetpx
Version:
A TypeScript framework for pixel art browser games.
195 lines • 6.73 kB
JavaScript
import { BeetPx } from "../";
import { BpxTimer } from "./Timer";
export class BpxTimerSequence {
static of(params, opts) {
return new BpxTimerSequence(params, opts);
}
#firstIterationPhases;
#loopPhases;
#firstIterationFrames;
#loopFrames;
#firstIterationOffset;
#ignoreGamePause;
#onGamePause;
#isPaused;
#pausedFrame;
#firstIterationTimer;
#loopTimer;
#recentlyComputedNow;
constructor(params, opts) {
this.#ignoreGamePause = opts.onGamePause === "ignore";
this.#onGamePause = opts.onGamePause;
this.#firstIterationPhases = [...params.intro, ...params.loop].map(entry => ({
name: entry[0],
frames: Math.max(0, Math.round(entry[1])),
}));
this.#loopPhases = params.loop.map(entry => ({
name: entry[0],
frames: Math.max(0, Math.round(entry[1])),
}));
this.#firstIterationFrames = this.#firstIterationPhases.reduce((acc, p) => acc + p.frames, 0);
this.#loopFrames = this.#loopPhases.reduce((acc, p) => acc + p.frames, 0);
this.#firstIterationOffset = this.#fn + opts.delayFrames;
this.#firstIterationTimer = BpxTimer.of({
frames: this.#firstIterationFrames,
loop: false,
paused: opts.paused,
delayFrames: opts.delayFrames,
onGamePause: this.#onGamePause,
});
this.#loopTimer =
this.#loopPhases.length > 0
? BpxTimer.of({
frames: this.#loopFrames,
loop: true,
paused: opts.paused,
delayFrames: opts.delayFrames + this.#firstIterationFrames,
onGamePause: this.#onGamePause,
})
: null;
this.#isPaused = false;
this.#pausedFrame = null;
if (opts.paused) {
this.pause();
}
}
get #now() {
if (this.#recentlyComputedNow?.frameNumber === (this.#pausedFrame ?? this.#fn)) {
return this.#recentlyComputedNow.value;
}
if (!this.#loopTimer ||
(this.#pausedFrame ?? this.#fn) <
this.#firstIterationOffset + this.#firstIterationFrames) {
const firstIterationT = this.#firstIterationTimer.t;
let offset = 0;
let prev = null;
let i = 0;
while (i < this.#firstIterationPhases.length - 1) {
let curr = this.#firstIterationPhases[i];
if (firstIterationT < offset + curr.frames) {
return {
recentlyFinishedPhase: prev?.name ?? null,
phase: curr,
t: firstIterationT - offset,
};
}
offset += curr.frames;
prev = curr;
i += 1;
}
let curr = this.#firstIterationPhases[i] ?? null;
return {
recentlyFinishedPhase: this.#firstIterationTimer.hasJustFinished
? (curr?.name ?? null)
: (prev?.name ?? null),
phase: curr,
t: firstIterationT - offset,
};
}
const loopT = this.#loopTimer.t;
let offset = 0;
let prev = this.#firstIterationPhases[this.#firstIterationPhases.length - 1] ?? null;
let i = 0;
while (i < this.#loopPhases.length - 1) {
let curr = this.#loopPhases[i];
if (loopT < offset + curr.frames) {
return {
recentlyFinishedPhase: prev?.name ?? null,
phase: curr,
t: loopT - offset,
};
}
offset += curr.frames;
prev = curr;
i += 1;
}
let curr = this.#loopPhases[i] ?? null;
return {
recentlyFinishedPhase: prev?.name ?? null,
phase: curr,
t: loopT - offset,
};
}
get justFinishedPhase() {
return this.hasJustFinishedOverall || this.#now.t === 0
? this.#now.recentlyFinishedPhase
: null;
}
get currentPhase() {
return this.#now.phase?.name ?? null;
}
get #fn() {
return this.#ignoreGamePause
? BeetPx.frameNumber
: BeetPx.frameNumberOutsidePause;
}
get t() {
return this.#now.t;
}
get progress() {
return this.#now.phase && this.#now.phase.frames > 0
? this.#now.t / this.#now.phase.frames
: 1;
}
get framesLeft() {
return this.#now.phase ? this.#now.phase.frames - this.#now.t : 0;
}
get tOverall() {
return this.#firstIterationTimer.hasFinished
? (this.#loopTimer?.t ?? this.#firstIterationTimer.t)
: this.#firstIterationTimer.t;
}
get framesLeftOverall() {
return this.#firstIterationTimer.hasFinished
? (this.#loopTimer?.framesLeft ?? this.#firstIterationTimer.framesLeft)
: this.#firstIterationTimer.framesLeft;
}
get progressOverall() {
return this.#firstIterationTimer.hasFinished
? (this.#loopTimer?.progress ?? this.#firstIterationTimer.progress)
: this.#firstIterationTimer.progress;
}
get hasFinishedOverall() {
return this.#firstIterationTimer.hasFinished;
}
get hasJustFinishedOverall() {
return (this.#loopTimer?.hasJustFinished ||
this.#firstIterationTimer.hasJustFinished);
}
get isPaused() {
return this.#isPaused;
}
pause() {
if (this.#isPaused)
return;
this.#isPaused = true;
this.#pausedFrame = this.#fn;
this.#firstIterationTimer.pause();
this.#loopTimer?.pause();
}
resume() {
if (!this.#isPaused)
return;
this.#isPaused = false;
this.#firstIterationOffset += this.#fn - (this.#pausedFrame ?? 0);
this.#pausedFrame = null;
this.#firstIterationTimer.resume();
this.#loopTimer?.resume();
}
restart() {
this.#firstIterationOffset = this.#fn;
this.#isPaused = false;
this.#pausedFrame = null;
this.#firstIterationTimer.restart();
if (this.#loopTimer) {
this.#loopTimer = BpxTimer.of({
frames: this.#loopFrames,
loop: true,
paused: false,
delayFrames: this.#firstIterationFrames,
onGamePause: this.#onGamePause,
});
}
}
}
//# sourceMappingURL=TimerSequence.js.map