Skip to content

Instantly share code, notes, and snippets.

@haxiomic
Last active January 5, 2021 15:39
Show Gist options
  • Save haxiomic/8ce12078301a6e6e9cfa to your computer and use it in GitHub Desktop.
Save haxiomic/8ce12078301a6e6e9cfa to your computer and use it in GitHub Desktop.
TimeLord.js: hack javascript's sense of time
window.TimeLord = (function(){
/*
# Time accounted for
Date.now()
window.performance.now()
window.setInterval(...)
window.setTimeout(...)
window.requestAnimationFrame(...)
# Not accounted for
(new Date()).getTime()
*/
var fakeTime_ms = 0;
var activateStamp = 0;
var intervalIdCounter = 1;
var intervals = [];
function stepTime(dt_ms){
fakeTime_ms += dt_ms;
var i = intervals.length;
while(--i >= 0){
var iObj = intervals[i];
var dt = fakeTime_ms - iObj.start_ms;
if(dt >= iObj.ms){
//fire
iObj.fn.apply(window, iObj.fnArgs);
if(iObj.loop){
iObj.start_ms += iObj.ms;
}else{
//remove
intervals.splice(i, 1);
}
}
}
}
function setTime(ms){
if(ms < fakeTime_ms){
console.warn('TimeLord: without a tardis or flux capacitor you\'re probably going to have errors if you try to go back in time');
}
var dt_ms = ms - fakeTime_ms;
stepFakeTime(dt_ms);//call stepTime so our intervals get fired
}
function getTime(){
return fakeTime_ms;
}
function addInterval(fn, ms, loop, fnArgs){
var id = intervalIdCounter++;
intervals.push({
id: id,
fn: fn,
ms: ms,
loop: loop,
fnArgs: fnArgs,
start_ms: fakeTime_ms,
});
return id;
}
function removeInterval(id){
var i = intervals.length;
while(--i >= 0){
if(intervals[i].id === id){
intervals.splice(i, 1);
break;
}
}
}
function activate(){
//override javascript time functions
activateStamp = Date.now();
//absolute time
Date._now = Date.now;
Date.now = function(){
return activateStamp + fakeTime_ms;
}
window.performance._now = window.performance.now;
window.performance.now = function(){
return fakeTime_ms;
}
//relative time
window._setTimeout = window.setTimeout;
window.setTimeout = function(fn, ms){
var fnArgs = Array.prototype.slice.call(arguments, [2]);
return addInterval(fn, ms, false, fnArgs);
}
window._setInterval = window.setInterval;
window.setInterval = function(fn, ms){
var fnArgs = Array.prototype.slice.call(arguments, [2]);
return addInterval(fn, ms, true, fnArgs);
}
window._clearInterval = window.clearInterval;
window.clearInterval = function(id){
removeInterval(id);
}
window._clearTimeout = window.clearTimeout;
window.clearTimeout = function(id){
removeInterval(id);
}
window._requestAnimationFrame = window.requestAnimationFrame;
window.requestAnimationFrame = function(cb){
var newCb = function(realTime_ms){
cb(fakeTime_ms);
}
return window._requestAnimationFrame(newCb);
}
}
return {
activate: activate,
stepTime: stepTime,
setTime: setTime,
getTime: getTime
};
})();
@haxiomic
Copy link
Author

Original functions accessed by prefixing _, eg: Date._now()

Example usage: run time at 1/2 speed

var multiplier = 0.5;

var lastRealTime_ms = window.performance._now();

function updateRealTime(realTime_ms){
    var dt = realTime_ms - lastRealTime_ms;
    TimeLord.stepTime(dt * multiplier);
    lastRealTime_ms = realTime_ms;

    window._requestAnimationFrame(updateRealTime);
}

updateRealTime(lastRealTime_ms);

@cola0405
Copy link

cola0405 commented Jan 5, 2021

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment