cs255 ยป




Now, the first stop in your trip to Awesometown starts with the backbone of all old-school graphics engines. How to write a 2D tile-based rendering engine. Now, in HTML5, this starts with a single DOM element called the Canvas Object.

What is canvas?

So, the first thing we need to know is, what is canvas? Canvas is a new HTML5 element which exposes APIs allowing you to draw graphs, images, and text to portions of the page. A canvas only has two attributes specific to it, width and height, which specify what size this drawing surface is on your page. Since canvas is effectively a large memory blob of pixel data, or bitmap for you Yankees, it closely resembles the memory layouts that game developers have been using for years to generate 2D games.

Your first canvas

Now, without further ado, let's create our first canvas. What I'd like you to do is grab the canvas element that we've already specified in our HTML page and set its width and height attributes appropriately.
Given Code:

Your first canvas - Quiz

setup = function() {
// Grab the body element using document.getElementById,
// assume the body element has an id of 'body'.
// Create a canvas element using document.createElement,
// then set the width and height properties to 1200 and
// 720, respectively.
// Finally, append the canvas element to the body.
var body = // YOUR CODE HERE
var canvas = // YOUR CODE HERE

canvas.width = // YOUR CODE HERE
canvas.height = // YOUR CODE HERE



Your first canvas - Quiz Answer

The basic HTML for grabbing the canvas object is pretty straight forward. We've seen this before. The interesting thing that we haven't yet covered is grabbing the context of the canvas. Think of the canvas object that we fetched from the DOM as a DOM element. While the context is a handle to the drawing APIs that we'll be able to use to modify the canvas visuals later. In this simple example, we set the width and height to 1200 by 720 respectively. Now, it's worth pointing out, that any time the user would resize the screen, the canvas will remain this size. For the purposes of grids, we actually use the window.innerwidth and window innerheight. sizes for our canvas, allowing it to occupy the fullscreen for the user.

Loading images

The bulk of canvas interaction that Grits uses, is through rendering images to the canvas. In order to draw an image to the canvas, we first have to load it. In order to load an image, we need to create a new image object, which in Javascript, is comprised of three steps. Number 1, is we need to declare the image object. Number 2, is we need to define its onload function. Then number 3 we need to set the image.source attribute. Its worth noting that as soon as the source property if this image is set through a value java script will kick off a load function. Because of this, we need to specify the call back function first before setting the source attribute. Otherwise the image will load the data and we won't get a call back received. Now let's take a look at this code. Here is the url of the image that we'd like you to load. What we want you to do is create a new image object, following the steps we just mentioned, and set the onload function and source properties for that image described in the code. Make sure that your onload function is assigned to this onImageLoad down here, which will actually print out some nice little message to the console log, letting you know that things have loaded properly. If you're confused about whether or not your image is loading, don't forget to check out Chrome's developer tools on the network tab, which will list whether or not the image has loaded, and how long it took to do it.

Loading Images- Quiz

setup = function() {
    var body = document.getElementById('body');
    var canvas = document.createElement('canvas');

    var context = canvas.getContext('2d');

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;


    // Create a new image with a src of "/media/js/standalone/libs/gamedev_assets/ralphyrobot.png" and onload of onImageLoad

onImageLoad = function(){
    // Use the console.log function to print a statement to the browser console.
    // This will print once the image has been downloaded.


Loading Images- Quiz Answer

Good job. Now, as we noted before, loading an image is comprised of three steps. We actually declare a new image object. Then, we specify the function to be called when the image has been loaded. And finally, we set the source of the image itself. Down here, we specified our on image load option, which simply prints out a statement to the console alerting us when this image has been loaded.

Drawing images

Now that we have a loaded image, we need to draw that image to the canvas via the canvas.draw image API. This function takes the image object itself as well as the locations on the canvas that we'd like to draw that image. As you can see, there are some other parameters that draw image takes. Don't worry about those just yet. For now you can leave those blank. By the way, if you are ever interested in finding out more about an API for html five development, make sure you check out webplatform.org. It's a nifty little space where all your questions can be answered. For our next step, why don't you go ahead and fill in the onLoad function that we defined earlier. So that rather than logging a message to the console, instead, it draws the image at pixel location 192 by 192.

Drawing images- Quiz

var canvas = null;
var context = null;
var img = null;

var onImageLoad = function(){
    // Draw an image to the canvas at position 192,192.
    // Remember that the drawImage method is attached
    // to the 2D Context, not the canvas element!

var setup = function() {
    var body = document.getElementById("body");
    canvas = document.createElement("canvas");

    context = canvas.getContext('2d');

    canvas.setAttribute('width', 500);
    canvas.setAttribute('height', 500);


    img = new Image();
    img.onload = onImageLoad;
    img.src = "/media/js/standalone/libs/gamedev_assets/ralphyrobot.png";


Drawing images- Quiz Answer

We were able to look at the documentation and see that context.drawImage allowed us to pass in the image object as well as the position on the canvas we'd like to draw, 192 by 192. Before we move on let's cover an important topic about canvas drawing, coordinate systems.

Coordinate systems

Now we draw our image at location 192 by 192. Which as you can see placed the top left corner of the image, 192 by 192 fix it up from the top left corner of the canvas, whose been conveintly placed at location zero, zero on the page. That is to say that on the canvas, the origin's coordinate system, i.e., the location of it's zero, zero. The top left hand corner, any draw functions will follow this coordinate system and place the top left hand corner of the image at the location specified by the draw image call.

Image formats

So let's take a quick moment and talk about something else that's very important to game development, what format your images are in? Now typically on the internet when you find photos or pictures of cats just floating around on random web pages, it's actually in a JPEG format. JPEG was developed some time ago by a joint efforts group from some of the industry's largest contributors. Now when I say a while ago, I actually mean back in you know, the early days of the internet back when Al Gore still rode the Moon Worm through the plains of . Another type of image format that you can use on the internet today, is actually one called PNG. Now where JPEG gives you better size comparison, PNG lacks in that department. However, PNG does give you one important feature. Transparency. JPEG itself gives you better compression formats but doesn't allow you to use transparent pixels in your seam which means the general rule of thumb is if you have an image on the internet that doesn't require it to be transparent you should probably be using JPEG. If it requires alpha you need to be using PNG. Now the cool thing about the internet is that it's always moving forward and new technologies are being developed every day to make the experience for end users better. Besides JPEG and PNG, there's a new image format coming down the pipe called WebP. WebP offers and interesting ground. First off, it has compression ratios similar if not better in some cases than JPEG but also allows you to have alpha transparency supported by PNG. Therefore we have with this new image format the ability to get good compression. And alpha transparency where we need it. Don't you love the internet?


Now we'd like you to write this flip book animation style in code. We've given you a list of image assets to use for evil devices. what you need to do is load all of these image asset and place them in the frame array. After your images are loaded, you should go through and fill out the rest of the animation function here, which will actually draw the flip book animation images to the screen as we described before. make sure that when your animation is finished you loop back to the beginning. Now before this. You need to have some logic that checks for whether or not the images are loaded, and once all of the frames have been loaded, actually does a call to set interval. Now set interval takes as input a pointer to a function you'd like to call as well as a millisecond count on how often you want it to be called. So, for instance, if I made a function and wanted it to be called once every 30 milliseconds, those would be parameters that I pass into it. Make sure that your set interval call, actually calls the animate function, once every 30 milliseconds.

Animation- Quiz

var canvas = null;
var context = null;
var assets = ['/media/js/standalone/libs/gamedev_assets/robowalk/robowalk00.png',
var frames = [];

var onImageLoad = function(){

var setup = function() {
    body = document.getElementById('body');
    canvas = document.createElement('canvas');

    context = canvas.getContext('2d');

    canvas.width = 100;
    canvas.height = 100;


    // Load each image URL from the assets array into the frames array 
    // in the correct order.
    // Afterwards, call setInterval to run at a framerate of 30 frames 
    // per second, calling the animate function each time.

var animate = function(){
    // Draw each frame in order, looping back around to the 
    // beginning of the animation once you reach the end.
    // Draw each frame at a position of (0,0) on the canvas.


Animation- Quiz Answer

Lets take a look at the solution to this its a little bit tricky. Firstly, at the top of our file we declare two new variables, frameRate and frame. Now, frameRate represents how often we'd like to actually call the animate function. Frame is a variable that we're going to use to represent what the current frame in our flip book is. Since we already have our frames array available, the next step is to actually loop through our predefined assets, and load each of the defined images into the frames array. This follows the same 3 step process we saw before. Create a new image, set its on load result, and then set its source. Once this is done we can actually call this setInterval function, which will call the animate function at the frameRate that we provided before. Now the animate function has a little bit of tricky logic inside of it. First off, we have our frame counter that we've defined. We use this to define what image out of the frames array we have to draw to the canvas, and of course, at our lovely position of 192 by 192. Once we've drawn the current frame we actually have to increment it, and that's where this little nice piece of math comes along. What we do is increment the frame counter and that modulo it by the frame's length. What will occur here is that if frame ever becomes longer than frame length, the modulo function will have it loop around back to 0 without us having to have all the other if statements involved. This is a nice little piece of math that you should put in your code. Your employer will be impressed by it. Now if you followed all the code, you should see something like this running around on the screen. If you'll notice something though, this doesn't exactly look right. You actually get each of the frames drawn over each other, creating this sort of halo effect. There's a reason for this. It's worth noting that the canvas 8doesn't actually clear itself each frame. Instead it allows you to just keep piling pixels on it as you go. In order to get rid of tha t ghosting effect, you have to put this line that we've conveniently left out of our previous function back in, and that is context.clearRect. What this will do is actually clear all of the pixels to some default value allowing us to draw back on top of it. So you won't get the previous images actually drawn on top. Top of each other. The result is a nice, nifty walking robot running around on your screen, just like it should. The result with clearRect is this nice, fancy walking robot.

Now, back in the early 90's, specialty hardware was used to get smooth graphics on early machines. Things like the NES, Genesis, and Gameboy had custom hardware that was built into the form factor that was allowed you to draw tons and tons of tiles very quickly on modern screen. Now desktop computers at the time didn't have that much power, in fact, they didn't have any of that specialty hardware at all. Modern desktops around that time running at 33 hertz were considered top of the line. Now, one day a young John Carmack made a demo called Dangerous Dave in copyright Infringement Which actually showed off a Super Mario Brothers 3 level running at full 30 frames a second, on desktop hardware. He showed that demo to a young John Romero. And that very day, ID Software was born. The same studio that went on to actually create the first person shooter genre with titles such as Wolfenstein, Doom. And Quick. Now, the trick that Carmack realized. To get the same performance from the specialty hardware on the desktop, was actually an optimization. See, these early machines weren't too good at actually copying pixels over here to over here in memory. It was actually a pretty difficult concept. Especially with the bit map colors and everything. But what they were good at was actually just copying rows of memory from different registers. So what Carmack realized was that he could use the previous frame. And somehow just use meme copies to sort of shift it, so that it looks like the scene is actually scrolling. They need to be able to only have to update the small portion of the screen that changed as your character was moving. Thus was born the concept of dirty rects. Now, this is the same concept that's been used today in tons and tons of games. See, that's the trick with game industry. Techniques like this. They never really die, they just kind of get rebranded as technology evolves over time.