Making a sprite sheet from an 2d canvas context in phaser

For this post on phaser ce I will be writing about ways to go about making a sprite sheet from a canvas element, rather than loading an external asset. This can be done a number of ways, but in this post I will be using the 2d canvas drawing context in a canvas element and pass that element to a method that can be used in the phaser cache to create a sprite sheet from a canvas element.

1 - What to know

This is a post on making a sprite sheet using a canvas element in phaser ce a javaScript powered game framework. This is not a getting start post on phaser ce, or on javaScript in general, so I assume that you have logged at least a few hours getting down some basics first.

2 - A quick, basic example of using canvas to make a sprite sheet in phaser.

So for a very quick, and easy getting started example of making a sprite sheet with canvas in phaser ce, I often use a single method to make a basic sheet when making one of my many examples for these posts of mine. The basic idea is to generate a canvas, and draw to it like normal, and then pass a reference to the canvas element as one of the arguments to a method in the cache called game.cache.addSpriteSheet.

What I end up with in many projects might look something like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// make a sprite sheet
Enemy.mkSheet = function (game) {
// sprite sheet generated by canvas
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
canvas.width = 64;
canvas.height = 32;
// blue frame
ctx.fillStyle = '#0000ff';
ctx.fillRect(0, 0, 32, 32);
// red frame
ctx.fillStyle = '#ff0000';
ctx.fillRect(32, 0, 32, 32);
game.cache.addSpriteSheet('sheet-block', null, canvas, 32, 32, 2, 0, 0);
};

When calling the game.cache.addSpriteSheet method the first argument is the key that I want to use to refer to the sheet when making sprites, and the second argument is what would be a url to an asset, but because I am using canvas I leave this at null. The third argument is the sprite sheet data, and for this one of the options for the data is a plain old canvas element. The next arguments are to set the frame width, and frame height, as well as the number of frames, and the spacing between frames.

3 - A more advanced example

For a basic example I will create a method that will create a canvas element, and set its native size depending on the frame width, and height, and the number of frames I want the animation to be. Once I have that worked out it will draw each frame using the canvas 2d drawing context. For this basic example it will just be a sprite sheet of a box with a line drawn from it’s center outward that rotates. Once the canvas is rendered it then creates a sprite sheet by calling a method in the phaser cache object.

3.1 - first a method that will create the sheet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// make a canvas that is a sprite sheet of a box with
// a line from it's center outwards.
var mkCanvas = function () {
var frame = 0,
maxFrame = 24,
frameWidth = 64,
frameHeight = 64,
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
// set the native size of the canvas
canvas.width = frameWidth * maxFrame;
canvas.height = frameHeight;
// while the current frame is less than max frames
while (frame < maxFrame) {
// figure startx, and percent done
var sx = frameWidth * frame + 0.5,
per = frame / maxFrame;
// draw for current frame
ctx.strokeStyle = '#00ff00';
ctx.save();
ctx.translate(sx + 32, 32);
ctx.rotate(Math.PI * 2 * per);
ctx.strokeRect(-16, -16, 32, 32);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, 30);
ctx.stroke();
ctx.restore();
// next frame
frame += 1;
}
// add a new sheet to cache
this.game.cache.addSpriteSheet('sheet-1', null, canvas, frameWidth, frameHeight, maxFrame, 0, 0);
};

This method will be used with call to set the value of this to what it should be inside the body of a create method in the state object for this example which is as follows.

3.2 - An example that uses the basic method written about above

So now that I have my method that can be used to create a sprite sheet with canvas in phaser, it is now time to have a phaser project that makes use of that method. I start out my making my instance of a phaser game object with the Phaser.Game constructor, then create just a single state object with a single create method.

In the create method I call the mkCanvas method with call setting the value of this to the state object which is the same as it is in the body of the create method. This will generate the canvas element, and make the sprite sheet with the key ‘sheet-1’. Once I have the sheet I can then create a sprite using that sheet, as well as an animation that uses all the frames in that sheet.

Once that is all done I then start the state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var game = new Phaser.Game(320, 240, Phaser.AUTO, 'gamearea');
game.state.add('basic', {
create: function () {
mkCanvas.call(this);
// create a sprite with the sheet
var sprite = game.add.sprite(0, 0, 'sheet-1', 0);
sprite.name = 'sp1';
sprite.x = game.world.centerX - sprite.width / 2;
sprite.y = game.world.centerY - sprite.height / 2;
// create an animation called 'rotate', that uses all the frames (null),\
// plays at 12 frames per second, and loops
sprite.animations.add('rotate', null, 12, true);
// start the animation
sprite.animations.play('rotate');
}
});
game.state.start('basic');

If you reproduce this on you end, and all goes well you should see a rotating box with a line drawing outward from the center.

3.3 - wrap up with the advanced example

So there is much lacking with this basic example, but to make a better solution I just need to expand on this as much would remain the same. The process would always be to make a canvas element, render one or more set of frames, and then pass the canvas element as the propper argument to game.cache.addSpriteSheet. Then I can make sprites, and animations using this sheet.