How to create sprite animations for EaselJS

How to create sprite animations for EaselJS

In this tutorial you are going to learn...

... how to ...

  • create sprite sheets for EaselJS/CreateJS
  • load assets using PreloadJS
  • use animations from a sprite sheet
  • set/edit pivot points visually
  • optimize your sprite sheet for fast downloads

Here's the final result of the tutorial:

Why you have to use sprite sheets for your game

Here are some reasons why sprite sheets are a big win for your game:

1. Sprite sheets reduce the download time

You are building a game or application for the web. This means that all data has to be loaded from your web server somewhere on the internet. The more files you have the bigger is the overhead for building connections to the server and requesting the data.

Your game starts faster if you download a smaller number of big files instead of many small files.

2. Smaller memory footprint

Obsolete transparency around the sprites can be removed automatically to reduce the amount of RAM used while displaying your game. This is very important on mobile devices.

3. Make use of animations and pivot points

The sprite sheet can be combined with a data file that contains additional information like animations and pivot points. This makes game development faster and easier for you.

Download the demo project from GitHub

Let's start by downloading the demo project from GitHub.

The project contains the following files and folders:

  • assets - A folder containing the sprites used in this demo
  • createjs - EaselJS and PreloadJS
  • demo.html - The demo source code
  • easeldemo.tps - TexturePacker project file used to create the sprite sheet
  • sheet.json and sheet.png - Pre-built sprite sheet

How to create sprite sheets for EaselJS / CreateJS

Using Photoshop® or Gimp to create your sprite sheets

You can of course create sprite sheets with Photoshop® or Gimp — simply put all your sprites into a big image and that's it...

But creating sprite sheets with a painting tool is a bad choice for game development.

EaselJS has to know where a sprite is and how big it is. You'll have to work with the sprite coordinates in your game. You'll also have to update the coordinates with each change.

That's not a good solution.

The better choice: TexturePacker

TexturePacker is a tool specialized in creating, managing and optimizing sprite sheets for game development — and it's the best too you can get for this job.

TexturePacker supports EaselJS's own sprite sheet data format including support for animations and pivot points. EaselJS loads the sheet and the data file you can reference the sprites by their names.

Please download TexturePacker from here:

After installing and starting TexturePacker (and accepting the license agreement) you should see the main window.

  1. Drag & drop the assets folder containing your sprites on the left or center panel.
  2. Set the Framework to EaselJS / CreateJS in the top right panel
  3. Press publish and select your game folder to write the sheet.json and sheet.png file

