This post was originally published at Making an HTML5 Canvas Based Game: A Tutorial Using AngularJS and CreateJS

Posted by Aninash Kaza – Software Engineer @ Toptal

Game development is one of the more interesting, advanced programming techniques that constantly challenges the software development industry.

There are many programming platforms used to develop games, and there are a plethora of devices to play them on, but when it comes to playing games in a web browser, Flash-based development still leads the way.

Rewriting Flash-based games to HTML5 Canvas technology would let us play them on mobile browsers as well. And, with Apache Cordova, skilled web developers could easily wrap them into cross platform mobile game apps.

Folks at CreateJS set out to do that and more.

EaselJS, part of CreateJS’s suite, makes drawing on HTML5 Canvas simple. Imagine building custom data visualization with high performance and thousands of elements. Scalable Vector Graphic (SVG) is not the right choice, because it uses DOM elements. Browsers become overwhelmed when, at around 600 DOM elements, initial renderings, re-draws, and animation become expensive operations. With HTML5 Canvas, we can easily get around these problems; Canvas drawings are like ink on paper, no DOM elements and their associated costs.

This means that Canvas based development needs more attention when it comes to separating elements, and attaching events and behaviors to them. EaselJS comes to the rescue; we can code as if we are dealing with individual elements, letting EaselJS library handle your mouse-overs, clicks, and collisions.

SVG-based coding has one big advantage: SVG has an old specification, and there are a lot of design tools that export SVG assets for use in development, so that cooperation between designers and developers works well. Popular libraries, such as D3.JS, and newer, more powerful libraries like SnapSVG, bring much to the table.

If designer-to-developer workflow is the only reason you would use SVGs, consider extensions for Adobe Illustrator (AI) that generate code from shapes created in AI. In our context, such extensions generate EaselJS code or ProcessingJS code, both of which are HTML5 Canvas-based libraries

Bottom line, if you are starting a new project, there is no reason to use SVGs anymore!

SoundJS is part of the CreateJS suite; it provides a simple API for HTML5 Audio specification.

PreloadJS is used to preload assets such as bitmaps, sound files, and the like. It works well in combination with other CreateJS libraries.

EaselJS, SoundJS, and PreloadJS make game development super easy for any JavaScript ninja. Its API methods are familiar to anyone who used Flash-based game development.

“This is all great. But, what if we have a team of developers converting a bunch of games from Flash to HTML5? Is it possible to do that with this suite?”

The answer: “Yes, but only if all of your developers are at Jedi level!”.

If you have a team of varying skill set developers, which is often the case, it can be a little scary to use CreateJS and expect a scalable and modular code. What if we bring together CreateJS suite with AngularJS? Can we mitigate against this risk by bringing in the best and most adopted front-end JS framework?

Yes, and this HTML5 Canvas game tutorial will teach you how to create a basic game with CreateJS and AngularJS!

HTML5 Canvas game tutorial with CreateJS and AngularJS

Planting The Seed

To give you an idea of what are we going to make in this tutorial, I made a small demo. Check it, and warm up to make your HTML5 Canvas based game.

I started with default AngularJS seed app, created by my WebStorm IDE. Then, I downloaded the source code of EaselJS Spritesheets example from createjs.com, and separated the code into AngularJS directive, service, and factories. I also added some music to the game, and a little more control of the character movement. Plus, I added a score and life count for the character, which are necessary for the game.

AngularJS significantly reduces complexity by enabling your development team with the following:

  1. Adding code modularity, so that team members can focus on different aspects of the game.
  2. Breaking the code into separate testable and maintainable pieces.
  3. Enabling code re-use, so that one factory class can be instantiated multiple times, and re-used to load different but similar assets and behaviors.
  4. Speeding up the development because multiple team members can work in parallel, without stepping on each other’s toes.
  5. Protecting developers from using bad patterns (Javascript carries notoriously bad parts with it and JSLint can only help us so much).
  6. Adding a solid testing framework.

If, like me, you are a “tinkerer” or a tactile learner, you should get the code from GitHub and start learning. My suggestion is to look through my check-ins and understand the steps I took to gain benefits of adding AngularJS goodness to CreateJS code.

Running Your AngularJS Seed Project

If you haven’t already done so, you need to install nodeJS before you can run this demo.

After creating an AngularJS seed project, or downloading it from GitHub, run npm install to download all dependencies to your app folder.

To run your application, execute npm start from same folder and navigate to http://localhost:8000/app/#/view1 in your browser. Your page should look like the image below.

page example

EaselJS Meets AngularJS

Add CreateJS library reference to your AngularJS seed project. Make sure that CreateJS script is included after AngularJS.

<script src="http://code.createjs.com/createjs-2014.12.12.min.js"></script>

Next, clean up the application:

  • Delete view2 folder from your app folder
  • Remove menu and AngularJS version info from index.html, by deleting the code shown below:

 

 

Angular seed app: v

Remove view2 module from app.js, by deleting the following line

myApp.view2,

