Game development for the Web

In the following series of blog posts, I will be mixing my passion for game development with the Web, in an attempt to stay true to my professional development roots. The focus of this series will be 2D game development, specifically with the CanvasRenderingContext2D API for the canvas HTML 5 element.


2D? What about 3D?

Math plays a big part in Game Development or anything related to graphics. With that in mind, it makes sense to start representing stuff in a two dimensional space, since, conceptually math is simpler and less overwhelming. After we build some confidence in our math and physics in a 2D space, making the jump to the 3D space will be intuitive and less daunting.

In addition, something to keep in mind is the fact that regardless of our perspective of spaces in games or graphics simulations our screen is a two dimensional surface. Therefore, 2D feels just right as a starting point.


Assumptions

The content of this series will assume that you have some basic JavaScript/HTML/CSS knowledge and understand at a basic level some lineal algebra concepts. In occasions, I will try to add some references to some of the math related concepts I use, but I won’t go very deep into math theory.

So, without further adieu,let’s jump right at it!


The Canvas Element

The <canvas> element is, basically, a drawing region to display programmable graphics in a Web Page.

Apple introduced the element in 2004 as part of their browser layout engine, WebKit (Safari). Other layout engines like Gecko (Firefox) and Presto (Opera) later adopted the element. It is now part of the WhatWG Web applications 1.0 specification, also known as HTML5; the Web Hypertext Application Technology Working Group (WHATWG) standardized it on new proposed specifications for next generation web technologies.

Relevant stuff

  • The canvas element was initially conceived as a self-closing tag, just like the <img> tag. This was later changed in order to have a fall back mechanism for unsupported layout engines. Therefore, in order to declare a canvas element you must have a starting tag <canvas> and a closing tag </canvas>.
  • By default, the <canvas> element has no border and no content. Borders for the area must be specified explicitly.
  • As a good practice you should specify an id attribute (to be referenced in script code), and a width and height attribute to define the size of the canvas.
  • In case the size is not specified explicitly the default size of the canvas is 300 x 150 pixels.
  • All drawing on the canvas must be done from JavaScript code.
  • It is encouraged to avoid the usage of the <canvas> element when a more suitable element is available for our needs.
  • When no styling rules are applied to the <canvas> it will initially be fully transparent.

Even though the element is supported by all major browsers I suggest that you go here and confirm that the rendering engine of the browser of your choice does support the canvas element and its context APIs.


Basic usage

Let us define a canvas.

<canvas id="mycanvas" width="300" height="150"></canvas>

The <canvas> element has only two attributes: width and height. These are both optional and can be set using DOM properties. By default, the canvas will initially be 300 pixels wide and 150 pixels high. The element size can be changed arbitrarily using CSS.

Fallback content

HTML5 is relatively a new standard. Moreover, even though, the <canvas> element is widely supported across the current generation of browsers, older browsers (in particular, versions of Internet Explorer earlier than version 9) do not support it.

The fallback content is a feature that allows displaying alternate content to unsupported browsers. Achieving this is very straightforward; the alternate content must be placed inside of the <canvas> element. This works because the graphical operations will not be performed by the browsers layout engine but by client side code (JavaScript).

<canvas id="mycanvas" width="300" height="150">
    The canvas element is not supported by your browser.
</canvas>    

Adding borders

For simplicity purposes, we will add borders to our canvas. This way we will have some visuals on the drawing area. I am a fan of following web standards, so instead of dropping inline style rules for our HTML element, I will use CSS.

<style type="text/css">
    canvas { border: 1px solid black; }
</style>

The Rendering Context

By default, the fixed-size drawing surface created by the <canvas> element is blank. The content of this so called surface can be accessed by one (or more) rendering context. As of the moment the <canvas> element supports two rendering contexts the 2D rendering context, which is the default, and WebGL, which uses a 3D context based on OpenGL ES. We will dig deeper into rendering contexts in the following article, for the time being we will use the 2D rendering context for our following examples.

The <canvas> element has a method called getContext(), used for two purposes:

  1. Check for canvas support programmatically.
  2. Obtain the rendering context and its drawing functions. getContext()
    takes one parameter, the type of context. In our case the context type will simply be 2d (for now ;).
var canvas = document.getElementById('mycanvas');
if (canvas.getContext) {
    var ctx = canvas.getContext('2d');
    // From now on we will use our context to draw into the canvas.
}
else {
    // Fall back code goes here
}

A simple example

Let us draw a simple rectangle and color it purple.

Here’s the code:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>The canvas element</title>
    <style type="text/css">
           canvas { border: 1px solid black; }
    </style>
    <script type="text/javascript">
         function draw() {
              var canvas = document.getElementById('mycanvas');
              if (canvas.getContext) {
                  var ctx = canvas.getContext('2d');
                  ctx.fillStyle = "rgb(200,0,200)";
                  ctx.fillRect(70, 25, 150, 100); 
              }
         }
    </script>
</head>
<body onload="draw();">
    <canvas id="mycanvas" width="300" height="150">
        The canvas element is not supported by your browser.
    </canvas>
</body>
</html>

Here’s the result:

Note: Notice how in the code there’s a callback function that triggers when the body element finalizes its load process.

More Rectangles

Obviously, it is possible to draw more than a shape at the same time, as well as text. Here is a more complex example:

To achieve this, I just added extra calls to the fillRect function and used a function for the font rendering. The code is really straight forward.

<script type="text/javascript">
         function draw() {
              var canvas = document.getElementById('mycanvas');
              if (canvas.getContext) {
                  var ctx = canvas.getContext('2d');
                  ctx.fillStyle = "rgb(246,83,20)";
                  ctx.fillRect (10, 10, 55, 50);
                  ctx.fillStyle = "rgb(124,187,0)";
                  ctx.fillRect (70, 10, 55, 50);
                  ctx.fillStyle = "rgb(0,161,241)";
                  ctx.fillRect (10, 70, 55, 50);
                  ctx.fillStyle = "rgb(255,187,0)";
                  ctx.fillRect (70, 70, 55, 50);
                  ctx.font = "30px Arial Black";
                  ctx.fillStyle = "Black";
                  ctx.fillText("Microsoft", 140, 75);
              }
         }
</script>

The rendering context API’s will be discussed with depth on the next article. There, we will go deeper into the functions available on the context "object" and what is their purpose.

For now you have a test bed to play with. Have fun, explore.


Conclusion

Web pages are available in any device with a Web Browser; this is a very strong reason to consider porting games for “web play”. Even though the maturity of the APIs for these purposes is rather low, it is worth considering this option due to the medium’s mass consumption and availability. The Internet is everywhere and for some, the only way to use it, is through a Web Browser.

Moreover, some breakthrough achievements have been made in order to run C++ native code in a browser. Both Mozillaand Google have made their moves, one with asm.js and the other with Native Client. This kind oftechnology is what made possible to run the Unreal Engine 3 in Firefox.

Finally, some major companies are taking some measurements to enforce HTML5 features into their Web capable ecosystems, making the <canvas> element available almost everywhere.


Dedication

The following series of articles is dedicated to Amhed A. Herrera. A special friend, whose passion and interest for technology have served as inspiration for my professional endeavors.