Labels

Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

2010-11-22

Project "HoT MetaL JaZz" - Part 4

In previous editions of this series, we went over some of the basic functions of the HTML5 Canvas element, including plotting paths, drawing images, and manipulating drawing parameters. Now, we will go over a very simple game framework written in JavaScript that uses HTML5 Canvas elements to display visual output.

The framework I created demonstrates a lot of tricks, as well as basic functions common in games. Features include:

  • Frame-based sprite animation
  • Sprite scaling, rotation, and transparency
  • Keyboard input management
  • Ability to scale to browser size while maintaining original aspect ratio

Furthermore, I've added functions such as a "wait until loaded" feature that ensures the game doesn't start until all related assets have been fully loaded. It currently has no progress indicator (just a static "Loading..." message), so you may want to add one of those if you decide to use any of the framework for your own games.

Now, let's go over some of the highlights of the framework for HoT MetaL JaZz, beginning with the front-end: "hotmetal.html".

hotmetal.html

When hotmetal.html loads, it runs the script function "startGame()", which is embedded right into the HTML page. Within the "startGame()" function, we create a new "GameCore" object, the constructor for which takes several parameters. Let's go over those quickly:

The first argument is the primary canvas - what the player will see. The next two arguments specify a maximum width and height for the primary canvas - this is mainly to ensure that the canvas doesn't get so large that performance begins to degrade too far. The next argument assigns the backbuffer canvas. The next two arguments are the width and height of the backbuffer - this value does not change; instead, this is the "natural" size of the backbuffer. The final argument is the desired frames-per-second timing at which to run the game.

Also, the body element of the page is given a function to run when the browser is resize: "game.resize()". We will go over this function as we go through the "gamecore.js" file.

gamecore.js

The constructor for the GameCore object is fairly straightforward - we assign values, and run a couple of functions.

We begin by setting some variables to keep track of our canvases and their sizes. Then we call "this.resize()" to size the canvas for a "best fit" within the browser's viewing area. We also assign a GameInputManager to the GameCore. As for the logic of GameCore, we use a demonstration logic script called "HotMetalLogic" - this contains all the code specific to how the actual game functions.

After this is done, we call "this.init()". Here, we set up the contexts for our canvases and save them. We clear both contexts, and draw a simple loading screen. At the end of the method, we call "this.loadData()".

The GameCore.loadData() method simply offloads the data-loading tasks to the logic part of the game. It will then run "this.assertReady()", which will cause the game to wait until the logic is fully loaded and ready.

The GameCore.assertReady() function will call the logic script's "images.loadImages()" function. The logic.images object is an instance of GameImageManager, and its "loadImages()" function will (re)assign the URL to each image loaded by the logic script. The function sets the GameImageManager.ready property to "true" if all images have finished loading. GameCore.assertReady will start running the logic (this.logic.run()) if the GameImageManager.ready property is set to true; otherwise, it will wait 1000 milliseconds (1 second) and run the check again. This will continue until the GameImageManager lets us know it is ready.

GameCore.resize() is an interesting function. It will find the "best fit" for the game's primary canvas within the browser window, all while maintaining the original aspect ratio of the canvas. First, we get the width-wise aspect ratio, and the "reverse", height-wise aspect ratio. We query the browser's "inner" window width and height, and then run a few checks to make sure the resize fits properly based on the aspect ratios. When all is said and done, you can resize your browser any way you want and have the primary canvas fit inside - with no portion of the primary canvas stretching past the window boundaries.

gameinputmanager.js

The GameInputManager object is quite simple - it sets up some functions for the document to run whenever a key is pressed or released. It also will release all input whenever the document loses keyboard focus via the document.onblur event. To determine whether a particular key is pressed, just check the GameInputManager.keyControls[keyCode] variable - it will be "true" if the key with the specified keyCode is pressed; otherwise, it will return "false" or "undefined".

gameimagemanager.js

This file contains two object constructors. The first is GameImageManager; the second is TaggedImage.

