You are previewing HTML5 Canvas.

HTML5 Canvas

Cover of HTML5 Canvas by Steve Fulton... Published by O'Reilly Media, Inc.
  1. HTML5 Canvas
    1. SPECIAL OFFER: Upgrade this ebook with O’Reilly
    2. A Note Regarding Supplemental Files
    3. Preface
      1. Running the Examples in the Book
      2. What You Need to Know
      3. How This Book Is Organized
      4. Conventions Used in This Book
      5. Using Code Examples
      6. We’d Like to Hear from You
      7. Safari® Books Online
      8. Acknowledgments
    4. 1. Introduction to HTML5 Canvas
      1. The Basic HTML Page
      2. Basic HTML We Will Use in This Book
      3. The Document Object Model (DOM) and Canvas
      4. JavaScript and Canvas
      5. HTML5 Canvas “Hello World!”
      6. Debugging with Console.log
      7. The 2D Context and the Current State
      8. The HTML5 Canvas Object
      9. Another Example: Guess The Letter
      10. What’s Next
    5. 2. Drawing on the Canvas
      1. The Basic File Setup for This Chapter
      2. The Basic Rectangle Shape
      3. The Canvas State
      4. Using Paths to Create Lines
      5. Advanced Path Methods
      6. Compositing on the Canvas
      7. Simple Canvas Transformations
      8. Filling Objects with Colors and Gradients
      9. Filling Shapes with Patterns
      10. Creating Shadows on Canvas Shapes
      11. What’s Next
    6. 3. The HTML5 Canvas Text API
      1. Displaying Basic Text
      2. Setting the Text Font
      3. Text and the Canvas Context
      4. Text with Gradients and Patterns
      5. Width, Height, Scale, and toDataURL() Revisited
      6. Final Version of Text Arranger
      7. What’s Next
    7. 4. Images on the Canvas
      1. The Basic File Setup for This Chapter
      2. Image Basics
      3. Simple Cell-Based Sprite Animation
      4. Advanced Cell-Based Animation
      5. Applying Rotation Transformations to an Image
      6. Creating a Grid of Tiles
      7. Zooming and Panning an Image
      8. Pixel Manipulation
      9. Copying from One Canvas to Another
      10. What’s Next
    8. 5. Math, Physics, and Animation
      1. Moving in a Straight Line
      2. Bouncing Off Walls
      3. Curve and Circular Movement
      4. Simple Gravity, Elasticity, and Friction
      5. Easing
      6. What’s Next?
    9. 6. Mixing HTML5 Video and Canvas
      1. HTML5 Video Support
      2. Converting Video Formats
      3. Basic HTML5 Video Implementation
      4. Preloading Video in JavaScript
      5. Video and the Canvas
      6. Video on the Canvas Examples
      7. Animation Revisited: Moving Videos
      8. What’s Next?
    10. 7. Working with Audio
      1. The Basic <audio> Tag
      2. Audio Formats
      3. Audio Tag Properties, Functions, and Events
      4. Playing a Sound with No Audio Tag
      5. Creating a Canvas Audio Player
      6. Case Study in Audio: Space Raiders Game
      7. What’s Next
    11. 8. Canvas Game Essentials
      1. Why Games in HTML5?
      2. Our Basic Game HTML5 File
      3. Our Game’s Design
      4. Game Graphics: Drawing with Paths
      5. Animating on the Canvas
      6. Applying Transformations to Game Graphics
      7. Game Graphic Transformations
      8. Game Object Physics and Animation
      9. A Basic Game Framework
      10. Putting It All Together
      11. The player Object
      12. Geo Blaster Game Algorithms
      13. The Geo Blaster Basic Full Source
      14. Rock Object Prototype
      15. What’s Next
    12. 9. Combining Bitmaps and Sound
      1. Geo Blaster Extended
      2. Creating a Dynamic Tile Sheet at Runtime
      3. A Simple Tile-Based Game
      4. What’s Next
    13. 10. Mobilizing Games with PhoneGap
      1. Going Mobile!
      2. Creating the iOS Application with PhoneGap
      3. Beyond the Canvas
      4. What’s Next
    14. 11. Further Explorations
      1. 3D with WebGL
      2. Multiplayer Applications with ElectroServer 5
      3. Conclusion
    15. Index
    16. About the Authors
    17. Colophon
    18. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

