efficient pixel particles

by hemingway
flash & math author's demo

successfully handles 200,000+ particles and maintains 60+ fps. modify numParticles to 500,00 for ~30 fps stress test
♥0 | Line 122 | Modified 2013-01-03 04:23:05 | MIT License
play

ActionScript3 source code

/**
 * Copyright hemingway ( http://wonderfl.net/user/hemingway )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rc5t
 */

package
{
    import net.hires.debug.*;
    import flash.display.*;
    import flash.filters.*;
    import flash.system.*;
    import flash.events.*;
    import flash.utils.*;
    import flash.geom.*;

    [SWF(frameRate = 60)]
    public class main extends Sprite
    {
        /*
        We will create 200,000 particles. This little application will run fine with as many as 500,000 particles.
        */
        var numParticles:Number = 200000;
        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 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;
 
        function main()
        {
            display = new Sprite();
            this.addChild(display);
            this.addChild(new Stats);
        
            //Size of the bitmap:
            displayWidth = 465;
            displayHeight = 465;
        
            //'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);
            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.lock();
            p = firstParticle;

            do
            {
                if (mouseX)
                {
                   p.x += mouseX;
                    p.y += mouseY; 
                }else{
                    p.x += 5;
                }


                
                bmpData.setPixel32(p.x, p.y, p.color);
                p = p.next;
            } while (p != null)
        
            bmpData.unlock();
        }

        function onClick(evt:MouseEvent) :void
            {}

        /*
        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 = (Math.random()-15)/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, 0);
            back.graphics.beginFill(c);
            back.graphics.drawRect(0,0,displayWidth,displayHeight);
            back.graphics.endFill();
        }
    }    
}

import flash.geom.Point;

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;
    }
}