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

Another Example: Guess The Letter

Now we will take a quick look at a more involved example of a “Hello World!”-type application, the game “Guess The Letter.” We’ve included this example to illustrate how much more Canvas programming is done in JavaScript than in the Canvas API.

In this game, shown in Figure 1-4, the player’s job is to guess the letter of the alphabet the computer has chosen randomly. The game keeps track of how many guesses the player has made, lists the letters he has already guessed, and tells the player whether he needs to guess higher (toward Z) or lower (toward A).

HTML5 Canvas “Guess The Letter” game

Figure 1-4. HTML5 Canvas “Guess The Letter” game

How the Game Works

This game is set up with the same basic structure as “Hello World!” canvasApp() is the main function, and all other functions are defined as local to canvasApp(). We use a drawScreen() function to render text on the canvas. However, there are some other functions included as well, which are described next.

The “Guess The Letter” Game Variables

Here is a rundown of the variables we will use in the game. They are all defined and initialized in canvasApp(), so they have scope to the encapsulated functions that we define locally.

guesses

This variable holds the number of times the player has pressed a letter. The lower the number, the better he has done in the game.

message

The content of this variable is displayed to give the user instructions on how to play.

letters

This array holds one of each letter of the alphabet. We will use this array to both randomly choose a secret letter for the game, and to figure out the relative position of the letter in the alphabet.

today

This variable holds the current date. It is displayed on the screen but has no other purpose.

letterToGuess

This variable holds the current game’s secret letter that needs to be guessed.

higherOrLower

This variable holds the text “Higher” or “Lower” depending on where the last guessed letter is in relation to the secret letter. If the secret letter is closer to “a,” we give the “Lower” instruction. If the letter is closer to “z,” we give the “Higher” instruction.

lettersGuessed

This array holds the current set of letters the player has guessed already. We will print this list on the screen to help the player remember what letters he has already chosen.

gameOver

This variable is set to false until the player wins. We will use this to know when to put the “You Win” message on the screen, and to keep the player from guessing after he has won.

Here is the code:

   var guesses = 0;
   var message = "Guess The Letter From a (lower) to z (higher)";
   var letters = [
               "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
               "p","q","r","s","t","u","v","w","x","y","z"
               ];
   var today = new Date();
   var letterToGuess = "";
   var higherOrLower = "";
   var lettersGuessed;
   var gameOver = false;

The initGame() Function

The initGame() function sets up the game for the player. The two most important blocks of code are as follows. This code finds a random letter from the letters array and stores it in the letterToGuess variable:

var letterIndex = Math.floor(Math.random() * letters.length);
letterToGuess = letters[letterIndex];

This code adds an event listener to the window object of the DOM to listen for the keyboard keyup event. When a key is pressed, the eventKeyPressed event handler is called to test the letter pressed:

window.addEventListener("keyup",eventKeyPressed,true);

Here is the full code for the function:

function initGame() {
   var letterIndex = Math.floor(Math.random() * letters.length);
   letterToGuess = letters[letterIndex];
   guesses = 0;
   lettersGuessed = [];
   gameOver = false;
   window.addEventListener("keyup",eventKeyPressed,true);
   drawScreen();
}

The eventKeyPressed() Function

This function, called when the player presses a key, contains most of the action in this game. Every event handler function in JavaScript is passed an event object that has information about the event that has taken place. We use the e argument to hold that object.

The first test we make is to see whether the gameOver variable is false. If so, we continue to test the key that was pressed by the player; the next two lines of code are used for that purpose. The first line of code gets the key-press value from the event, and converts it to an alphabetic letter that we can test with the letter stored in letterToGuess:

var letterPressed = String.fromCharCode(e.keyCode);

The next line of code converts the letter to lowercase so that we can test uppercase letters if the player unintentionally has Caps Lock on:

letterPressed = letterPressed.toLowerCase();

Next, we increase the guesses count to display, and use the Array.push() method to add the letter to the lettersGuessed array:

guesses++;
lettersGuessed.push(letterPressed);

Now it is time to test the current game state to give feedback to the player. First, we test to see whether letterPressed is equal to letterToGuess. If so, the player has won the game:

