fury-js
Version:
WebGL Game Engine
115 lines (94 loc) • 2.62 kB
JavaScript
const Input = require('./input');
module.exports = (function() {
let gameTime = 0; // Time in seconds that the game loop thinks it's run (i.e. accounting for clamps, pauses / focus loss)
let exports = {
get time() { return gameTime; },
};
let State = {
Paused: 0,
Running: 1,
RequestPause: 2
};
let state = State.Paused;
let stopCount = 0;
let maxFrameTimeMs = null;
let loopDelegate = null;
let lastTime = 0;
exports.timeScale = 1;
exports.init = function({ loop, maxFrameTimeMs: maxMs }) {
if (maxMs && typeof(maxMs) === 'number') {
// Optional max frame time to keep physics calculations sane
maxFrameTimeMs = maxMs;
}
if (loop && typeof(loop) === 'function') {
loopDelegate = loop;
} else {
console.error("You must provide GameLoop.init with a loop parameter of type function");
}
if (loopDelegate) {
window.addEventListener('blur', onWindowBlur);
window.addEventListener('focus', onWindowFocus);
}
};
exports.start = function() {
stopCount = Math.max(0, stopCount - 1);
if (stopCount == 0) {
switch (state) {
case State.Paused:
state = State.Running;
lastTime = Date.now();
Input.handleFrameFinished(); // clear any input that happened since pause
window.requestAnimationFrame(loop);
break;
case State.RequestPause:
state = State.Running;
break;
}
}
};
exports.stop = function() {
stopCount += 1;
if (state != State.Paused) {
state = State.RequestPause;
}
};
exports.isRunning = function() {
return state === State.Running;
};
let onWindowBlur = function() {
exports.stop();
};
let onWindowFocus = function() {
exports.start();
};
let loop = function() {
if (state == State.RequestPause) {
state = State.Paused;
return;
}
let elapsed = Date.now() - lastTime;
lastTime += elapsed;
if (elapsed == 0) {
console.warn("elapsed time of 0, skipping frame");
requestAnimationFrame(loop);
return;
}
elapsed *= exports.timeScale;
if (maxFrameTimeMs && elapsed > maxFrameTimeMs) {
elapsed = maxFrameTimeMs;
// Arguably could run multiple logic updates,
// however that would require tracking window focus
// and ensuring update length < maxFrameTime
}
elapsed /= 1000; // Convert elapsed to seconds
gameTime += elapsed;
try {
loopDelegate(elapsed);
} catch (error) {
console.error(error);
}
Input.handleFrameFinished();
window.requestAnimationFrame(loop);
};
return exports;
})();