Tutorial: Using sprite sheets in MelonJS

In this tutorial you are going to learn:
- Why you should use a sprite sheet in your MelonJS game
- Using TexturePacker to create a sprite sheet
- Optimizing the sprite sheet for size faster downloads
- Adding a static background
- Creating an animation
Your goals for this tutorial:
- Learn why you should use sprite sheets in your MelonJS game
- Use TexturePacker to create a sprite sheet
- Optimize the sprite sheet to improve startup time and performance of your game
- Add a static background
- Create and play an animation
Why you should use sprite sheets
Using a sprite sheet instead of a bunch of single images comes with some advantages:
- Saving memory — the sheet uses less memory
- Faster startup time — only one file has to be loaded from the server
- Increased frame rate — MelonJS optimizes the GPU usage and makes your game faster
Creating a sprite sheet
The easiest way to create an optimized sprite sheet is using TexturePacker — available for Windows, MacOS and Linux (Ubuntu):
Selecting your data format
For this tutorial start a trial of the pro features of TexturePacker.
TexturePacker as a free mode which is automatically activated after the trial. It works with MelonJS if you use the generic JSON Array data format but does not contain the optimizations and presets for MelonJS.
You should see a screen similar to the one below after you've installed TexturePacker:

TexturePacker supports a bunch of different game and web development frameworks. Start by selecting MelonJS as your Data format .
Adding sprites
Next add your sprites by dropping the cityscene folder onto the center of TexturePacker. All known image formats (such as psd, png, jpg, even swf) inside the folder are added to the sprite sheet automatically. New or changed files update the sprite sheet as soon as you re-enter the application.
Optimizing your sprite sheet for speed and size
TexturePacker has already optimized your sprite sheet using Trim . You see this below the texture: 85% overdraw . The missing 15% are transparent pixels that have been removed. They are not needed in the sprite sheet — keeping them would waste memory and require more rendering. MelonJS gets the information about the removed pixels through the data file and keeps your animations aligned.
TexturePacker can rotate sprites to pack into a texture size. This causes some calculation overhead in MelonJS. If you prefer smaller memory over performance, click Show advanced in Layout and check Allow rotation .
Reduce the file size to improve the download speed of your game by setting Pixel format to INDEXED . This enables the pngquant — storing the image as 8 bit indexed png. This decreases the file size from 383kb to 102kb while keeping the image quality almost identical. If you see color bands in gradiens set Dithering to PngQuant High .
Original scene with 32 bit colors, 383kb:
Optimized scene with indexed colors, 102kb:
Creating the sprite sheet
You can now press Publish sprite sheet from the top toolbar to create a data file and the sprite sheet image. Enter cityscene.json as file name and save it in the data/img folder. You can change the file name under Data file if you have to.
Importing and using the sprite sheet in MelonJS
Start by adding the sprite sheet and data file toto the list of assets to be loaded in resources.js :
game.resources = [
{ name : "texture", type : "json", src : "data/img/cityscene.json" },
{ name : "texture", type : "image", src : "data/img/cityscene.png" }
];
Note that resources.js is automatically managed by the MelonJS boilerplate,
as it builds the resources list and exposes it to your app as game.resources
when using the grunt serve task.
Now create a global reference of your Texture
under the game namespace in game.js :
"loaded" : function () {
// load the texture atlas file
game.texture = new me.video.renderer.Texture(
me.loader.getJSON("texture"),
me.loader.getImage("texture")
);
…
}
Add the static background
Adding a static background is pretty easy:
game.PlayScreen = me.ScreenObject.extend({
/**
* action to perform on state change
*/
onResetEvent: function() {
// viewport width and height
var w = me.game.viewport.width;
var h = me.game.viewport.height;
// add the Background
var background = game.texture.createSpriteFromName("background");
// set position to the middle of the viewport
// (as the sprite anchorPoint is (0.5, 0.5)
background.pos.set(w / 2, h / 2, 1);
// add to the scene
me.game.world.addChild(background, 1);
}
});
The code uses the background texture from the sprite sheet and adds it to the screen. It also centers the background by setting it's coordinates to the screen's middle.
Note that as the default settings in TexturePacker is to use center as the anchorPoint, we also set the default position for the background to the center of the screen, but you can of course change it to top-left or whatever you need, and change the default position accordingly (that would be [0, 0] if top-left coordinates are used for the anchor point).
Also, note that melonJS 3.x provides an alternate and easier way of creating directly a me.Sprite using a texture atlas, as shown below :
// add the Background with default position to the middle of the viewport
var background = new me.Sprite(
me.game.viewport.width / 2,
me.game.viewport.height / 2,
{
image : game.texture,
region : "background.png"
}
);
// add to the scene
me.game.world.addChild(background, 1);
Add the cap guy animation
Let's now add an animation. To do this create a new Entity
in entity.js :
/**
* Cap Guy entiry
*/
game.CapGuyEntity = me.Entity.extend({
/**
* constructor
*/
init: function (x, y) {
// call the super constructor
this._super(me.Entity, "init", [200, 140, {width : 100, height : 300}]);
// create an animation using the cap guy sprites, and add as renderable
this.renderable = game.texture.createAnimationFromName([
"capguy/walk/0001", "capguy/walk/0002",
"capguy/walk/0003", "capguy/walk/0004",
"capguy/walk/0005", "capguy/walk/0006",
"capguy/walk/0007", "capguy/walk/0008"
]);
// enable this, since the entity starts off the viewport
this.alwaysUpdate = true;
},
});
This code initialises a simple entity at 200,140 and adds a renderable component. This component is initialised with the animation frames from the CapGuy walk cycle.
Add the animation to the game scene, add the following code at the end of onResetEvent
in play.js :
// add the Cap Guy
var CapGuyEntity = new game.CapGuyEntity();
// add it to the scene
me.game.world.addChild(CapGuyEntity, 2);
If you start the demo now you'll see CapGuy walking... but he's not yet moving. Add the following code block to entity.js
/**
* manage the enemy movement
*/
update : function (dt) {
// just manually change the guy position
this.pos.x += 0.3*dt;
// repeat once leaving the viewport
if (this.pos.x >= me.game.viewport.width) {
this.pos.x = 0;
}
// call the parent function
this._super(me.Entity, "update", [dt]);
return true;
}
This block moves CapGuy a bit to the right. dt
is the time difference between the last frame and the current frame.
Using this as a base for the update keeps the animation speed constant.
The if
block resets CapGuy to the left border after he left to the right.
Using the command line / grunt
TexturePacker starts with the graphical user interface by default. It also comes with a command line client — allowing you to fully automate the process.
Use Install Command Line Tool from TexturePacker's menu to add the TexturePacker
command.
The command line tool allows you to fully configure the creation process of your sprite sheets. E.g. to create a MelonJS sheet you can use:
TexturePacker --format melonjs \
--data data/img/cityscene.json \
--sheet data/img/cityscene.png \
data/assets/cityscene
You can also use it to update the .tps file. This makes your life easier: Configure everything in the graphical user interface — then re-build sheets on change:
TexturePacker *.tps
You can even add it to grunt using the grunt-shell plugin:
shell: {
update_spritesheets: {
command: 'TexturePacker *.tps'
}
}
Summary
You've now learned how to create sprite sheets and use them in your MelonJS project. TexturePacker makes it easy to handle your assets and optimize your game for size and speed.