GameImageManager sets up an array of TaggedImage objects, which stores each image inserted into the manager along with a string ID for each. To begin adding images to the GameImageManager, use the function GameImageManager.addImage(filename, tag). The filename is the URL of the image to load; tag is a string identifier used to store and access the image. For example, you can use the code:

myImageManager.addImage("images/my-image.png", "sprite");

The file will be associated with the string "sprite". Thus, to retrieve the image from the GameImageManager instance, you would use:

var img = myImageManager.getImage("sprite");

Finally, the "loadImages()" function will check the "complete" status of each image loaded into the GameImageManager. If it finds that all images have a "complete" status, it will set the GameImageManager's "ready" flag to true.

gamesprite.js

This file contains three object constructors: GameSprite; GameSpriteProperty; and GameSpriteAnimation.

GameSprite.update(elapsedTime) will begin its task by checking whether the sprite is animated - if so, it calls the update(elapsedTime) function of the animation sequence. It continues by ensuring the sprite speed hasn't exceeded the designated maximum, and then updating the sprite's position by factoring its velocity in.

GameSprite.draw(context) takes the backbuffer context as its sole argument. The function sets the appropriate globalAlpha, translation, rotation, and scale of the context to match those of the sprite, and draws the sprite to the context. If the sprite is animated, it will draw the current frame; otherwise, it will draw the image parameter used in the GameSprite's constructor.

GameSprite.setProperty(name, value) and GameSprite.getProperty(name) allow the sprite to have an arbitrary set of properties. For example, you can add a "Hit Points" property to the sprite, without having to write a new sprite class. The GameSpriteProperty class simply holds a name for the property and its value.

The GameSpriteAnimation(image, width, height, delay) constructor takes an image, divides it into "cells" of the given width and height, and delays frame transitions by "delay" milliseconds. The update function simply checks whether it needs to transition to the next frame, by comparing the current frame time with the delay of the transition. If it's time to transition, the frame index is incremented. If the frame index has gone past the last frame index, the animation "loops" back to the first frame.

hotmetallogic.js

The HotMetalLogic class is the "glue" that ties all the previous classes together. It uses a GameImageManager to load and assign images, it interacts with sprites using the GameInputManager (use the arrow keys to move around), and handles the AI for different sprites.

When playing the game, you need to avoid the fireballs shooting out of the flares on the four corners of the play area. As the flares shoot out fireballs, they gradually weaken until they disappear. When all flares and fireballs have been extinguished, the game ends. You lose points each time a fireball hits you.

Of course, this is just a modest demo of what is possible. There are better ways to set up a framework for a game - this is just to get your creative juices flowing.

Some suggestions for improvements:

Make the GameCore capable of holding an array of logic scripts, and switch between them. For example, run a logic script for a main menu, and another logic script for the game in action.

Sort sprite drawing order by Y: The farther from the bottom of the canvas a sprite is, the sooner it should be drawn, so that sprites appear behind or in front of their appropriate peers.

2010-11-20

Project "HoT MetaL JaZz" - Part 3

In our last episode, we demonstrated how to draw images to our canvas. Now we will dig deeper into the HTML5 Canvas drawing methods by looking at the path-drawing methods, and learn how to scale images.

Drawing straight lines is easy. We start with [context].beginPath(), plot our paths, apply a stroke and/or fill, then call [context].closePath() to finish up. For example, to draw a simple triangle, you could use code like the following. Open gamecore.js, and replace your current draw() method with the following:

GameCore.prototype.draw = function() {
  this.bufferContext.fillStyle = "rgb(0, 0, 0)";
  this.bufferContext.fillRect(0,
                              0,
                              this.bufferCanvasWidth,
                              this.bufferCanvasHeight);

  this.bufferContext.beginPath();
  this.bufferContext.moveTo(100, 100);
  this.bufferContext.lineTo(200, 100);
  this.bufferContext.lineTo(100, 200);
  this.bufferContext.lineTo(100, 100);

  this.bufferContext.fillStyle = "rgb(127, 127, 127)";
  this.bufferContext.fill();
  this.bufferContext.strokeStyle = "rgb(255, 255, 255)";
  this.bufferContext.stroke();
  this.bufferContext.closePath();

  this.primaryContext.clearRect(0,
                                0,
                                this.primaryCanvasWidth,
                                this.primaryCanvasHeight);

  this.primaryContext.drawImage(this.bufferCanvas,
                                0,
                                0,
                                this.primaryCanvasWidth,
                                this.primaryCanvasHeight);

  setTimeout("game.draw()", this.frameSpeed);
}