if (letterPressed == letterToGuess) {
   gameOver = true;

If the player has not won, we need to get the index of letterToGuess and the index of letterPressed in the letters array. We are going to use these values to figure out whether we should display “Higher,” “Lower,” or “That is not a letter.” To do this, we use the indexOf() array method to get the relative index of each letter. Because we alphabetized the letters in the array, it is very easy to test which message to display:

} else {
   letterIndex = letters.indexOf(letterToGuess);
   guessIndex = letters.indexOf(letterPressed);

Now we make the test. First, if guessIndex is less than zero, it means that the call to indexOf() returned -1, and the key press was not a letter. We then display an error message:

if (guessIndex < 0) {
   higherOrLower = "That is not a letter";

The rest of the tests are simple. If guessIndex is greater than letterIndex, we set the higherOrLower text to “Lower.” Conversely, if guessIndex is less than letterIndex, we set the higherOrLower test to “Higher”:

   } else if (guessIndex > letterIndex) {
      higherOrLower = "Lower";
   } else {
      higherOrLower = "Higher";
   }

}

Finally, we call drawScreen() to paint the screen:

drawScreen();

Here is the full code for the function:

function eventKeyPressed(e) {
      if (!gameOver) {
         var letterPressed = String.fromCharCode(e.keyCode);
         letterPressed = letterPressed.toLowerCase();
         guesses++;
         lettersGuessed.push(letterPressed);

         if (letterPressed == letterToGuess) {
            gameOver = true;
         } else {

            letterIndex = letters.indexOf(letterToGuess);
            guessIndex = letters.indexOf(letterPressed);
            Debugger.log(guessIndex);
            if (guessIndex < 0) {
               higherOrLower = "That is not a letter";
            } else if (guessIndex > letterIndex) {
               higherOrLower = "Lower";
            } else {
               higherOrLower = "Higher";
            }

         }
         drawScreen();
        }
   }

The drawScreen() Function

Now we get to drawScreen(). The good news is that we have seen almost all of this before—there are only a few differences from “Hello World!” For example, we paint multiple variables on the screen using the Canvas Text API. We only set context.textBaseline = 'top'; once for all the text we are going to display. Also, we change the color using context.fillStyle, and the font with context.font.

The most interesting thing we display here is the content of the lettersGuessed array. On the canvas, the array is printed as a set of comma-separated values, like this:

Letters Guessed: p,h,a,d

To print this value, all we do is use the toString() method of the lettersGuessed array, which prints out the values of an array as—you guessed it—comma-separated values:

context.fillText  ("Letters Guessed: " + lettersGuessed.toString(), 10, 260);

We also test the gameOver variable. If it is true, we put You Got It! on the screen in giant 40px text so the user knows he has won.

Here is the full code for the function:

function drawScreen() {
      //Background
      context.fillStyle = "#ffffaa";
      context.fillRect(0, 0, 500, 300);
      //Box
      context.strokeStyle = "#000000";
      context.strokeRect(5,  5, 490, 290);

      context.textBaseline = "top";
      //Date
      context.fillStyle = "#000000";
      context.font = "10px _sans";
      context.fillText  (today, 150 ,10);
      //Message
      context.fillStyle = "#FF0000";
      context.font = "14px _sans";
      context.fillText  (message, 125, 30);
     //Guesses
      context.fillStyle = "#109910";
      context.font = "16px _sans";
      context.fillText  ('Guesses: ' + guesses, 215, 50);
      //Higher Or Lower
      context.fillStyle = "#000000";
      context.font = "16px _sans";
      context.fillText  ("Higher Or Lower: " + higherOrLower, 150,125);
      //Letters Guessed
      context.fillStyle = "#FF0000";
      context.font = "16px _sans";
      context.fillText  ("Letters Guessed: " + lettersGuessed.toString(), 10, 260);
      if (gameOver) {
         context.fillStyle = "#FF0000";
         context.font = "40px _sans";
         context.fillText  ("You Got It!", 150, 180);
      }
   }

Exporting Canvas to an Image

Earlier, we briefly discussed the toDataUrL() property of the Canvas object. We are going to use that property to let the user create an image of the game screen at any time. This acts almost like a screen-capture utility for games made on Canvas.

We need to create a button in the HTML page that the user can press to get the screen capture. We will add this button to <form> and give it the id createImageData:

<form>
<input type="button" id="createImageData" value="Export Canvas Image">
</form>

In the init() function, we retrieve a reference to that form element by using the getElementById() method of the document object. We then set an event handler for the button “click” event as the function createImageDataPressed():

var formElement = document.getElementById("createImageData");
formElement.addEventListener('click', createImageDataPressed, false);

