We are going to develop a game - not all at once, let's divide the whole job into a series of smaller tasks. The first step is to create a foundation or basic structure.
Let's start by building the skeleton of a small game framework, based on the Black Box Driven Development in JavaScript methodology. In other words: a game framework skeleton is a simple object-based model that uses encapsulation to expose only useful methods and properties.
We will evolve this framework throughout the lessons in this course, and cut it in different files once it becomes too large to fit within one single file.
Here is the starting point:
var GF = function(){
var mainLoop = function(time){
//Main function, called each frame
requestAnimationFrame(mainLoop);
};
var start = function(){
requestAnimationFrame(mainLoop);
};
// Our GameFramework returns a public API visible from outside its scope
// Here we only expose the start method, under the "start" property name.
return {
start: start
};
};
With this skeleton, it's very easy to create a new game instance:
var game = new GF();
// Launch the game, start the animation loop, etc.
game.start();
Try this online example at JSBin, with a new mainloop: (check the JavaScript and output tabs). This page should display a different random number every 1/60 second. We don't have a real game yet, but we're improving our game engine :-)
Source code extract:
var mainLoop = function(time){
// main function, called each frame
document.body.innerHTML = Math.random();
// call the animation loop every 1/60th of second
requestAnimationFrame(mainLoop);
};
Every game needs to have a function which measures the actual frame rate achieved by the code.
The principle is simple:
Count the time elapsed by adding deltas in the mainloop.
If the sum of the deltas is greater or equal to 1000, then 1s has elapsed since we started counting.
If at the same time, we count the number of frames that have been drawn, then we have the frame rate - measured in number of frames per second. Remember, it should be around 60 fps!
Quick glossary: the word delta is the name of a Greek letter (uppercase Δ, lowercase δ or 𝛿). The upper-case version is used in mathematics as an abbreviation for measuring the change in some object, over time - in our case, how quickly the mainloop is running. This dictates the maximum speed at which the game display will be updated. This maximum speed could be referred to as the rate of change. We call what is displayed at a single point-in-time, a frame. Thus the rate of change can be measured in frames per second (fps). Accordingly, our game's delta determines the achievable frame rate - the shorter the delta (measured in mS), the faster the possible rate of change (in fps).
Here is a screenshot of an example and the code we added to our game engine, for measuring FPS (try it online at JSBin):
Source code extract:
// vars for counting frames/s, used by the measureFPS function
var frameCount = 0;
var lastTime;
var fpsContainer;
var fps;
var measureFPS = function(newTime){
// test for the very first invocation
if(lastTime === undefined) {
lastTime = newTime;
return;
}
// calculate the delta between last & current frame
var diffTime = newTime - lastTime;
if (diffTime >= 1000) {
fps = frameCount;
frameCount = 0;
lastTime = newTime;
}
// and display it in an element we appended to the
// document in the start() function
fpsContainer.innerHTML = 'FPS: ' + fps;
frameCount++;
};
Now we can call the measureFPS function from inside the animation loop, passing it the current time, given by the high resolution timer that comes with the requestAnimationFrame API:
var mainLoop = function(time){
// compute FPS, called each frame, uses the high resolution time parameter
// given by the browser that implements the requestAnimationFrame API
measureFPS(time);
// call the animation loop every 1/60th of second
requestAnimationFrame(mainLoop);
};
And the <div> element used to display FPS on the screen is created in this example by the start() function:
var start = function(){
// adds a div for displaying the fps value
fpsContainer = document.createElement('div');
document.body.appendChild(fpsContainer);
requestAnimationFrame(mainLoop);
};
Hack: achieving more than 60 fPS? It's possible but to be avoided except in hackers' circles!
We also know methods of implementing loops in JavaScript which achieve even more than 60fps (this is the limit using requestAnimationFrame).
My favorite hack uses the onerror callback on an <img> element like this:
function mainloop(){
var img = new Image;
img.onerror = mainloop;
img.src = 'data:image/png,' + Math.random();
}
What we are doing here, is creating a new image on each frame and providing invalid data as a source of the image. The image cannot be displayed properly, so the browser calls the onerror event handler that is the mainloop function itself, and so on.
Funny right? Please try this and check the number of FPS displayed with this JSBin example.
Source code extract of this example:
var mainLoop = function(){
// main function, called each frame
measureFPS(+(new Date()));
// call the animation loop every LOTS of seconds using previous hack method
var img = new Image();
img.onerror = mainLoop;
img.src = 'data:image/png,' + Math.random();