The first difference is in the first line - we set the fillStyle to black explicitly, to ensure that we always get a black fill since we'll be changing the context's fillStyle in this example.

Then comes the call, [context].beginPath(). This simple call is used to indicate that we are starting to plot a path. After that, we use [context].moveTo() to move our "cursor" to the indicated X/Y coordinate, without plotting any paths. Three lines calling [context].lineTo() plot the path for a triangular shape. We set our fillStyle to gray, call [context].fill(), and this fills our triangle shape with the color gray. We then set our strokeStyle to white, and call [context].stroke() to draw the lines between points. A call to [context].closePath() lets the context know that this path is complete.

Of course, we can draw curves fairly easily, too. We can draw a triangle that looks "pinched", with each side bending inward toward the center of the shape. To do this, we replace our [context].lineTo() calls with the following:

this.bufferContext.quadraticCurveTo(125, 125, 200, 100);
this.bufferContext.quadraticCurveTo(125, 125, 100, 200);
this.bufferContext.quadraticCurveTo(125, 125, 100, 100);

Look out, those are some sharp points on that triangle!

Quadratic curves are simple: The first two arguments define the coordinate to which the middle of the line will be "pulled", and the second pair of arguments define that start and end points of the path.

Of course, bezier curves are no problem for us, either. Change the code for drawing your triangle to the following:

this.bufferContext.bezierCurveTo(250,  50,  50,  50, 200, 100);
this.bufferContext.bezierCurveTo(125, 275, 275, 125, 100, 200);
this.bufferContext.bezierCurveTo( 50,  50,  50, 250, 100, 100);

The main difference between quadratic curves and bezier curves are that quadratic curves have one "pull" point, while bezier curves have two. Once you master these curves, you can make some very intriquing designs.

As a side note, you can assign an image as a fillStyle for a path. Doing so is quite simple, involving a call to [context].createPattern(). The function takes two arguments: The first is the image you want to use, and the second is a string that determines the pattern of repetition. Valid values for this argument are "repeat", "repeat-x", "repeat-y", and "no-repeat".

There are some other path-plotting functions: arcTo(float x1, float y1, float x2, float y2, float radius); and arc(float x, float y, float radius, float startAngle, float endAngle, boolean anticlockwise). Experiment with these to learn how to create things like pie charts, etc. Oh, and don't forget the rect(float x, float y, float width, float height) function!

Before we move on to scaling our game canvas, let's touch on one last detail about paths - there is a function, [context].isPointInPath(float x, float y) that will tell you whether the specified point is contained within the path you are currently plotting. It returns true if the point is contained within the path, false if otherwise. Use this for collision detection against complex shapes.

Now that you have a good understanding of paths, we can move on to something a little different. Let's say you want to scale your game canvas to fit the size of the browser window. Furthermore, you want to scale the image with the canvas, so that players with bigger screens see the same amount of view area, just stretched to fit.

If that's something you're interested in, you're in luck - it's pretty easy to do this, so let's get to work on that. Firstly, go back to your skeleton HTML file. We will generally leave this alone for the most part, but there are times where it will need a slight tweak. In the <body> tag, add the following attribute shown in boldface:

<body onload="startGame();" onresize="game.resize();">

This makes the browser call our GameCore's .resize() function, which is:

GameCore.prototype.resize = function() {
  var winInnerWidth = window.innerWidth;
  var winInnerHeight = window.innerHeight;

  this.primaryCanvas.width = winInnerWidth;
  this.primaryCanvas.height = winInnerHeight;

  this.primaryCanvasWidth = this.primaryCanvas.width;
  this.primaryCanvasHeight = this.primaryCanvas.height;
}

