I've coded along with very simple game tutorials that use a simple requestAnimationFrame game loop. They have no need of tracking time elapsed or frame rate:
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
function gameLoop() {
ctx.clearRect(0,0,canvas.width,canvas.height);
//Drawing, etc.
var myRAF = requestAnimationFrame(gameLoop);
}
gameLoop();
Now I want to learn how to animate things like walk cycles from a spritesheet, rather than only animating movement of a static object. I believe that requires first learning how to track how much time a frame took to render, or what frame you are on. I was under the impression that this wasn't necessary if you use RAF instead of setInterval or setTimeout (oops!). I've seen people use the Date Object, the requestAnimationFrame Timestamp, and performance.now, though I don't understand the code yet. Which is the best choice for game development with requestAnimationFrame if my goals are to animate from spritesheets, and to make sure movement in the game is the same speed no matter how many fps any particular player is achieving? I've read that you have to multiply all speeds in the game by a time factor, but don't know how. Otherwise a slow computer that's only getting 30fps is walking through the game and shooting bullets at half speed compared to fast machines gettine around 60fps, right?
Please show me how I would implement the time/frame tracking code in a game loop, in addition to pros and cons of different methods of accomplishing this.
At risk of sounding like I want a tutorial, please ignore the following part from the original question
It would also be nice to see how you would use that code to animate something like walking or flapping wings from a spritesheet, and how to multiply movements speeds by a time factor so everyone gets the same game experience.
requestAnimationFrame
takes a callback. That callback is passed the time in milliseconds since the page started. So you can use that time subtract it from the time if the previous requestAnimationFrame callback to figure out your frame rate and to use for a "deltaTime" to mutiply other values by like velocity.
Typically you move things based on deltaTime. If your deltaTime is in seconds then it's easy to make anything based on delta-per-second. For example to move 10 units per second each frame you do something like
const unitsPerSecond = 10;
x = x + unitsPerSecond * deltaTimeInSeconds
As for frame count you just keep your own counter
const ctx = document.querySelector('canvas').getContext('2d');
let x = 0;
let y = 0;
const speed = 120; // 120 units per second
let frameNumber = 0;
let previousTime = 0;
function render(currentTime) {
// keep track of frames
++frameNumber;
// convert time to seconds
currentTime *= 0.001;
// compute how much time passed since the last frame
const deltaTime = currentTime - previousTime;
// remember the current time for next frame
previousTime = currentTime;
// move some object frame rate independently
x += speed * deltaTime;
y += speed * deltaTime;
// keep x and y on screen
x = x % ctx.canvas.width;
y = y % ctx.canvas.height;
// clear the canvas
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// draw something
ctx.fillStyle = (frameNumber & 0x1) ? 'red' : 'blue'; // change color based on frame
ctx.fillRect(x - 5, y - 5, 11, 11);
// draw something else based on time
ctx.fillStyle = 'green';
ctx.fillRect(
145 + Math.cos(currentTime) * 50,
75 + Math.sin(currentTime) * 50,
10, 10);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<canvas></canvas>