Advanced Cell-Based Animation

In the previous example, we simply flipped back and forth between two tiles on our tile sheet. Next, we are going to create a method that uses a tile sheet to play through a series of images. First, let’s look at the new tile sheet, created by using tiles from SpriteLib. Figure 4-7 shows the example sprite sheet, tanks_sheet.png; we will refer back to this figure throughout the chapter.

Example tile sheet

Figure 4-7. Example tile sheet

As you can see, it contains a number of 32×32 tiles that can be used in a game. We will not create an entire game in this chapter, but we will examine how to use these tiles to create a game screen. In Chapter 9, we will create a simple maze-chase game using some of these tiles.

Examining the Tile Sheet

The tile sheet is formatted into a series of tiles starting at the top left. As with a two-dimensional array, the numbering starts at 0—we call this 0 relative. Moving from left to right and down, each tile will be referenced by a single number index (as opposed to a multidimensional index). The gray square in the top left is tile 0, while the tank at the end of the first row (the rightmost tank) is tile 7. Moving down to the next row, the first tank on the far left of the second row is tile 8, and so on until the final tile on row 3 (the fourth row down when we start numbering at 0) is tile 31. We have four rows with eight columns each, making 32 tiles with indexes numbered 0 to 31.

Creating an Animation Array

Next, we are going to create an array to hold the tiles for the animation. There are two tanks on the tile sheet: one is green and one is blue. Tiles 1‒8 are a series that—when played in succession—will make it appear as though the green tank’s tracks are moving.

Note

Remember, the tile sheet starts at tile 0, but we want start with the first tank image at tile number 1.

We will store the tile ids we want to play for the tank in an array:

var animationFrames = [1,2,3,4,5,6,7,8];

We will use a counter to keep track of the current index of this array:

var frameIndex = 0;

Choosing the Tile to Display

We will use the frameIndex of the animationFrames array to calculate the 32×32 source rectangle from our tile sheet that we will copy to the canvas. First, we need to find the x and y locations of the top-left corner for the tile we want to copy. To do this, we will create local variables in our drawScreen() function on each iteration (frame) to calculate the position on the tile sheet. The sourceX variable will contain the top-left corner x position, and the sourceY variable will contain the top-left corner y position.

Here is pseudocode for the sourceX calculation:

sourceX = integer(current_frame_index modulo 
the_number_columns_in_the_tilesheet) * tile_width

The modulo (%) operator gives us the remainder of the division calculation. The actual code we will use for this calculation looks like this:

var sourceX = Math.floor(animationFrames[frameIndex] % 8) *32;

The calculation for the sourceY value is similar, except we divide rather than use the modulo operation:

sourceY = integer(current_frame_index divided by 
the_number_columns_in_the_tilesheet) *tile_height

Here is the actual code we will use for this calculation:

var sourceY = Math.floor(animationFrames[frameIndex] / 8) *32;

Looping Through the Tiles

We will update the frameIndex value on each frame tick. When frameIndex becomes greater than 7, we will set it back to 0:

frameIndex++;
     if (frameIndex == animationFrames.length) {
     frameIndex = 0;
     }

The animationFrames.length value is 8. When the frameIndex is equal to 8, we must set it back to 0 to start reading the array values over again, which creates an infinite animation loop.

Drawing the Tile

We will use drawImage() to place the new tile on the screen on each iteration:

context.drawImage(tileSheet, sourceX, sourceY,32,32,50,50,32,32);