This function simply resizes the primary canvas, without touching the buffer canvas. Thus, we can keep the same amount of data on-screen independent of the size of the game's primary canvas. The buffer just "stretches" to the size of the primary canvas.

Remember that this function is called whenever the window is resized, so you may want to add an extra call to the GameCore.resize() method at the end of your GameCore.init() method, just before the call to GameCore.loadData().

Here's an exercise: Add a minimum and maximum size to which the primary canvas will scale. For extra credit, have the primary canvas retain its original aspect ratio. Hint: The aspect ratio would be the canvas width divided by the canvas height.

That about does it for laying the groundwork. In the next section, we'll begin to take what we've learned to help us build a simple framework for our game. In the meantime, there's a really nice "HTML5 Canvas Cheat Sheet" you should definitely check out.

Until next time, have fun!

Project "HoT MetaL JaZz" - Part 2

In the previous installment of this series, we added code to our project that showed us how to draw text to our canvas and manipulate it a bit. Now, we will learn more about the drawing functions within the HTML5 canvas element, including image-drawing capabilities.

Let us begin this exercise by modifying our base template for HTML5 games. Everything will be similar to the skeleton presented in Part 0 of our series, except that we will have a separate file for our game scripts.

The new skeleton code is as follows:


<head>
  <title>HoT MetaL JaZz - Rev.2</title>

  <script src="gamecore.js"></script>

  <script>
    var game;
    function startGame() {
      game = new GameCore(document.getElementById("gamecanvas"),
                          document.getElementById("backbuffer"),
                          30);
    }
  </script>

  <style type="text/css">
    body { margin: 0 auto; text-align: center; }
  </style>
</head>

<body onload="startGame();">
  <canvas id="gamecanvas" width="300" height="300"></canvas>
  <canvas id="backbuffer" width="300" height="300" style="display:none;"></canvas>
</body>


Save the code into a plain text file, with a file name ending with ".html". This simple HTML file will allow us to write as much game code as we want without touching the "front-end" HTML file, with the exception of adding new script file definition in the <head> area.

This skeleton code works with the script file "gamecore.js". To add this file, create a new, empty text file to the same folder as your HTML file, and name it "gamecore.js". We will use this new file to store the "core" scripts for our game.

We will define a GameCore class in gamecore.js. Its constructor will simply take a primary canvas, a buffer canvas, and a "desired" framerate as arguments. It will then store references to the canvas elements and do a few other basic setup tasks. Then, it will automatically call a function to initialize the game. Take the following code:


function GameCore(primaryCanvas, bufferCanvas, desiredFramerate) {
  this.primaryCanvas = primaryCanvas;
  this.primaryContext;
  this.bufferCanvas = bufferCanvas;
  this.bufferContext;

  //store the width and height of each canvas to reduce
  //the overhead involved in individual queries to canvas elements
  this.primaryCanvasWidth = primaryCanvas.width;
  this.primaryCanvasHeight = primaryCanvas.height;
  this.bufferCanvasWidth = bufferCanvas.width;
  this.bufferCanvasHeight = bufferCanvas.height;

  //To get a framerate of N frames per second, divide 1000 by N
  this.frameSpeed = 1000 / desiredFramerate;

  this.images = new Array();

  this.init();
}


As you can see, there isn't much going on here that we haven't covered. After we reference the Canvas objects and make variables to store the context for each canvas, we store the width and height of each. We have a "frameSpeed" variable, which sets a timeout between refreshes - timeouts are measured in milliseconds (1/1000th of a second), so we get our actual frames-per-second delay by dividing 1000 by our desiredFramerate. The desiredFramerate should be a reasonable value - no more than 60, but in practice, about 30. Then we create a new array to store the images we will use for this example.

At the end of the GameCore constructor, we make a call to the init() function of our GameCore object. For now, our GameCore.init() function looks like this:


GameCore.prototype.init = function() {
  if (this.primaryCanvas.getContext) {
    this.primaryContext = this.primaryCanvas.getContext("2d");
    this.primaryContext.clearRect(0,
                                  0,
                                  this.primaryCanvasWidth,
                                  this.primaryCanvasHeight);
  }

  if (this.bufferCanvas.getContext) {
    this.bufferContext = this.bufferCanvas.getContext("2d");
    this.bufferContext.clearRect(0,
                                 0,
                                 this.bufferCanvasWidth,
                                 this.bufferCanvasHeight);
  }

  this.loadData();
}


We simply set up the references to the context of our primary and buffer canvases here. We use the variables in which we stored each canvas's width and height, to avoid any unnecessary overhead from calling the canvas properties directly. Once this has been done, the GameCore.loadData() function is called. This function is defined as such:


GameCore.prototype.loadData = function() {
  var testImage = new Image();
  testImage.src = "sprite.png";
  this.images.push(testImage);

  this.draw();
}


For the purpose of our demonstration, we define the loadData() function to create a new Image object, set it to point to an image named "sprite.png", and then add the image to our GameCore.images array. Once that is done, we are ready to start the game. Our GameCore.draw() function looks like this:


GameCore.prototype.draw = function() {
  this.bufferContext.fillRect(0,
                              0,
                              this.bufferCanvasWidth,
                              this.bufferCanvasHeight);


  for (currImage = 0; currImage < this.images.length; currImage++) {
    if (this.images[currImage].complete) {
      this.bufferContext.drawImage(this.images[currImage],
                                   this.bufferCanvasWidth / 2,
                                   this.bufferCanvasHeight / 2);
    }
  }


  this.primaryContext.clearRect(0,
                                0,
                                this.primaryCanvasWidth,
                                this.primaryCanvasHeight);

  this.primaryContext.drawImage(this.bufferCanvas,
                                0,
                                0,
                                this.primaryCanvasWidth,
                                this.primaryCanvasHeight);

  setTimeout("game.draw()", this.frameSpeed);
}


This function begins by filling the backbuffer with a solid black rectangle (remember, the default fillStyle is black). We then iterate through all the images in our demo (currently, just one) to make sure they have completely loaded. If the image is finished loading, we draw the image to the center of our backbuffer using the context.drawImage(...) function. Here, we put our image as the first argument, and the X/Y coordinate at which to place the image.

Once we have iterated through all our images, we clear the primary context, and then "flip" our backbuffer onto it using the drawImage() function. This time, we call the drawImage() function with five arguments: The image, the X/Y coordinates, and the width/height of the image to draw. We then set a timeout for redrawing the canvas.

To test this out, we will need our "sprite.png" image file in our game directory. If you don't feel like making your own, here is the one I used in writing this article:



When you open the page, you should see your sprite image appear near the center of the canvas. It is off-center a bit, because the image is drawn starting from the top-left. In other words, the top-left of the image is in the center of the canvas!

Later, we will give suggestions for easily drawing images from their center, rather than their top-left corners. For now, though, let's go into detail on the drawImage() function.

The drawImage() function template looks like this:

drawImage(Object image, float dx, float dy, float dw, float dh)

Where image can be an HTML image, HTML canvas, or HTML video element. dx/dy indicate the origin of drawing (i.e. the top-left corner of where to draw). dw/dh are optional arguments, and indicate how much of the image to draw. In other words, if our image is 300x300, and only want to draw half of that image, we would call drawImage() as such:

[context].drawImage(myImage, 0, 0, 150, 150);

If dw/dh are not defined, the entire image will be drawn.

There is also an alternate way to use drawImage() that allows you to draw a specific portion of an image to a context. We will go over this method later in this series.

The next time we dive into Project "HoT MetaL JaZz", we will go over some of the advanced path functions built into the HTML5 canvas element, and also learn how to dynamically scale our game to fit the player's browser window. It will be an extremely exciting ride, so don't miss it!

2010-11-19

