Example and Code

One of the most common tools used in particle effects are pixel or bitmap particles; that is, tiny one pixel dots. In this tutorial we explain the nature of pixel particles. Curiously, such particles are not display objects. We give a simple example that shows how to create and move particles and how to make particles leave shadowy trails. Click the screen shot below or this link to open the effect in a new window:

Download

Download the well-commented source files corresponding to the effect above:

Comments

The main point that needs to be emphasized is that a 'pixel particle' is not a display object. A particle has has a 32-bit 0xAARRGGBB color and an xy-position, and that is it. A particle appears on the screen because we assign its color to the pixel at the corresponding position in a Bitmap which is on the Display List. In our code this Bitmap is named 'bitmap'.

Coloring a pixel in a Bitmap is done via its BitmapData object and BitmapData.setPixel32 method. In our code the BimapData of 'bitmap' is named 'bmpData'.

The effect of motion is created by changing a particle's xy-position and coloring the pixel corresponding to the new position in 'bitmap'. The previously drawn particles blur and fade out thanks to a filter and a color transform applied to 'bmpData'.

To keep together all properties of each pixel it is convenient to create a custom AS3 class. We call our class Particle2D. One of the properties of the Particle2D class is 'next'. We use this property to create a 'list' of particles: firstParticle, its 'next' particle etc. We use such list instead of an array. With large number of particles, lists are faster than arrays.

In the simple example presented here, we use 1500 particles. You can set that number to 200,000 particles and the application will run smoothly.

Code

Below is the Timeline code in pixtut.fla. We keep comments within the code for greater clarity.

import com.flashandmath.particles.Particle2D;

/*
We will create 1500 particles. This little application will run fine with as many as 200,000 particles.
*/

var numParticles:Number = 1500;

var firstParticle:Particle2D;

/*
The display objects that will be created programmatically: a container 'display', a Bitmap 'bitmap', its bitmapData 'bmpData', and the background 'back'.
*/

var display:Sprite;

var bmpData:BitmapData;

var bitmap:Bitmap;

var back:Shape;

var displayWidth:Number;

var displayHeight:Number;

/*
Variables related to filters and transforms that we will apply to 'bmpData' on ENTER_FRAME to create trailing and fading effects.
*/

var origin:Point;

var blur:BlurFilter;

var colorTrans:ColorTransform;

/*
The next two variables are responsible for pausing and resuming the animation and the color of the background. Within the function 'init' we initialize all variables.
*/

var particlesGo:Boolean;

var bgColor:uint;

init();

 

function init():void {

display = new Sprite();

this.addChild(display);

display.x=50;

display.y=40;

//Size of the bitmap:

displayWidth = 400;

displayHeight = 300;

//'bitmap' is the bitmap that we will see, 'bmpData' is its bitmapData

//into which we will draw particles. 'bmpData' supports transparent pixels (true)

//and intially contains completely transparent black pixels (0x00000000).

bmpData = new BitmapData(displayWidth,displayHeight,true,0x00000000);

bitmap = new Bitmap(bmpData);

//A background to put underneath 'bitmap':

bgColor=0x000000;

back = new Shape();

drawBack(bgColor);

display.addChild(back);

display.addChild(bitmap);

blur = new BlurFilter(6,6);

blur.quality = BitmapFilterQuality.LOW;

colorTrans=new ColorTransform(1,1,1,1,0,0,0,-2);

origin = new Point(0,0);

//The function 'createParticles' creates a 'list' of 1500 particles.

createParticles();

this.addEventListener(Event.ENTER_FRAME, onEnter);

display.addEventListener(MouseEvent.CLICK,onClick);

particlesGo=true;

}

/*
On each ENTER_FRAME, we apply blur and a color transform to 'bmpData' to gradually blur and fade previously drawn particles. Then we loop through the list of particles. We calulate a new position p.x, p.y for each particle and then draw the particle at its new position into 'bmpData' via setPixel32 method. The simple equations of motion for p.x, p.y create a circular motion for each particle, with direction and angular velocity that depend on p.wc property of each particle (set in 'createParticles').
*/

function onEnter(evt:Event):void {

if(!particlesGo){return;}

var p:Particle2D = firstParticle;

bmpData.applyFilter(bmpData,bmpData.rect,origin,blur);

bmpData.colorTransform(bmpData.rect, colorTrans);

bmpData.lock();

p = firstParticle;

do {

p.y += p.wc*(p.x-displayWidth/2);

p.x += -p.wc*(p.y-displayHeight/2);

bmpData.setPixel32(p.x, p.y, p.color);

p = p.next;

} while (p != null)

bmpData.unlock();

}

 

function onClick(evt:MouseEvent):void {

particlesGo=!particlesGo;

}

/*
Within 'createParticles' we create a 'list' of particles: firstParticle, its 'next' etc. To each particle we assign a 32-bit, 0xAARRGGBB color with alpha 255 (0xFF), and the red, green and blue components chosen randomly. Thus, each of our particles is completely opaque and has random color. The wildcard property, p.wc, will determine the angular velocity for each particle.
*/

function createParticles():void {

var c:uint;

var lastParticle:Particle2D;

var i:int;

var r:uint;

var g:uint;

var b:uint;

var a:uint=0xFF;

for (i=0; i<numParticles; i++) {

r=Math.random()*0xFF;

g=Math.random()*0xFF;

b=Math.random()*0xFF;

c=((a << 24) | (r << 16) | (g << 8) | b);

var thisP:Particle2D = new Particle2D(c);

thisP.x = displayWidth/2*Math.random()+displayWidth/4;

thisP.y = displayHeight/2*Math.random()+displayHeight/4;

//We will use the wildcard property, 'wc', of the Particle2D class

//to adjust the speed and the direction of rotation of each particle.

thisP.wc = (2*Math.random()-1)/30;

//Create a 'list' of particles using the 'next' property of Particle2D:

if (i == 0) {

firstParticle = thisP;

}

else {

lastParticle.next = thisP;

}

lastParticle = thisP;

}

}

 

function drawBack(c:uint):void {

back.graphics.lineStyle(1,0x999999);

back.graphics.beginFill(c);

back.graphics.drawRect(0,0,displayWidth,displayHeight);

back.graphics.endFill();

}

Within the function createParticles and in the Particle2D class, we use bitwise shifts. For a simple tutorial on bitwise operators see: Extracting and Combining RGB Components, Custom Color Picker.

Particle2D Class

package com.flashandmath.particles {

import flash.geom.Point;

public class Particle2D extends Point {

//Linking:

public var next:Particle2D;

//Velocity and acceleration vectors

public var vel:Point = new Point();

public var accel:Point = new Point();

//Color attributes

public var color:uint;

public var red:uint;

public var green:uint;

public var blue:uint;

public var alpha:uint;

//Luminance

public var lum:Number;

//A wildcard property that you can use in your application if you need it.

public var wc:Number;

public function Particle2D(thisColor=0xFFFFFFFF){

this.color = thisColor;

this.red = ((thisColor >> 16) & 0xFF);

this.green = ((thisColor >> 8) & 0xFF);

this.blue = (thisColor & 0xFF);

this.alpha=((thisColor >> 24) & 0xFF);

this.lum = 0.2126*this.red + 0.7152*this.green + 0.0722*this.blue;

}

}

}

For another simple particle tutorial in which a particle is a Sprite written to a Bitmap see: Fading Trail Effect for Flash AS3 Particle Animations - a Simple Example.

A Few of Our Particle Effects

Back to Intermediate Tutorials              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.