Blitting a particle transition between two images
This article is about Actionscript and was originally posted on my personal blog 6 years ago.
Sometimes when you are experimenting around with flash, you’ll notice that things can get a little laggy when you put too many things on the stage and try to move them around at the same time. The Display List is a very fast and easy way to handle the way things are displayed on the screen, but to you have to sacrifice some performance.
So why does the framerate in flash drop when you want to move +1000 MovieClips around at the same time? If you go and take a look at the livedocs for the MovieClip class, you’ll see that not only does MovieClip extend a handful of classes ( Sprite >DisplayObjectContainer > InteractiveObject > DisplayObject > EventDispatcher >Object), it also has loads of properties like .currentFrame and methods like gotoAndPlay(). These are all very welcome when you want to make use of them, but when you just want to display basic things, this is not the way to go.
One solution is using a Sprite (losing the timeline functionalities) or even a DisplayObject, the most basic class that Flash can display on its DisplayList. Another solution is using a technique called Blitting. There is an excellent article over at Adobe Developer Connection explaining the basics behind this technique.
In short, the reason why this technique is so fast, is that it skips the DisplayList entirely. When you draw something on-screen using the blitting technique, you copy a rectangular part of a bitmap straight to another bitmap. The first bitmap being offscreen, the second one on your stage.
For example, you tell flash to copy a rectangle with width=100 and height=100 at position x=0 and y=0, to your stage at position x=20 and y=20. This will now display a square with sides of 100pixels, containing whatever was in the upper-left corner of your off-screen bitmap, on your stage at position (20,20). Take a look at the following example to get a better idea:
Blitting is really powerful when implemented in games. When you are animating a character, blitting the animation can easily give you a performance increase by factor 10.
I did an intro a couple of years ago for the Interational Centre for Art & New Technologies, and in an early version of the current intro there was a transition between 2 logos using pre-sliced particles. I always wanted to do this again without the need of slicing the logos and with more particles, but I realised that performance would be an issue. A few years later I learned about blitting and familiarized myself with BitmapData & friends and the Synergy class was born in the process.
The Synergy class is initialized with the stage property of your Document class, and has a method called loadItems() that accepts 2 DisplayObjects — one sourceObject and one targetObject. What happens next is that after calling the Synergy.explode() method, the sourceObject dissolves in all the pixels that make up the object, fly away and then join together in the targetObject.
Now let’s take a look at what is happening behind the screens. There were a couple of challenges that I encountered and things I learned while working on this project, so read on for some highlights or just dive into the source code.
A closer look at the drawing technique
The first thing that happens in the loadItems() method, is parsing of the DisplayObjects. By parsing I mean analyzing every pixel, checking it for alpha value (when the alpha value is 0, you don’t need to move it around because, well, it’s transparent). for every pixel that is worth moving around, an object from the ‘Particle’ class is created. This class contains some essential info about the pixel:
- Its original position (“sourceX,sourceY” >> we will need these later on, when we are blitting FROM the offscreen object)
- Its current position (“x,y” >> indicates the position on the stage where we will copy TO.
- Its target position (“targetX,targetY” >> which will indicate the position where the pixel will have to move to)
- A reference to the DisplayObject where the pixel came from. (a variable called “copyBitmapData”)
All these particles get placed in a list, and are drawn on the screen 31 times per second, on the ENTER_FRAME event. Let’s take a look at the function that draws our pixels on the screen:
private function drawStuff(e:Event):void
canvasData.fillRect(canvasData.rect, 0xFFFFFF) // clear the canvas before drawing
var lli : ILinkedListIterator = sourceList.iterator() as ILinkedListIterator;
item = lli.current;
copyP.x = item.x; copyP.y = item.y;
copyR.width = copyR.height = particleSize;
copyR.x = item.sourceX; copyR.y = item.sourceY;
canvasData.copyPixels(item.copyBitmapData, copyR, copyP);
“copyP” is a Point object and “copyR” is a Rectangle object. These two objects are essential parameters for the copyPixels method. the “copyR” rectangle defines the area that will be copied to the stage (see examples above) and the “copyP” point defines the position that this rectangle will get on the stage. item.copyBitmapData is the reference to the DisplayObject where the pixels will be copied from.
the item.update() method returns a Boolean, which is false when the particle is still swarming around randomly. Yet when this function returns true, it means that the particle has come to a standstill, and that it needs a destination. The method getNewTarget will give this particle a destination to Tween to. Notice that in this case we are not tweening a DisplayObject -which is usually the case- but we will be tweening the X and the Y properties of the Particle object.
the Pixel32 class
When you extract pixel information from a bitmap, you can do so using the BitmapData.getPixel32() method. This returns an unsigned integer, ranging from 0 (0x00000000) to 4294967295 (0xFFFFFFFF). To make my life a little bit easier I created the Pixel32 class. You can create a new Pixel32 object by instantiating it with the color value and then reading the public properties alpha,red,green or blue, or you can make use of the static functions. These include:
- toString(): this will return a string, for example “OxFFOOFFOO — Alpha: FF — Red: 0 — Green: FF- Blue: 0”;
- isWhite(): this will return a Boolean that tells you wether or not the pixel is white.
- isTransparent(): this will return a Boolean that tells you wether or not the pixel is 100% transparent.
- getAlpha(), getRed(), getGreen(), getBlue()
Some random optimisations
- Declare your variables outside of for/while loops. You will noticed a huge increase in performance when doing this. If you take a look at the code above, you’ll see that I declare “var item:Particle” just once, before the loop, and then re-use this variable, instead of declaring it over and over again inside of the while loop.
- Using a LinkedList instead of an Array is a great way to increase performance, when iterating through the list is the most important thing and random access of items in the list is not necessary.
I hope you had as much fun reading this blogpost as I had making it! If you have any questions about this post, or if you have tips to improve my code or the application performance, please use the comments section below.
Like this post ? Follow me on Twitter !