In canvasApp(), we define the createImageDataPressed() function as an event handler. This function calls window.open(), passing the return value of the Canvas.toDataUrl() method as the source for the window. Since this data forms a valid PNG, the image is displayed in the new window:

function createImageDataPressed(e) {

   window.open(theCanvas.toDataURL(),"canvasImage","left=0,top=0,width=" + 
   theCanvas.width + ",height=" + theCanvas.height +",toolbar=0,resizable=0");
   }

Note

We will discuss this process in depth in Chapter 3.

The Final Game Code

Example 1-4 shows the full code for the Guess The Letter game.

Example 1-4. Guess The Letter game

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CH1EX4: Guesss The Letter Game</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">

window.addEventListener('load', eventWindowLoaded, false);

var Debugger = function () { };
Debugger.log = function (message) {
   try {
      console.log(message);
   } catch (exception) {
      return;
   }
}

function eventWindowLoaded() {

   canvasApp();
}

function canvasSupport () {
     return Modernizr.canvas;
}

function eventWindowLoaded() {

   canvasApp();
}

function canvasApp() {
   var guesses = 0;
   var message = "Guess The Letter From a (lower) to z (higher)";
   var letters = [
               "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
               "p","q","r","s","t","u","v","w","x","y","z"
               ];
   var today = new Date();
   var letterToGuess = "";
   var higherOrLower = "";
   var lettersGuessed;
   var gameOver = false;

   if (!canvasSupport()) {
          return;
        }

   var theCanvas = document.getElementById("canvasOne");
   var context = theCanvas.getContext("2d");

   initGame();

   function initGame() {
      var letterIndex = Math.floor(Math.random() * letters.length);
      letterToGuess = letters[letterIndex];
      guesses = 0;
      lettersGuessed = [];
      gameOver = false;
      window.addEventListener("keyup",eventKeyPressed,true);
      var formElement = document.getElementById("createImageData");
      formElement.addEventListener('click', createImageDataPressed, false);
      drawScreen();
   }

   function eventKeyPressed(e) {
      if (!gameOver) {
         var letterPressed = String.fromCharCode(e.keyCode);
         letterPressed = letterPressed.toLowerCase();
         guesses++;
         lettersGuessed.push(letterPressed);

         if (letterPressed == letterToGuess) {
            gameOver = true;
         } else {

            letterIndex = letters.indexOf(letterToGuess);
            guessIndex = letters.indexOf(letterPressed);
            Debugger.log(guessIndex);
            if (guessIndex < 0) {
               higherOrLower = "That is not a letter";
            } else if (guessIndex > letterIndex) {
               higherOrLower = "Lower";
            } else {
               higherOrLower = "Higher";
            }

         }
         drawScreen();
        }
   }

   function drawScreen() {
      //Background
      context.fillStyle = "#ffffaa";
      context.fillRect(0, 0, 500, 300);
      //Box
      context.strokeStyle = "#000000";
      context.strokeRect(5,  5, 490, 290);
      context.textBaseline = "top";
      //Date
      context.fillStyle = "#000000";
      context.font = "10px _sans";
      context.fillText  (today, 150 ,10);
      //Message
      context.fillStyle = "#FF0000";
      context.font = "14px _sans";
      context.fillText  (message, 125, 30);
      //Guesses
      context.fillStyle = "#109910";
      context.font = "16px _sans";
      context.fillText  ('Guesses: ' + guesses, 215, 50);
      //Higher Or Lower
      context.fillStyle = "#000000";
      context.font = "16px _sans";
      context.fillText  ("Higher Or Lower: " + higherOrLower, 150,125);
      //Letters Guessed
      context.fillStyle = "#FF0000";
      context.font = "16px _sans";
      context.fillText  ("Letters Guessed: " + lettersGuessed.toString(), 10, 260);
      if (gameOver) {
         context.fillStyle = "#FF0000";
         context.font = "40px _sans";
         context.fillText  ("You Got It!", 150, 180);
      }
   }

   function createImageDataPressed(e) {

      window.open(theCanvas.toDataURL(),"canvasImage","left=0,top=0,width=" + 
      theCanvas.width + ",height=" + theCanvas.height +",toolbar=0,resizable=0"); 
   }

}

</script>
</head>
<body>
<div style="position: absolute; top: 50px; left: 50px;">
<canvas id="canvasOne" width="500" height="300">
 Your browser does not support HTML5 Canvas.
</canvas>
<form>
<input type="button" id="createImageData" value="Export Canvas Image">
</form>
</div>
</body>
</html>

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