Here, we are passing the calculated sourceX and sourceY values into the drawImage() function. We then pass in the width (32), the height (32), and the location (50,50) to draw the image on the canvas. Example 4-5 shows the full code.

Example 4-5. Advanced sprite animation

var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);

tileSheet.src = "tanks_sheet.png";

var animationFrames = [1,2,3,4,5,6,7,8];
var frameIndex = 0;

function eventShipLoaded() {
  startUp();
}

function drawScreen() {

  //draw a background so we can see the Canvas edges
  context.fillStyle = "#aaaaaa";
  context.fillRect(0,0,500,500);

  var sourceX = Math.floor(animationFrames[frameIndex] % 8) *32;
  var sourceY = Math.floor(animationFrames[frameIndex] / 8) *32;

  context.drawImage(tileSheet, sourceX, sourceY,32,32,50,50,32,32);

  frameIndex++;
  if (frameIndex ==animationFrames.length) {
     frameIndex=0;
  }

}

function startUp(){

  setInterval(drawScreen, 100 );
}

When we run the example, we will see the eight tile cell frames for the tank run in order and then repeat—the only problem is that the tank isn’t going anywhere. Let’s solve that little dilemma next and drive the tank up the screen.

Moving the Image Across the Canvas

Now that we have the tank tracks animating, let’s “move” the tank. By animating the tank tracks and applying a simple movement vector to the tank’s position, we can achieve the simulation of animated movement.

To do this, we first need to create variables to hold the current x and y positions of the tank. These represent the top-left corner where the tile from our sheet will be drawn to the canvas. In the previous examples, this number was set at 50 for each, so let’s use that value here as well:

var x = 50;
var y = 50;

We also need a movement vector value for each axis. These are commonly known as deltaX (dx) and deltaY (dy). They represent the “delta” or “change” in the x or y axis position on each iteration. Our tank is currently facing in the “up” position, so we will use -1 for the dy and 0 for the dx:

var dx = 0;
var dy = -1;

The result is that on each frame tick, our tank will move one pixel up on the y-axis and zero pixels on the x-axis.

Inside drawScreen() (which is called on each frame tick), we will add the dx and dy values to the x and y values, and then apply them to the drawImage() function:

y = y+dy;
x = x+dx;
context.drawImage(tileSheet, sourceX, sourceY,32,32,x,y,32,32);

Rather than use the hardcoded 50,50 for the location of the drawImage() call on the canvas, we have replaced it with the current x,y position. Let’s examine the entire code in Example 4-6.

Example 4-6. Sprite animation and movement

var tileSheet = new Image();
tileSheet.addEventListener('load', eventShipLoaded , false);
tileSheet.src = "tanks_sheet.png";

var animationFrames = [1,2,3,4,5,6,7,8];
var frameIndex = 0;
var dx = 0;
var dy = -1;
var x = 50;
var y = 50;

function eventShipLoaded() {
  startUp();
}

function drawScreen() {

   y = y+dy;
   x = x+dx;

  //draw a background so we can see the Canvas edges
  context.fillStyle = "#aaaaaa";
  context.fillRect(0,0,500,500);

  var sourceX = Math.floor(animationFrames[frameIndex] % 8) *32;
  var sourceY = Math.floor(animationFrames[frameIndex] / 8) *32;

  context.drawImage(tileSheet, sourceX, sourceY,32,32,x,y,32,32);

  frameIndex++;
  if (frameIndex==animationFrames.length) {
     frameIndex=0;
  }

}

function startUp(){

  setInterval(drawScreen, 100 );
}

By running this example, we see the tank move slowly up the canvas while its tracks play through the eight separate tiles of animation.

Our tile sheet only has images of the tank facing in the up position. If we want to have the tank move in other directions, we can do one of two things. The first option is to create more tiles on the tile sheet to represent the left, right, and down positions. However, this method requires much more work and creates a larger source image for the tile sheet. We are going to solve this problem in another way, which we will examine next.

The best content for your career. Discover unlimited learning on demand for around $1/day.