If you haven’t used AngularJS before, and are not familiar with AngularJS directives, check this tutorial. Directives in AngularJS are a way to teach HTML some new tricks. They are the most well thought out feature in the framework, and make AngularJS powerful and extensible.

Whenever you need a specialized DOM functionality or a component, search for it online; there is a good chance it is already available in places like Angular modules.

The next thing we need to do is create a new AngularJS directive that will implement the example from EaselJS. Create a new directive called spriteSheetRunner in a new file located in /app/view1/directives/spriteSheetRunner.js.

Once your directive is created, add a dependency to the app by updating /app/app.js as below:

Include the directive code in index.html by adding a reference to spriteSheetRunner.js.

We are almost ready! Copy the game assets to your app folder. I’ve prepared the images, so feel free to download them and save in your app/assets folder.

As a final step, add our newly created directive to the page. To do so change your app/view/view1.html file, and make it a one-liner:

Start your application and you will get your runner in motion 🙂

runner in motion

If this is your first AngularJS or first CreateJS application, celebrate, you just made something really cool!

Preloading Assets In A Service

Services in AngularJS are singletons used primarily to share the code and the data. We will use a service to share the ‘game assets’ across the application. To learn more about AngularJS services check the AngularJS documentation.

AngularJS services provide an effective mechanism for loading and managing all assets in one place. Asset changes are propagated to each individual instance of a service, making our code much easier to maintain.

Create new JS file named loaderSvc.js in your /app/view1/services folder.

AngularJS requires us to register any service we are using. To do so, update your app.js file to include reference to myApp.services.

Update your directive code, in app/view1/directives/spriteSheetRunner.js file, to remove the preloading code and use the service instead.

Creating UI elements factory

Re-using and repeating sprites in game development is very important. In order to enable instantiation of UI classes (which are sprites in our case) we will use AngularJS Factories.

Factory is registered in the application just like any other AngularJS module. To create uiClasses factory, modify your app.js file to look like this:

Let’s use the new factory to create sky, hill, ground, and our runner. To do so, create JavaScript files as listed below.

  • app/view1/uiClasses/sky.js

  • app/view1/uiClasses/hill.js

  • app/view1/ground.js

  • app/view1/uiClasses/character.js


Do not forget to add all these new JS files in your index.html.

Now, we need to update the game directive.

Note that moving uiClasses out of the directive reduced the directive size by 20%, from 91 to 65 lines.

In addition, we can independently write tests for each factory class to simplify its maintenance.

Note: Testing is a topic that is not covered in this post but here is a good place to start.

Arrow Keys Interaction

At this point in our HTML5 Canvas game tutorial, mouse click or tap on a mobile will make our guy jump, and we cannot stop him. Let’s add arrow key controls:

  • Left arrow (pause the game)
  • Up arrow (jump)
  • Right arrow (start running)

To do that, create the keyDown function and add an event listener as last line of handleComplete() function.

Try running your game again and check the keyboard controls.

Let The Music Play

Games are not fun without music, so let’s play some music.

We will first need to add MP3 files to our app/assets folder. You can download them from the URLs provided below.

Now, we need to preload these sound files using our loader service. We will use loadQueue of PreloaderJS library. Update your app/view1/services/loaderSvc.js to preload these files.

Modify your game directive to play sounds on game events.

Adding Score and Life Indicators

Let’s add the game score and life (heart) indicators to the HTML5 Canvas game. The score will be shown as a number in the upper left corner, and heart symbols, at the top right corner, will indicate life count.

We will use an external font library to render hearts, so add the following line to your index.html file header.

Standard AngularJS binding will provide real-time updates. Add the following code to your app/view1/view1.html file:

To properly position our indicators, we need to add CSS classes for top-left and top-right in app/app.css file.

Initialize the score and lifesCount variables in app/view1/view1.js controller.

To make sure that indicators are properly updated, modify your main game directive to use the scope variables.

To test the scope binding, add these three lines at the end of handleComplete() method.

When you run the application you should see the score and life indicators.

score and life indicators

Additional white space, on the right of the page, will continue to be present because we are still hardcoding the game’s width and height at this point in our HTML5 game programming tutorial.

Adapting the Game Width

AngularJS is packed with useful methods and services. One of them is $window, which provides an innerWidth property that we will use to calculate the position of our elements.

Modify your app/view1/view1.js to inject $window service.

Extend the main game directive with width and height properties and that’s it!

Now you have the game adjusting itself to width of the browser window.

If you want to port this into a mobile app, I suggest reading my other mobile app development tutorial about using Ionic framework to create mobile apps. You should be able to create an ionic seed app, copy all the code from this project, and start playing the game on your mobile device in less than an hour.

The only thing I am not covering here is collision detection. To learn more about it, I read this article.

Wrap Up

I believe that through the course of this game development tutorial you realized that AngularJS and CreateJS are a winning duo for HTML5 based game development. You’ve got all the basics and I’m sure you recognized the benefits of combining these two platforms.

You can download the code for this article from GitHub, feel free to use, share, and make it your own.