Project "HoT MetaL JaZz" - Part 1

In the introduction to this series, we went over how to get started programming games with HTML5 and JavaScript. If you haven't seen that article yet, I suggest you do so before proceeding further. The code in the previous article will be the basis upon which the remaining articles rely.

So, we should now have a blank HTML5 canvas element on our Web page. It seems a shame to let it just sit there, sight-unseen, so let's learn how to use JavaScript to interact with and manipulate the canvas element.

Go to the script portion of your source (i.e. the lines between the <script> and </script> tags). Insert the following lines of code above the declaration for the startGame() function:

var primaryCanvas;
var primaryContext;
var bufferCanvas;
var bufferContext;
var animation;

We will use the first four variables to reference our drawing surfaces - the "primary" variables show our graphics, while the "buffer" variables store data that is put together in preparation for drawing. The HTML5 Canvas element has a Context property, which is what we will primarily deal with when writing games. The fifth variable will simply be used to animate the context later.

Now, after the variable definitions, go into the body of the function "startGame()", and enter the following code:

primaryCanvas = document.getElementById("gamecanvas");
if (primaryCanvas.getContext) {
  primaryContext = primaryCanvas.getContext("2d");
  primaryContext.clearRect(0, 0, 300, 300);
}

bufferCanvas = document.getElementById("backbuffer");
if (bufferCanvas.getContext) {
  bufferContext = bufferCanvas.getContext("2d");
  bufferContext.clearRect(0, 0, 300, 300);
}

So, what did we just do here? First, we set our primaryCanvas variable to a reference to the actual HTML5 canvas element in our page, "gamecanvas". Then we did a check to make sure the primaryCanvas variable has a context. If so, we get the "2d" context, and set it into our primaryContext variable. We finish up by clearing a rectangular area of the context, starting from 0/0 (top-left) to 300/300 (the size of the canvas). We repeat the same process for the backbuffer.

The "2d" context of a canvas gives us access to all 2D functions and parameters that apply to drawing. In the future, when WebGL (and possibly other technologies) become more prevalent, there may be additional contexts. For now, though, we want the "2d" context.

Notice that rather than call the width and height properties of the primaryCanvas and bufferCanvas, I put literal values (i.e. 300) for the width and height of the clearRect function. Calling canvas elements directly is expensive, in that it has a fair bit of overhead involved. Thus, I simply use literal values instead.

Now that we have our drawing contexts, we're ready to make things happen.

After the code for grabbing our contexts, enter the following new function:

function draw() {
  bufferContext.fillStyle = "rgb(0, 0, 0)";
  bufferContext.fillRect(0, 0, 300, 300);
  bufferContext.fillStyle = "rgb(255, 255, 255)";
  bufferContext.font = "24px sans-serif";
  bufferContext.textAlign = "center";
  bufferContext.fillText("Oh, HI!", 150, 150);

  primaryContext.drawImage(bufferCanvas, 0, 0, 300, 300);
}

Finally, save your html file, and open it in your Web browser. If all went well, you should be greeted by a friendly message surrounded by a black background.

Here's a review of the above code:

The [context].fillStyle property tells the context which color - in RGB format - to use for fills. This value will persist until it is given a new value later on in the code. As for [context].fillRect, that simply takes the fillStyle (which defaults to RGB 0,0,0 - black) and uses that color to draw a filled rectangle, given an X/Y origin, and a width/height.

After drawing the black background in our context, we set the fillStyle to white (RGB 255,255,255), and use [context].font to adjust the font. The font can be any CSS-compliant font style. Then, we set [context].textAlign to center. This makes the text centered on the point used to draw it. Finally, we draw our text with [context].fillText, giving it the string, X-coordinate, and Y-coordinate to start from.

The context of an HTML5 canvas has a plethora of drawing functions beyond the code we just plugged in. The context has full support for translation, rotation, scaling, and has a transform method. To add a little spice to our project, let's make the text spin around like a propeller!

Go back to your code, and enter the following line at the end of your startGame() function:

animation = setInterval("draw()", 50);

