2017-04-27 17:03:19 +01:00
|
|
|
var NOOP = require('../utils/NOOP');
|
|
|
|
var RequestAnimationFrame = require('../dom/RequestAnimationFrame');
|
|
|
|
|
|
|
|
var VariableTimeStep = function (game, framerate)
|
|
|
|
{
|
|
|
|
this.game = game;
|
|
|
|
|
|
|
|
this.raf = new RequestAnimationFrame();
|
|
|
|
|
|
|
|
this.started = false;
|
|
|
|
this.running = false;
|
|
|
|
|
2017-04-28 03:14:30 +01:00
|
|
|
// For fixed-step physics
|
2017-04-27 17:03:19 +01:00
|
|
|
this.fps = framerate;
|
|
|
|
|
|
|
|
this.callback = NOOP;
|
|
|
|
|
|
|
|
this.useRAF = true;
|
|
|
|
|
|
|
|
this.time = 0;
|
|
|
|
this.startTime = 0;
|
|
|
|
this.lastTime = 0;
|
2017-05-03 00:54:09 +01:00
|
|
|
this.runOff = 0;
|
2017-04-27 17:03:19 +01:00
|
|
|
|
|
|
|
this.delta = 0;
|
|
|
|
this.deltaIndex = 0;
|
|
|
|
this.deltaHistory = [];
|
|
|
|
this.deltaSmoothingMax = 30;
|
|
|
|
};
|
|
|
|
|
|
|
|
VariableTimeStep.prototype.constructor = VariableTimeStep;
|
|
|
|
|
|
|
|
VariableTimeStep.prototype = {
|
|
|
|
|
|
|
|
start: function (useRAF, callback)
|
|
|
|
{
|
|
|
|
if (this.started)
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.started = true;
|
|
|
|
this.running = true;
|
|
|
|
|
2017-04-28 03:14:30 +01:00
|
|
|
var now = window.performance.now();
|
|
|
|
|
|
|
|
this.time = now;
|
|
|
|
this.startTime = now;
|
|
|
|
this.lastTime = now;
|
2017-05-03 00:54:09 +01:00
|
|
|
this.runOff = 0;
|
2017-04-27 17:03:19 +01:00
|
|
|
|
|
|
|
// Pre-populate smoothing array
|
|
|
|
|
|
|
|
var history = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < this.deltaSmoothingMax; i++)
|
|
|
|
{
|
|
|
|
history[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.delta = 0;
|
|
|
|
this.deltaIndex = 0;
|
|
|
|
this.deltaHistory = history;
|
|
|
|
|
|
|
|
this.useRAF = useRAF;
|
|
|
|
this.callback = callback;
|
|
|
|
|
|
|
|
this.raf.start(this.step.bind(this), useRAF);
|
|
|
|
},
|
|
|
|
|
|
|
|
step: function (time)
|
|
|
|
{
|
|
|
|
// delta time
|
|
|
|
var dt = (time - this.lastTime) / 1000;
|
|
|
|
|
|
|
|
if (dt < 0 || dt > 1)
|
|
|
|
{
|
|
|
|
// Loop skip, probably super bad start time
|
2017-05-03 00:54:09 +01:00
|
|
|
this.runOff = time - this.lastTime;
|
2017-04-27 17:03:19 +01:00
|
|
|
this.lastTime = time;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clamp delta to 0.0001 to 0.5 range
|
|
|
|
dt = Math.max(Math.min(dt, 0.5), 0.0001);
|
|
|
|
|
2017-05-03 00:54:09 +01:00
|
|
|
// Smooth out the delta over the previous X frames
|
2017-04-27 17:03:19 +01:00
|
|
|
|
|
|
|
var idx = this.deltaIndex;
|
|
|
|
var history = this.deltaHistory;
|
|
|
|
var max = this.deltaSmoothingMax;
|
|
|
|
|
|
|
|
// add the delta to the smoothing array
|
|
|
|
history[idx] = dt;
|
|
|
|
|
|
|
|
// adjusts the delta history array index based on the smoothing count
|
|
|
|
// this stops the array growing beyond the size of deltaSmoothingMax
|
|
|
|
this.deltaIndex = (idx + 1) % max;
|
|
|
|
|
|
|
|
// average
|
|
|
|
var avg = 0;
|
|
|
|
|
2017-04-28 03:14:30 +01:00
|
|
|
// Loop the history array, adding the delta values together
|
2017-04-27 17:03:19 +01:00
|
|
|
for (var i = 0; i < max; i++)
|
|
|
|
{
|
|
|
|
avg += history[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then divide by the array length to get the average delta
|
|
|
|
avg /= max;
|
|
|
|
|
|
|
|
// Set as the world delta value
|
|
|
|
this.delta = avg;
|
|
|
|
|
|
|
|
// Real-world timer advance
|
|
|
|
this.time += avg;
|
|
|
|
|
|
|
|
this.callback(this.time, avg * 1000);
|
|
|
|
|
|
|
|
// Shift time value over
|
|
|
|
this.lastTime = time;
|
|
|
|
},
|
|
|
|
|
|
|
|
tick: function ()
|
|
|
|
{
|
2017-04-28 03:14:30 +01:00
|
|
|
this.step(window.performance.now());
|
2017-04-27 17:03:19 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
sleep: function ()
|
|
|
|
{
|
|
|
|
if (this.running)
|
|
|
|
{
|
|
|
|
this.raf.stop();
|
|
|
|
|
|
|
|
this.running = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
wake: function (seamless)
|
|
|
|
{
|
|
|
|
if (this.running)
|
|
|
|
{
|
|
|
|
this.sleep();
|
|
|
|
}
|
|
|
|
else if (seamless)
|
|
|
|
{
|
2017-04-28 03:14:30 +01:00
|
|
|
this.startTime += -this.lastTime + (this.lastTime = window.performance.now());
|
2017-04-27 17:03:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
this.raf.start(this.step.bind(this), this.useRAF);
|
|
|
|
|
|
|
|
this.running = true;
|
|
|
|
|
2017-04-28 03:14:30 +01:00
|
|
|
this.step(window.performance.now());
|
2017-04-27 17:03:19 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
setFps: function (value)
|
|
|
|
{
|
|
|
|
this.fps = value;
|
|
|
|
|
|
|
|
this.wake();
|
|
|
|
},
|
|
|
|
|
|
|
|
getFps: function ()
|
|
|
|
{
|
|
|
|
return this.fps;
|
|
|
|
},
|
|
|
|
|
|
|
|
stop: function ()
|
|
|
|
{
|
|
|
|
this.running = false;
|
|
|
|
this.started = false;
|
|
|
|
|
|
|
|
this.raf.stop();
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = VariableTimeStep;
|