console
var box = document.getElementById('box'), // the box
boxPos = 10, // the box's position
limit = 300; // how far the box can go before it switches direction
var fpsDisplay = document.getElementById('fpsDisplay');
function draw(interp) {
box.style.left = (boxLastPos + (boxPos - boxLastPos) * interp) + 'px'; // interpolate
fpsDisplay.textContent = Math.round(fps) + ' FPS'; // display the FPS
}
// Re-adjust the velocity now that it's not dependent on FPS
var boxVelocity = 0.08,
delta = 0;
var boxLastPos = 10;
function update(delta) { // new delta parameter
boxLastPos = boxPos; // save the position from the last update
boxPos += boxVelocity * delta; // velocity is now time-sensitive
// Switch directions if we go too far
if (boxPos >= limit || boxPos <= 0) boxVelocity = -boxVelocity;
}
var lastFrameTimeMs = 0, // The last time the loop was run
maxFPS = 60; // The maximum FPS we want to allow
// We want to simulate 1000 ms / 60 FPS = 16.667 ms per frame every time we run update()
var timestep = 1000 / 60;
var fps = 60,
framesThisSecond = 0,
lastFpsUpdate = 0;
function mainLoop(timestamp) {
// Throttle the frame rate.
if (timestamp < lastFrameTimeMs + (1000 / maxFPS)) {
frameID = requestAnimationFrame(mainLoop);
return;
}
// Calculate current FPS
if (timestamp > lastFpsUpdate + 1000) { // update every second
fps = 0.25 * framesThisSecond + (1 - 0.25) * fps; // compute the new FPS
lastFpsUpdate = timestamp;
framesThisSecond = 0;
}
framesThisSecond++;
// Track the accumulated time that hasn't been simulated yet
delta += timestamp - lastFrameTimeMs; // note += here
lastFrameTimeMs = timestamp;
// Simulate the total elapsed time in fixed-size chunks
var numUpdateSteps = 0;
while (delta >= timestep) {
update(timestep);
delta -= timestep;
// Sanity check
if (++numUpdateSteps >= 240) {
panic(); // fix things
break; // bail out
}
}
draw(delta / timestep);
frameID = requestAnimationFrame(mainLoop);
}
function panic() {
delta = 0; // discard the unsimulated time
// ... snap the player to the authoritative state
}
var frameID;
var running = false,
started = false;
function stop() {
running = false;
started = false;
cancelAnimationFrame(frameID);
}
function start() {
if (!started) { // don't request multiple frames
started = true;
// Dummy frame to get our timestamps and initial drawing right.
// Track the frame ID so we can cancel it if we stop quickly.
frameID = requestAnimationFrame(function(timestamp) {
draw(1); // initial draw
running = true;
// reset some time tracking variables
lastFrameTimeMs = timestamp;
lastFpsUpdate = timestamp;
framesThisSecond = 0;
// actually start the main loop
frameID = requestAnimationFrame(mainLoop);
});
}
}
// Start things off
start()
document.getElementById('start').onclick = start
document.getElementById('stop').onclick = stop
<div id="box"></div>
<div id="fpsDisplay"></div>
<button id="start">start</button>
<button id="stop">stop</button>
#box {
background-color: red;
height: 50px;
left: 150px;
position: absolute;
top: 10px;
width: 50px;
}