And then add the following into your draw() function, just before the primaryContext.drawImage(...) call:

bufferContext.translate(150, 150);
bufferContext.rotate(0.1);
bufferContext.translate(-150, -150);

Save your code, and open it in your browser. Voila - the text spins around like a propeller, centered on the canvas.

Of course, you may be wondering about a few things. First, the [context].translate() calls. Why do we need those? The answer is simple - because the center point of rotations is always oriented to the top-left origin of what you are rotating. We change this by translating the context - and thus the center point - to the center of the screen (X=150, Y=150). Then we apply our rotation, and clean up our translation "mess" by subtracting the translation.

You may also find it odd that the letters "jitter" a bit. This is perfectly normal - text drawing along an angle isn't always precise. Of course, there are ways around this problem (such as drawing the text to the backbuffer first, and then rotating the backbuffer itself before copying it to the primary context).

We've only scratched the surface of what the HTML5 canvas is capable of. In the next article, we will cover drawing lines and shapes, as well as drawing images to the context. See you there!

Project "HoT MetaL JaZz" - Part 0

Welcome to the introduction to a series of articles that aim to teach you how to write games in HTML5 and JavaScript. HTML5 is bringing great new things to rich Internet applications, so we will learn how to make games - comparable to anything Adobe Flash is capable of - using this simple, open technology.

Before you get started, you might want to make things easier by making sure you have the following:

Up-to-date Firefox Web browser - Version 3.6+ or higher recommended.
Firebug for Firefox - This add-on, available in the Firefox add-on repository, is a great help for debugging JavaScript.
A text editor - Any one will do, just use the text editor you prefer. Make sure to save all JavaScript and HTML source files to plain text, though!

Once you have all that rounded up, you're ready to rock. So, let's lay a little groundwork for our project, which we'll call "HoT MetaL JaZz". Don't worry, the name is irrelevant to the actual project, so just push those images of whatever weirdness you came up with after hearing that title right out of your head.

First thing's first - we need a source file to put all our wonderful code in. It's simple - just create a new text file, and name it "htmljz.html" - or whatever else you like, just so long as the file name ends with ".html". Now use your text editor to open the new file.

Now we are presented with a blank canvas on which to write our code. The first thing our file needs is a doctype declaration. This is simple enough - in the old days, our doctype declarations were long, messy, and hard to remember. But now, all we need is...

<!DOCTYPE html>

And that's pretty much it! This little doctype declaration is all we need under the HTML5 specification. Now, we can get started on the HTML portion of our game.

Now, let's use this template for the HTML portion of our game:

<head>
  <title>HoTMetaL JaZz</title>

  <script>
    function startGame() {
      //Our game's startup code will go here
    }
  </script>

  <style type="text/css">
    body { margin: 0 auto; width: 300px; }
  </style>
</head>

<body onload="startGame();">
  <canvas id="gamecanvas" width="300" height="300"></canvas>
  <canvas id="backbuffer" width="300" height="300" style="display:none;"></canvas>
</body>

That is our basic skeleton page for HoT MetaL JaZz. The "title" tags set the caption of the browser's title bar - whatever you put there is what will be displayed on your browser's title bar. Our game script code will live between the "script" tags. The style tag denotes the width of the page and adds a simple CSS trick (a la the margin setting) that will allow us to center our game on the browser's viewing area. In the body, the "canvas" elements are what we'll be using for drawing our game's graphics - the canvas with the id "backbuffer" is set to not display, as we'll be using that as a back buffer to make our scene drawing a little smoother.

When you save the file, open it in your browser and behold! Nothing. Well, what were you expecting, fireworks? We still need to add more to get anything going on, but just to ensure your code is working, try hovering your mouse cursor over the top-center of your browser's viewing pane, and right-click. If you have the options "View Image" and "Save Image As..." show up in your context menu, then all is well.

Now that we have our skeleton page, we can start learning how to write awesome games in HTML5 and JavaScript. Our next article will cover the basics of using HTML5 canvas functionality. Happy gaming!