HTML5 Canvas [49]
Example 4-3. Using all of the drawImage() parameters
var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);
tileSheet.src = "ships.png";
function eventShipLoaded() {
drawScreen();
}
function drawScreen() {
//draw a background so we can see the Canvas edges
context.fillStyle = "#aaaaaa";
context.fillRect(0,0,500,500);
context.drawImage(tileSheet, 32, 0,32,32,50,50,64,64);
}
As you can see, we have changed the name of our Image instance to tileSheet because it represents more than just the source for the single ship image.
Figure 4-6. Using all of the drawImage() parameters
Now, let’s use this same concept to simulate animation using the tiles on our tile sheet.
Simple Cell-Based Sprite Animation
With a tile sheet of images, it is relatively simple to create what seems like cell-based or flip-book animation. This technique involves rapidly swapping images over time to simulate animation. The term flip-book comes from the age-old technique of drawing individual cells of animation in the top-left corner pages of a book. When the pages are rapidly flipped through, the changes are viewed over time, appearing to create a cartoon. Cell-based animation refers to a similar professional technique. Individual same-sized cells (or pages) of images are drawn to simulate animation. When played back rapidly with special devices in front of a camera, animated cartoons are recorded.
We can use the drawImage() function and the first two tiles on our tile sheet to do the same thing.
Creating an Animation Frame Counter
We can simulate the ship’s exhaust firing by rapidly flipping between the first two tiles (or cells) on our tile sheet. To do this, we set up a counter variable, which is how we track the tile we want to paint to the canvas. We will use 0 for the first cell and 1 for the second cell.
We will create a simple integer to count which frame we are displaying on our tile sheet:
var counter = 0;
Inside drawScreen(), we will increment this value by 1 on each frame. Since we only have two frames, we will need to set it back to 0 when it is greater than 1:
counter++;
if (counter >1) {
counter = 0;
}
Or use the nice shortcut:
counter ^= 1;
Creating a Timer Loop
As it currently stands, our code will only be called a single time. Let’s create a simple timer loop that will call the drawScreen() function 10 times a second, or once every 100 milliseconds. A timer loop that is set to run at a certain frame rate is sometimes referred to as a frame tick or timer tick. Each tick is simply a single iteration of the timer running all the code we put into our drawScreen() function. We will also need a function that starts the timer loop and initiates the tick once the image has preloaded properly. We’ll name this function startUp():
function eventShipLoaded() {
startUp();
}
function startUp(){
setInterval(drawScreen, 100 );
}
Changing the Tile to Display
To change the tile to display, we can multiply the counter variable by 32 (the tile width). Since we only have a single row of tiles, we don’t have to change the y value:
context.drawImage(tileSheet, 32*counter, 0,32,32,50,50,64,64);
NOTE
We will examine how to use a tile sheet consisting of multiple rows and columns in the next section, Advanced Cell-Based Animation.
Example 4-3 used this same line of code to draw our image. In Example 4-4, it will be placed on the canvas at 50,50 and scaled to 64×64 pixels. Let’s look at the entire set of code.
Example 4-4. A simple sprite animation
var counter = 0;
var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);
tileSheet.src = "ships.png";
function eventShipLoaded() {
startUp();
}
function drawScreen() {
//draw a background so we can see the Canvas edges
context.fillStyle = "#aaaaaa";
context.fillRect(0,0,500,500);
context.drawImage(tileSheet, 32*counter, 0,32,32,50,50,64,64);