(You can also open the existing easeldemo.tps file. It's a TexturePacker project file with the basic setup.)

How to create sprite sheets for EaselJS / CreateJS using TexturePacker

The file demo.html contains the demo source code. Please be aware that opening the file in your browser directly does not work. The reason is that the sprite sheet is loaded dynamically which is not permitted with the browser's default settings. You have to serve the files from a web server.

If you have PHP installed on your computer you can use

php -S localhost:8080

to serve the demo. It's available from http://localhost:8080/demo.html

Another option is to use Node.js:

npm install http-server -g
http-server .

The demo now runs on http://localhost:8080/demo.html.

The basic skeleton file looks like this.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">

    <!-- load EaselJS and PreloadJS -->
    <script src="./createjs/easeljs.js"></script>
    <script src="./createjs/preloadjs.js"></script>

    <script>
        function init()
        {
        }
    </script>
</head>

<body onload="init();">
<div>
    <canvas id="testCanvas" width="960" height="540"></canvas>
</div>
</body>
</html>

The code consists of:

  • the <script> tags to load the libraries (EaselJS and PreloadJS)
  • the <script> block with the code (currently only the init() function)
  • the <body> with the onload='init()' to start the demo code
  • the <canvas> element which is used to render the scene

How to load assets from using PreloadJS

PreloadJS is responsible for loading the assets from the server. You could create a much easier version for this demo, but I've decided to keep the full-featured loader code. This is useful if you want to extend code demo and add your own content later.

Let's start with the init() function:

function init()
{
    var manifest = [
        {src: "sheet.json", id: "sheet1", type: "spritesheet"}
    ];

    var loader = new createjs.LoadQueue(true, "./");
    loader.on("fileload", handleFileLoad);
    loader.on("complete", handleComplete);
    loader.loadManifest(manifest);
}

The manifest contains the stuff you want PreloadJS to fetch from the server.

{src: "sheet.json", id: "sheet1", type: "spritesheet"} tells it to load a sprite sheet file called sheet.json with the id sheet1. The image file sheet.png is loaded automatically — it's referenced in the json file.

The next line creates a LoaderQueue. true tell PreloadJS to use XHR by default, "./" is the default resource path to use for loading the data.

The next two lines define event handlers that are triggered during the loading process:

  • fileload is triggered after a single file is completed
  • completed is triggered after all files are loaded

There are other events you can listen to — e.g. error or progress but we'll ignore them for this demo.

The final line passes the manifest to the loader and starts loading data.

Let's implement the function handleFileLoad() which is called after loading a single file:

var assets = [];

function handleFileLoad(event)
{
    assets.push(event);
}

This function simply appends the result event to our assets array. The array is processed after all files are loaded in handleComplete():

var betty;
var stage;
var spriteSheet;

function handleComplete()
{
    for (var i = 0; i < assets.length; i++)
    {
        var event = assets[i];
        var result = event.result;

        switch (event.item.id)
        {
            case 'sheet1':
                spriteSheet = result;
                break;
        }
    }

    initScene();
}

The code iterates through the loaded assets and assigns the sprite sheet to the variable spriteSheet. I've kept this code for the tutorial because you can easily add more case blocks for other assets in the future.

The final line initScene() starts the main scene.

How to build a game scene with animations with EaselJS

Creating a basic scene with some static sprites

Let's start with a simple scene: Some ground tiles:

function initScene()
{
    stage = new createjs.Stage(document.getElementById("testCanvas"));

    for (var i = 0; i < 5; i++)
    {
        var floor = new createjs.Sprite(spriteSheet, "Floor");
        floor.x = i * 256;
        floor.y = 400;
        stage.addChild(floor);
    }

    createjs.Ticker.timingMode = createjs.Ticker.RAF;
    createjs.Ticker.addEventListener("tick", stage);
}

The first line initialises a Stage object. The parameter passed is the <canvas> element in the html file. It's referenced by the id testCanvas.

The second block creates 5 floor sprites using the image called Floor from the spriteSheet. The sprites are placed at increasing x positions and added to the stage.

The name Floor is derived from the Floor.png file that you added in TexturePacker.

The final 2 lines create a timer event that updates the stage in regular intervals. You need this for animations — coming in the next section.

You should see the following scene after reloading the demo in your browser:

EaselJS using static sprites

Adding an animation

Adding animations is easy because TexturePacker has already done most of the work for you.

The asset folder contains a bunch of animation frames of our game character Betty:

  • RunRight_0001.png
  • RunRight_0002.png
  • RunRight_0003.png
  • RunRight_0004.png
  • RunRight_0005.png
  • RunRight_0006.png

TexturePacker detects the _0001_0006 in the file names as animations and builds an animation object called RunRight (taken from the base name of the files).

To play the animation it's sufficient to pass its name to the createjs.Sprite() method, set the coordinates and add the object to the stage. Add the following code to the initScene method:

betty = new createjs.Sprite(spriteSheet, "RunRight");
betty.x = stage.canvas.width / 2;
betty.y = 400;
stage.addChild(betty);

Ok — this plays the animation, but it's too low in the scene:

EaselJS misplaced sprite animation

This is because pivot points in EaselJS are at top left by default, and we've placed the floor and Betty on the same y coordinate.

You could now start adjusting the Betty's y coordinate until it has the right position. But there's also another option which can save you a lot of time in your game projects...

Use TexturePacker to visually edit the pivot points

TexturePacker gives you an easier way: The pivot point editor.

Editing EaselJS sprite pivot points
  • Select all animation frames of the Betty sprite
  • Click Sprite settings in the toolbar
  • Check Enable pivot points in the right panel
  • Select all pivot points in the center view by pressing CMD-A (Mac) or CTRL-A (Windows)
  • Drag the pivot points down to the bottom center or user the Bottom center preset in the right panel.
  • Press publish and reload your demo

Betty should not be positioned above the floor.

Moving the sprite

Nice... but Betty is not moving.

Simply add the following line to the end of the initScene() function:

createjs.Ticker.on("tick", tick);

This adds a tick handler that is called in regular intervals. You also have to add the function that is called as the handler:

function tick(e)
{
    betty.x = (betty.x + e.delta * 0.5) % stage.canvas.width;
}

This updates Betty's x position. The modulo operation % makes sure that betty re-enters the scene from the left after leaving on the right...

Refresh your browser to see Betty moving!

Changing animation speed and animation preview

You can set the default speed for the animations in TexturePacker's advanced settings. Click the Advanced settings at the bottom of the right panel.

The frame rate settings are at the top right of the panel:

EaselJS: frame rate

TexturePacker also comes with an animation preview that you can start from the toolbar. Select some sprites to preview the animation.

The animation preview works ins real time — you can even watch the animation change while you edit your pivot points.

Faster downloads: Reducing the size of your sprite sheet

You've already done a lot to optimize the download for this scene: Instead of loading 7 single images you only load one sprite sheet.

But there's more you can do to reduce the amount of memory and speed up downloads.

TexturePacker comes with a high quality image optimizer (based on pngquant). It can reduce your sprite sheet's size by 62%!

You can enable it by switching the texture format from PNG-32 to PNG-8:

Optimizing images for EaselJS

Conclusion

TexturePacker is the best companion tool for you EaselJS development:

  1. Pack sprite sheets
  2. Edit pivot points
  3. Preview animation
  4. Optimize image size