Overview


Expect this Unit to last between 3 to 5 hours. To demonstrate what you should have at the end of this Unit, check out the Demo for Unit 8.

There will be a pretty rewarding Unit as you'll finally starting seeing stuff on the screen, that with very little effort can become interactive! There's a whole lot of content that we could cover, but I'm going to focus on code structure and framework, so we can quickly move onto the even more exciting unit on Sprites.

Rendering is typically a pretty heavy subject matter in games development. Rendering pipelines can be quite large, the technology often bleeding edge. Great visuals are such an important part of games so it is critical that we build our engine to support. Lucky for us this is actually one of the greatest strengths of HTML5 games, as rendering is something that's primarily handled by the browser.

In HTML5 games, we actually have a couple of choices for displaying things on the screen. We've already been using text and displaying Images directly in the DOM. One option is using SVG, which stands for Scalable Vector Graphics, and allows you to render things much like Flash. We could also use CSS transitions to make things animated and pretty. However, the best option for this class is Canvas, as using it most closely resembles development for native made games.

HTML5 Canvas

The HTML5 <canvas> element is used to draw graphics, on the fly, via scripting. Canvas has several methods for drawing paths, boxes, circles, characters, and adding images.

There is a wealth of resources on the internet that explain the history and evolution of the HTML5 canvas. This class isn't meant to make you an expert on what canvas is and on its many features, but my goal is to make you sure you're comfortable with using it as a drawing surface. We'll be drawing lines and paths and rendering images in order to display sprites. I won't go into the Canvas API in depth, but I highly recommend reading through this section of Dive Into HTML5 on Canvas called LET’S CALL IT A DRAW(ING SURFACE). It's midly lengthy, but does a good job at explaining how canvas (and pretty much any other HTML5 feature) works and preparing you for this Unit.

Canvas has a whole lot of features, but there's only two I'm going to be concerned with for this Unit:

  • clearRect() - clears the pixels in the specified rectangle.
  • drawImage() - draws an Image on the canvas

It's very likely that we would only need a single canvas to draw our sprites to. Or it's also possible that we would want more than canvas, and may not want all of them visible to the user. We might have an offscreen canvas that we draw into procedurally, and copy over to the on-screen canvas every frame. Or we could have a couple of on-screen canvas objects, either on top of each other or at different locations on the page, and will be drawing to each of them in different ways.

These kinds of choices can have an interesting impact on performance, but those decisions generally need to be made at game code time. For now we are going to do our best to support multiple canvas objects that can be configured to be on screen or not.

In this Unit we will focus on two things:


renderContext2D.js


Our canvas wrapper is going to inherit from DrawNode. This is so that when we tell the canvas to draw, any object attached to it can draw with an appropriate render order given by the zOrder property.

Anytime we create a new instance of a RenderContext2D we need it to manage a separate instance of a canvas object. The base functionality we'll need this object to have is:

I've added a list of default properties that we will use in the implementation.

API Source Code:

init()

First, because this is a derived class type, we need to call our parent class constructor through this._super(). We had a good break from OOP in the last Unit didn't we!

This class is assuming that we want to create a new canvas object, although it could easily be changed so that we support accessing on from the DOM.

We want to get the 2D rendering context from the canvas, which is what we'll actually be using to draw things to the screen. Right now "2d" is our only option, but this flexibility to take in other options is required by the HTML5 specification, in anticipation of eventual 3D canvas support.

backgroundColor and zIndex are both CSS properties that this class uses to pass along using jQuery.

You'll probably remember that creating a new HTML object doesn't actually add it to the DOM. If we are given a container property then we know this is an on-screen canvas and it needs to be inserted into the DOM. The easiest way to get a container to pass in here is through jQuery: $('#some_div_id')

Implementation Source Code:

resize()

We are supporting two features with setting the canvas size: either it is full screen taking up as much of the window as possible, or it is set to a fixed size.

Implementation Source Code:

canvasDraw()

Usually we'll want to clear the entire render context and then draw all of the sprites associated with it. Just in case we don't want to clear first, check a flag before using the Visitor pattern built into the DrawNode object to call .draw on any child objects.

Implementation Source Code:

clearCanvas()

Since we want to clear the entire canvas, this is a very simple function to implement. The canvas API gives us a function that can clear a rect within the canvas, so we only need to pass it a rect that covers the entire size of the canvas.

Implementation Source Code:


backgrounds.js


This is essentially a manager of canvas instances. The implementation will follow the same path the Asset Manager took by adding new functionality to the Engine itself. It will also follow the same behavior of storing these objects so they can be accessed under an alias.

There is another programming pattern we are using here, called the Factory pattern. The engine is now a factory for creating new instances of the RenderContext2D class. This means it also needs functions for destroying a canvas.

Along with having functions to clear and draw all created canvases, we also are going to have a function that we can register with the engine as a game loop function.

First let's take a look at the API, and then we'll dive into the implementation for each function.

We are also going to have a helper function called canvasGameLoop() that will be explained below, along with local storage for canvas objects.

API Source Code:

createCanvas()

Here is the implementation for the RenderContext2D factory function.

The code is very straightforward, although the is one bit at the end that might require a deeper look. If there currently no game loop registered, go ahead and register this helper function that makes sure all canvas objects get drawn.

It returns the canvas (which is also a DrawNode) so that the user can attach child objects to it and have them get drawn as well.

API Source Code:

getCanvas()

Easy accessor function for a given canvas. It only needs to do a safety check to warn the user in case a canvas doesn't (or no longer) exists.

API Source Code:

destroyCanvas()

Destroying a RenderContext2D is as easy as calling .destroy(), however we need to make sure we remove all references to the object.

API Source Code:

destroyAllCanvases()

Call destroy on all canvas objects we've created, and clear out both of the lists we have.

API Source Code:

clearAllCanvases()

A very simple wrapper function, to call .clearCanvas() on all created canvas objects.

API Source Code:

drawAllCanvases()

Another very simple wrapper function, that I think you can guess what it will do.

API Source Code:

canvasGameLoop()

Now here's something fun! If want an easy way to make sure all canvas objects we create get rendered, then we have this utility function to register as a game loop function with the engine.

Registering this function using the engine's setGameLoop() from Unit 3, will make sure that each frame .drawAllCanvases() gets called.

API Source Code:


Test Code


Time to pull a whole bunch of pieces together! We'll use GameObjects, the Asset Manager, and the Canvas system to draw a sprite to the screen!

We haven't gone over the API for how to actually draw an Image to a canvas (we will in the next Unit), but it's very straightforward. Once we have an object that can draw itself, we just need to attach it to our canvas and presto!

Source Code:


Homework


Part 1. Create and add the two files to your project: renderContext2D.js and backgrounds.js

Part 2. Fill out both files with the code from this Unit.

Part 3. Put it to work in your test code in main.js:


Extra Credit


This is where we really start getting room to expand on features and functionality, so I'll list off a few ideas on how you might take this section further. Reading the Canvas API should give you some ideas.