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

Creating a Dynamic Tile Sheet at Runtime

In Chapter 4, we briefly examined two principles we can use to help eliminate the need to precreate rotations of objects in tile sheets. Creating these types of tile sheets can be cumbersome and use up valuable time that’s better spent elsewhere in the project.

The idea will be to take a single image of a game object (e.g., the first tile in the medium rock tile sheet), create a “dynamic tile sheet” at runtime, and store it in an array rather than using the prerendered image rotation tiles.

To accomplish this, we need to make use of a second canvas, as well as the getImageData() and putImageData() Canvas functions. If you recall from Chapter 4, getImageData() will throw a security error if the HTML page using it is not on a web server.

Currently, only the Safari browser will not throw this error if the file is used on a local filesystem. For this reason, we have separated this functionality from the Geo Blaster Extended game and will simply demonstrate how it could be used instead of replacing all the tile sheets in the game with this type of prerendering.

We will start by creating two <canvas> elements on our HTML page:

<body>
<div>
<canvas id="canvas" width="256" height="256" style="position: absolute; top: 
50px; left: 50px;">
 Your browser does not support HTML5 Canvas.
</canvas>

<canvas id="canvas2" width="32" height="32"  style="position: absolute; top: 
 256px; left: 50px;">
 Your browser does not support HTML5 Canvas.
</canvas>
</div>
</body>

The first <canvas>, named canvas, will represent our hypothetical game screen, which will be used to display the precached dynamic tile sheet animation.

The second <canvas>, named canvas2, will be used as a drawing surface to create the dynamic tile frames for our tile sheet.

We will need to separate context instances in the JavaScript, one for each <canvas>:

var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");
var theCanvas2 = document.getElementById("canvas2");
var context2= theCanvas2.getContext("2d");

We will use the mediumrocks.png file (Figure 9-9) from the Geo Blaster Extended game as our source for the dynamic tile sheet. Don’t let this confuse you. We are not going to use all five tiles on this tile sheet—only the first tile.

The mediumrocks.png tile sheet

Figure 9-9. The mediumrocks.png tile sheet

In Geo Blaster Extended, we used all five tiles to create a simulated rotation animation. Here, we will only use the first tile. We will draw this first tile and rotate it on theCanvas2 by 10 degrees, and then copy the current imageData pixels from this canvas to an array of imageData instances, called rotationImageArray.

We will then repeat this process by rotating theCanvas2 by 10 more degrees and in a loop until we have 36 individual frames of imageData representing the rotation animation for our medium rock in an array:

var rotationImageArray = [];
var animationFrame = 0;
var tileSheet = new Image();
tileSheet.addEventListener('load', eventSheetLoaded , false);
tileSheet.src = "mediumrocks.png";

The rotationImageArray variable will hold the generated imageData instances, which we will create by using a rotation transformation on theCanvas2.

The animationFrame is used when redisplaying the rotation animation frames in rotationImageArray back to the first theCanvas to demo the animation.

When the tileSheet is loaded, the eventSheetLoaded() function is called, which in turn calls the startup() function. The startup() function will use a loop to create the 36 frames of animation:

function startUp(){

   for (var ctr=0;ctr<360;ctr+=10){
     context2.fillStyle = "#ffffff";
     context2.fillRect(0,0,32,32);
     context2.save();
     context2.setTransform(1,0,0,1,0,0)
     var angleInRadians = ctr * Math.PI / 180;
     context2.translate(16, 16);
     context2.rotate(angleInRadians);
     context2.drawImage(tileSheet, 0, 0,32,32,-16,-16,32,32);
     context2.restore();
     var imagedata = context2.getImageData(0, 0, 32, 32)
     rotationImageArray.push(imagedata);
   }
   setInterval(drawScreen, 100 );
}

This loop first clears theCanvas2 with a white color, and then saves it to the stack. We then translate to the center of our object and rotate the canvas by the current ctr value (an increment of 10). Next, we draw the first tile from mediumrocks.png and save the result into a new local imageData instance using the getImageData() function.

Note

This is the place where the security error will be thrown if the domain of the image and the domain of the HTML file are not the same. On a local machine (not running on a local web server, but from the filesystem), this error will be thrown on all browsers but Safari (currently).

Finally, the new imageData is pushed into the rotationImageArray. When the loop is complete, we set up an interval to run and call the drawScreen() function every 100 milliseconds.

To display the animation on the first canvas, we use this timer loop interval and call putImageData() to draw each frame in succession, creating the simulation of animation. As with the tile sheet, we didn’t have to use 36 frames of animation, we could use just five. Naturally, the animation is much smoother with more frames. But this process shows how easy it is to create simple transformation animations “on the fly” rather than precreating them in image files:

function drawScreen() {

      //context.fillStyle = "#ffffff";
      //context.fillRect(50,50,32,32);
      context.putImageData(rotationImageArray[animationFrame],50,50);
      animationFrame++;
      if (animationFrame ==rotationImageArray.length){
         animationFrame=0;
      }
}

Example 9-2 shows the entire code.

Example 9-2. A dynamic tile sheet example

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CH9EX2: Canvas Copy</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded() {
   canvasApp();
}

function canvasSupport () {
    return Modernizr.canvas;
}

function canvasApp(){

   if (!canvasSupport()) {
          return;     }else{
      var theCanvas = document.getElementById("canvas");
      var context = theCanvas.getContext("2d");

      var theCanvas2 = document.getElementById("canvas2");
      var context2= theCanvas2.getContext("2d");
   }
   var rotationImageArray = []
   var tileSheet = new Image();
   var animationFrame = 0;
   tileSheet.addEventListener('load', eventSheetLoaded , false);
   tileSheet.src = "mediumrocks.png";
   function eventSheetLoaded() {
      startUp();
   }

   function startUp(){
      //context.drawImage(tileSheet, 0, 0);
      //context2.drawImage(theCanvas, 0, 0,32,32,0,0,32,32);

      for (var ctr=0;ctr<360;ctr+=10){
         context2.fillStyle="#ffffff";
         context2.fillRect(0,0,32,32);

         context2.save();
         context2.setTransform(1,0,0,1,0,0)
         var angleInRadians = ctr * Math.PI / 180;
         context2.translate(16, 16)
         context2.rotate(angleInRadians);
         context2.drawImage(tileSheet, 0, 0,32,32,-16,-16,32,32);
         context2.restore();

         var imagedata = context2.getImageData(0, 0, 32, 32);

         rotationImageArray.push(imagedata);
      }
      setInterval(drawScreen, 100 );
   }

   function drawScreen() {
      //context.fillStyle="#ffffff";
      //context.fillRect(50,50,32,32);
      context.putImageData(rotationImageArray[animationFrame],50,50);
      animationFrame++;
      if (animationFrame ==rotationImageArray.length){
         animationFrame = 0;
      }
   }

}

</script>
</head>
<body>
<div>
<canvas id="canvas" width="256" height="256" style="position: absolute; top: 
 50px; left: 50px;">
 Your browser does not support the HTML 5 Canvas.
</canvas>

<canvas id="canvas2" width="32" height="32" style="position: absolute; top: 
 256px; left: 50px;">
 Your browser does not support HTML5 Canvas.
</canvas>

</div>
</body>
</html>

In the rest of the chapter, we will look at creating a simple tile-based game using some of the techniques first discussed in Chapter 4.

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