Tip #14 – How to create a Flixel plugin
When Adam created Flixel 2.5 he added support for plugins. Probably due to my constant harassing him on GTalk about it, but he did it all the same! And lots of my Flixel Power Tools take advantage of them. But it’s not always easy to know when you should be creating a plugin and what benefits you get from doing so. So here’s my guide to Flixel plugins. Along with a tutorial and playable demo on creating a plugin that makes a tinted mirror effect from any given FlxCamera that looks like this:
Where do plugins live?
Plugins live in the org.flixel.plugin package, which naturally maps to this folder:
in your file system. You can create the class file either directly in here, or create your own folder inside “plugin” and then create your classes within that. This is a good way of avoiding naming conflicts with other plugins found online, so I’d recommend it.
Name your class file to match what the plugin does as best you can. Try not to be obscure. If the plugin is responsible for launching a wave of aliens then call it AlienWaveLaunch, so when you come back to your code later on, you know what it’s going to do before you’ve even opened the file. It’s common for Flixel plugins to have Flx at the start of their name, i.e. FlxAlienWaveLaunch, but this is not a technical requirement, so name it whatever you feel like.
The different types of plugin
A plugin can work in one of three ways:
- Registered Core Plugin – Automatically updated by Flixel every step
- Standard Class Plugin – Updated only when directly called in the game code
- Static Class Plugin – Typically offers utility methods
Which one you need is entirely up to your requirements. Here are some examples to help you differentiate between them:
Registered Core Plugin
An automatic plugin has to extend the FlxBasic class, and must have either an update or draw method. In the game code you register this plugin with Flixel, telling it to activate it:
if (FlxG.getPlugin(FlxControl) == null)
In this example the FlxControl plugin has been activated by Flixel and is now available for use. You only need do this once in your game. When a plugin is added in this way, Flixel will check it twice per step (typically there is one step per frame update). First in the updatePlugins sweep it searches its list of registered plugins. If the plugin has its exists and active values both set to true, then it calls the update method of the plugin.
This happens BEFORE the update method of your games FlxState is called. This is important – it means the plugin is called before any other object in your game (i.e. all of your FlxSprites)
Once the State has updated Flixel then does a second sweep, this time calling the draw method of your plugin (if it has one). This happens immediately AFTER the FlxState draw is called during which every object in your game (sprite, button, group) are drawn to the cameras. Once this is complete all of the plugins then have their draw method called.
This sequence of events is vitally important. If your plugin is performing a visual effect on a sprite for example, then you’d want the code for that to be in the plugins draw method so it happens after the sprite has been updated. Although “draw” sounds like you should only put code relating to rendering in it, that’s simply not true. If anything you should think of “update” as “pre” and “draw” as “post”, i.e. pre update and post render.
The other important thing to remember about these types of plugin is that they carry on updating, automatically, regardless of which State your game is in. Even when you change state they carry on updating. So if your plugin is using FlxSprites from a State for example, add in some logic so that it checks if they are still valid before doing anything with them – as the whole game state may have changed, causing for run-time errors.
Many examples of automatically updating plugins can be found in the Flixel Power Tools, such as the FlxMouseControl plugin. When registered this plugin monitors the mouse every step. It records the number of times you’ve clicked, the distance travelled, calculates the average mouse movement speed and more. As it works off values that are updating ever step, it makes sense to make this an automatically updating plugin.
Standard Class Plugin
This type of plugin is a normal class. It can extend any base type that you need, and doesn’t need registering with addPlugin. In fact it doesn’t even have to live in the plugins folder, although for consistency I would recommend it. These sorts of plugin don’t have their update/draw methods called automatically, in fact they don’t even need to have them.
An example of this type of plugin is FlxBitmapFont. It extends FlxSprite and has lots of methods for creating a bitmap font sprite. You can then add an instance of this to your game, update it, move it and do anything you’d usually do to an FlxSprite, plus all of the extra functionality coded into the class. Because it extends FlxSprite when its added to a State Flixel will automatically call its update method every step. This happens in the normal processing flow however, it doesn’t fall into the “pre-update” block that an automatic plugin would.
Static Class Plugin
The only difference between this and Standard Class Plugin is that the methods inside it are static. This means that you don’t have to create an instance of the plugin, you can simply hit methods directly once it is imported, i.e.:
var maskedSprite:FlxSprite = new FlxSprite;
FlxDisplay.alphaMask(sourcePNG, maskPNG, maskedSprite);
In the above we create an FlxSprite and then pass it to the alphaMask function, which is a static method within FlxDisplay (that lives in the plugins folder). This merges a source and mask PNG into the sprite. Then we send the sprite to FlxDisplay.screenCenter which modifies its x/y coordinates to ensure it’s centred horizontally in the camera.
Static classes are very useful when you don’t need an instance of the class, i.e. it’s just full of typically one-hit helper methods. These sorts of plugins are almost never updated on a regular step.
Creating a simple plugin
Let’s step through creating a plugin. Our plugin is going to create a mirror effect, by taking the camera bitmap and flipping it vertically, then applying a shade over the top.
Because it’s an auto-updating plugin it needs to extend FlxBasic. Here is the base FlxCameraMirror.as file:
public class FlxCameraMirror extends FlxBasic
public function FlxCameraMirror()
This plugin is going to work as follows:
- You create it by giving it an FlxCamera, a height and a ColorTransform tint
- Every step it takes “height” number of pixels from the camera, flips them vertically and applies the color tint
- The flipped pixels are re-assigned to an FlxSprite which is in the State, displaying the reflected camera
The constructor is changed to:
public function FlxCameraMirror(source:FlxCamera, height:uint, color:ColorTransform)
sourceCamera = source;
reflection = new FlxSprite;
reflection.makeGraphic(source.width, height, 0x0);
reflection.scrollFactor.x = 0;
reflection.scrollFactor.y = 0;
tempBitmapData = reflection.pixels;
shade = color;
camRect = new Rectangle(0, source.height – height, source.width, height);
You can see the camera, height and color tint values being passed in. reflection is the FlxSprite into which the mirrored camera will be drawn, it’s what you add to your display list. camRect is a helper var to avoid us dynamically creating a new Rectangle() every update.
The update method is:
override public function update():void
// Copy the bottom part of the Camera buffer into our temp bitmap data
tempBitmapData.copyPixels(sourceCamera.buffer, camRect, zeroPoint);
// Then flip it and apply the tint
tempBitmapData = flipBitmapData(tempBitmapData);
// Set the sprite data to the flipped cam image
reflection.pixels = tempBitmapData;
The comments explain what happens. flipBitmapData is a method within the class that does a simple matrix transform and draw on the bitmapData, applying the color tint as it does so. You can view the whole thing in the source download at the end.
In order to use the plugin in our platform game we have to activate it and add the reflection to the display. This code is taken from the PlayState.as file (also available in the download zip)
if (FlxG.getPlugin(FlxCameraMirror) == null)
var blueTint:ColorTransform = new ColorTransform(0.5, 0.5, 1);
FlxG.addPlugin(new FlxCameraMirror(playerCam, 120, blueTint));
FlxCameraMirror.reflection.y = 120;
You’ll notice that reflection is a static var in FlxCameraMirror, this is just so we can access it easily. Feel free to do whatever you need in your own code.
So all of the above is going to create an FlxSprite. This sprite is positioned at Y 120 on the screen (it has a scrollFactor of zero, so it doesn’t move). Every update the plugin takes a copy of the playerCam (an FlxCamera), copies it, flips it, tints it and throws it back into the FlxSprite again. The result is a mirrored camera that looks like this:
[swfobj src=”http://www.photonstorm.com/wp-content/uploads/2011/11/NutmegCameraMirror.swf” width=”640″ height=”480″ align=”none” allowfullscreen=”false”]
Have a play. Cursors to run, space to jump.
Of course this is just the beginning. There’s no reason why you couldn’t update the ColorTransform each step to produce a nice trippy colour effect. Or perform a pixel distortion on the FlxSprite, perhaps rippling it to look like water? Or it could even be a gameplay mechanic – so certain sprites are only visible in the mirrored world, and actions performed “above” influence the map below.
The options are endless, as they say in marketing class 🙂
Download a zip file contain the whole project, including assets, FlashDevelop project, plugin and swf.
Share and Enjoy!
Now you understand how plugins work, and how to make them – why not go ahead? and then share whatever you make with the flixel community.
Post them up to the Flixel forums for the benefit of all.
8 ResponsesLeave a comment
Make yourself heard
All about Photon Storm and our
HTML5 game development services
Filter our Content
- Cool Links
- Flash Game Dev Tips
- Game Development
- Geek Shopping
- In the Media
- Phaser 3