Introduction
This blog post is a response to the forum thread here. Posting my complete answer was getting a bit too large for a normal forum post, so I decided to write it out here as a dev blog post.
Source: Creator of this Sprite Sheet is called “acasas” https://opengameart.org/content/pixel-art-character
Overview
While travelling / zoning out at family dinners, I had time to think about why it was so important to me that I could re-use existing animations in Phaser 3. I came to the conclusion that what really mattered to me was a flexible way to add & remove skins (sprite sheets) to the game, without having to update the game code, minify the files again, and upload to my web server.
So what I did was the following:
- Create all animations at the start of the game, as rich explained.
- Import all animations, which target the skins, from an external JSON file.
- The Hero object saves & plays the correct animation key using the setData() and getData() methods, as samme suggested.
The result is exactly what I needed! I can add & remove as many skins as I want now by updating my JSON file called “anims.json” and the game will automatically creat the animations at start-up, and the Hero object correctly saves the animation keys when instantiated.
JSON File
Here is my anims.json file. For testing it contains just 2 skins at the moment but can be extended with as many skins as you want:
{ "skins" : [ "hero1", "hero2" ], "keys" : [ "walk-left", "walk-up", "walk-down" ], "frames" : { "walk-left" : [ 0, 1, 2 ], "walk-up" : [ 3, 4, 5 ], "walk-down" : [ 6, 7, 8 ] }, "repeat" : -1, "frameRate" : 9 }
Creating the Phaser 3 Animations
Create the animations at game start-up. I’m doing it in the create() method of my PreloadScene. You can do it anytime at the start of the game, as long as it has loaded the sprite sheeets and json file. Look how much shorter it is now than adding 6 animations manually (2 skins, 3 animations each).
NOTE: The animation for walking left and right is the same for me. I just flip the sprite horizontally but play the same animation, namely “walk-left”.
this.json_anims = this.cache.json.get('json-anims'); this.json_anims.skins.forEach((skin) => { this.json_anims.keys.forEach((key) => { this.anims.create({ key : skin + '-' + key, frames : this.anims.generateFrameNumbers('spr-' + skin, { frames: this.json_anims.frames[key] }), repeat : this.json_anims.repeat, frameRate : this.json_anims.frameRate }); }, this); }, this);
Saving the Animation Keys
Here is the snippet from my Hero object where I set the skin and at the same time save the corresponding animation keys, making use of the setData() method. Remember that you have to use setDataEnabled() on the sprite object beforehand.
NOTE: this.ctx is a reference to the Phaser Scene, in which the Hero object was instantiated.
Hero.prototype.setSkin = function(skin_id) { 'use strict'; if(!this.spr) return; // Skin this.skin_id = parseInt(skin_id); this.spr.setFrame(this.ctx.helper.getSkinFrame(this.skin_id)); // Anims let json_anims = this.ctx.cache.json.get('json-anims'); let skin_name = json_anims.skins[this.skin_id - 1]; let anims = {}; this.spr.setDataEnabled(); json_anims.keys.forEach((key) => { anims[key] = skin_name + '-' + key; }, this); this.spr.setData('anims', anims); };
Playing the Phaser 3 Animation
And finally, this is the snippet from the Hero object where it plays the animation, making use of the getData() method:
Hero.prototype.triggerAnimsBySpeed = function() { 'use strict'; let direction = this.getCurrentDirection(); // Nothing changed: stop here if(this.last_direction === direction) { return; } // Anims for this sprite let anims = this.spr.getData('anims'); // Play the animation switch(direction) { case 'left': this.spr.setFlipX(false); this.spr.play(anims['walk-left']); break; case 'right': this.spr.setFlipX(true); this.spr.play(anims['walk-left']); break; case 'up': this.spr.setFlipX(false); this.spr.play(anims['walk-up']); break; case 'down': this.spr.setFlipX(false); this.spr.play(anims['walk-down']); break; default: // idle this.stopAnims(this.last_direction); } // Save last direction at the end this.last_direction = direction; };
Final Words
As you can see, the game creates, saves & plays all Phaser 3 animations automatically now. The only thing I have to edit now is the JSON file.
When I add a new skin, I just add the sprite sheet’s name to the “skins” array, i.e. “hero3”. My naming conventions are quite boring but you could just as well call your skins “FireSkin” and “IceSkin” etc.
As a final reminder, the constraints are as follows:
- All sprite sheets must have the same frame sequence for the same animation key, i.e. “walk-left” always has to be the frames [ 0, 1, 2, 3 ].
- And all sprite sheets must have the same animations, meaning that if I want to add a new skin it also has to have 4 directional movement. I cannot create a skin with only walk up and down.
- That also means that if for example I want to extend my sprite sheets with a running sequence, I have to add the running sequence to ALL my skins.
- Since these are literally just skins in my game, and all skins must have the same animations anyways, this isnt’ a problem for me. But it’s something you might have to keep in mind for your own game.
I hope this was clear and useful! Feel free leave feedback in the comments below if you liked it or how I can improve it.
The Ultimate Phaser 3 Guide
Everything you need to make real, polished, professional Phaser 3 games, you find it in this guide here: HTML5 Game Development Mini-Degree
I highly suggest you check it out!
Thanks for sharing this technique! It’s amazing how Phaser 3 can allow us to leverage that much power in JSON files. very cool.
Hi blackhawx, thank you for leaving your feedback! There is still so much more to discover in Phaser 3, I hope one day the developer of the framework will release a full game and we get to inspect his techniques in the source code. For example there is still so much more that can be achieved with the new Scene and Camera Objects.