52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import { formatError, formatErrorMessage } from "./errors";
|
|
import Input from "./input";
|
|
import { nextFrame } from "./utils";
|
|
|
|
type Setup<T> = () => Promise<T> | T;
|
|
type Frame<T> = (dt: number, state: T) => Promise<T | void> | T | void;
|
|
type GameMain = () => void;
|
|
|
|
export function gameLoop<T>(frame: Frame<T>): GameMain;
|
|
export function gameLoop<T>(setup: Setup<T>, frame: Frame<T>): GameMain;
|
|
export function gameLoop<T>(setupOrFrame: Setup<T> | Frame<T>, frame?: Frame<T>): GameMain {
|
|
return async () => {
|
|
let state: T;
|
|
try {
|
|
if (frame) {
|
|
state = await (setupOrFrame as Setup<T>)();
|
|
} else {
|
|
frame = setupOrFrame as Frame<T>;
|
|
state = {} as T;
|
|
}
|
|
} catch (e) {
|
|
console.error(formatError(e, 'Error in game setup'));
|
|
alert(formatErrorMessage(e));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
let prevFrame = performance.now();
|
|
while (true) {
|
|
await nextFrame();
|
|
Input.updateKeys();
|
|
|
|
const now = performance.now();
|
|
const dt = (now - prevFrame) / 1000;
|
|
|
|
if (dt < 1) {
|
|
const newState = await frame(dt, state);
|
|
if (newState) {
|
|
state = newState;
|
|
}
|
|
}
|
|
|
|
prevFrame = performance.now();
|
|
}
|
|
} catch (e) {
|
|
console.error(formatError(e, 'Error in game loop'));
|
|
alert(formatErrorMessage(e));
|
|
return;
|
|
}
|
|
}
|
|
};
|