Phaser 2 and Flump Animations

Aaron Malley
Well Red
Published in
8 min readDec 11, 2019

Introduction

For HTML5 game development, there are a few options developers have to create animations. We use Adobe Animate (formerly known as Flash) and Flump to produce high quality keyframe-based animations. Animate provides our artists with an industry standard animation tool. Flump takes animations created in Animate and serialized timeline data to JSON or XML, and rasterize vector art into texture atlases.

Unfortunately, Flump is not very wide spread within the game development community. It is because of this that it does not have a lot of support within some of the more popular HTML5 game engines. We use Phaser 2 for our HTML5 games, which doesn’t support Flump. To solve this, we wrote a plugin for Phaser that will load and play Flump animations.

Flump vs. Other Options

So, why Flump? By default, Phaser 2 supports two types of animations: flipbook sprite animations, and Spine. Flipbook animations are standard sprite animations where you swap images to give the illusion of motion. Spine is a skeletal animation tool that allows animators to animate individual parts of a character by attaching them to bones.

We use Flump instead of flipbook animations because of quality and memory consumption. Flump provides smooth television quality animations that use less texture memory.

When it comes to choosing Flump over Spine, it came down to cost and workflow. Spine is an excellent animation tool and popular within game development. You can get a similar level of quality with Spine as you can in Adobe Animate; and it is natively supported in Phaser. So why use Flump over Spine? Simple, Spine is expensive. It is free to use within Phaser 2, however the Spine animation tools have extremely high licensing fees for medium to large businesses. The license costs increase based on company revenue. While Adobe Animate does have license fee, it is far cheaper for individuals and companies that are already using Adobe Creative Cloud.

We also do a lot of work with world-class media brands, and often adapt television animations to game content. Being able to directly use TV animations created with Adobe Animate in our games allows for a more authentic experience.

Example of a character setup for Flump in Adobe Animate.
Example of the character previewed in the Flump exporter.
Exported Flump atlas of the character.

Technical Breakdown

The original runtime

The plugin we wrote is based off the runtime written for the Flump exporter tool. Flump is open source and is licensed under the MIT license. This meant we were free to use what we needed from Flump to get animations working in Phaser, however, it wasn’t a straight port. Since Flump is written in ActionScript 3 for the Starling framework, bringing it over to Phaser 2 meant integrating Flump so it worked fluidly with the engine.

Asset Loading

Our first step was implementing a custom loader that we could use with Phaser’s load manager. We wanted to be able to use the standard Phaser pipeline to load our Flump assets. With our new Flump atlas loader, we can call `game.load.flumpAtlas(…)`.

preload() {
game.load.flumpAtlas(“demoLibrary”, “assets/library.json”, “assets/atlas0.png”);
}

To load the Flump assets, we provide a key that we will use to identify those assets within the cache object. In this case, our key is “demoLibrary”. The loader will store the `library.json` data using the key, and add the key as a prefix to the image file name. In our example, the file “assets/atlas0.png” is stored as “demoLibrary/atlas0.png”. We need to prefix the library key onto our images because the Flump exporter does not allow us to change the naming scheme it uses when exporting the atlas images. Without the prefixed library key, we would run into naming collisions if the assets for more than one library were loaded.

Library Creation

After we have the Flump assets loading into Phaser’s asset cache, we initialize a Flump library to use its resources. A Flump library is a collection of textures and movie symbols that were exported from Animate. Each symbol is unique to the library it belongs to, and this was something we wanted to make sure remained the case within the plugin.

create() {
game.flump.add(“demoLibrary”);
}

When a library is added to the plugin, it uses the key we provide to pull all the resources it needs from Phaser’s asset cache. This includes “library.json” and any atlas images that were prefixed by our custom loader. Once the data has been retrieved, it will parse “library.json” and create the frame data for each atlas image. With the atlas images paired with frame data, the Flump atlas can be used as if it were any other image atlas.

game.image.add(0, 0, “demoLibrary/atlas0.png”, “orangeSquare”);

Porting the Animation Player

Having our Flump assets integrated into the standard Phaser workflow allowed us to easily begin porting over the animation player from the Flump exporter.

We started by creating a generic Symbol object. A symbol is any object that Flump uses to play an animation. This includes empty placeholder objects, textures, and movies. In practice, our Symbol is just an extended Phaser Image. This allows us to assign any symbol texture data from a Flump atlas. It also allows pooling of texture symbols when they are not being used by a movie.

When Flump exports an animation with rotations, it converts the rotation values into a scale and skew. This means that the plugin needed support for skewing images. Our Symbol object allowed us to add skewing support into Phaser.

Symbol pooling is one of the optimizations we added. We wanted the ability to reuse a movie symbol to play different animations, which meant that when changing animations some symbols would no longer be needed. Instead of allocating and deallocating symbols, we pool and reuse them by assigning new texture data to it. Any symbol not being used remains in the pool until one is needed.

Frame Labels

One of the more interesting features of Flump is the ability to export frame labels from the timeline in Animate. A frame label is just a string given to a keyframe. This is useful because it allows developers to listen for frame labels to trigger in-game events. For example, if our animators create a cutscene animation, they can use frame labels to tell the game when it should begin playing voice over audio or sound effects. Frame labels can also be used in code to tell an animation to play until it reaches some label, or to go to and stop at a specific label. This was an important feature to make sure we carried over into the plugin.

movie.labelEvents.add((label) => {
if (label === “playSfx”) {
sound.play();
}
});

With our Symbol object and symbol pooling in place, we were able to port the Flump runtime over into Phaser. Overall, it went smoothly. We came across a couple bugs that we fixed, and we did not run into any major issues. After everything was done, we had a Flump animation plugin for Phaser 2 that accurately played content created in Adobe Animate.

Speed Control

After the Flump implementation was complete, we found that we wanted to have a greater level of control over playback. While animations did play and animate at the correct frame rate, we wanted the ability to control the playback speed of animations. This would allow us to speed up and slow animations down based on game logic. Adding the feature was not difficult, because it only required scaling the delta time used to advance an animation.

This did introduce an issue when animations were slowed down. They looked clunky; as if the game was running at a lower frame rate even though it was still running at 60 fps. When Flump advances an animation, it rounds its frame position. It does this so it does not run into errors when pulling keyframes from an array. The issue this causes is that when it came to calculating the interpolation between one frame to the next, it did so in whole steps. So frame one to frame two, two to three, and so on. This is good for figuring out which keyframe data to use, however, it does not work for scaling the speed of an animation. To fix this, we allowed the interpolation to use fractions of frames without allowing the animation to play further than the keyframe it is currently on. So if our last frame was one and our next frame was two, then if game time determined we are actually at frame position 1.5, then the animation would use 1.5 to interpolate between the two frames. We still used whole numbers to determine keyframe positions, however now animations can use fraction of frames to interpolate. The result is far smoother animations. They still animate at the frame rate that was set in Adobe Animate, however they play smoother in our plugin. These smoother animations allowed us to scale the playback speed without slower speeds looking clunky.

Conclusion

A GIF of the Flump mascot playing in Phaser 2

After we were able to smooth out animations, the plugin was complete. We were able to create a Flump player for Phaser 2 that allows developers to reuse movies for multiple animations as well as implemented optimizations and improvements.

You can find the source for the Phaser 2 Flump plugin on GitHub here. The plugin is also available on NPM here. We also provide a demo project that shows examples of how to use the plugin here.

What’s Next?

We are currently bringing this plugin over to Phaser 3. Although the Phaser 2 port of Flump was straight forward, Phaser 3 does not support the ability to skew an image. Since Phaser 2 is built on top of PIXI, we were able to easily use Flump’s scale and skew value to calculate a matrix to figure out the rotation of an object. In Phaser 3, the matrix calculations have been decoupled from the renderers and game objects making Flump integration more difficult. When we finally do port Flump to Phaser 3, we want to make sure it is seamlessly integrated into the engine to ensure maximum stability.

--

--

Aaron Malley
Well Red
Writer for

Game developer at REDspace who has been creating web and mobile games for over 10 years.