Personal tools
shadowfax.org.uk logo
Views

Particle Blur Trail

From Shadowfax

Jump to: navigation, search

ActionScript 3 Blur Trail

You can change the speed with the up and down arrow keys, and the jitter with the left and right arrow keys (you will probably need to click on the Flash before the keys start working).

This is a simple particle blur trail. When I started ActionScript programming I found a number of useful resources, including an excellent blur filter demo on kokosan.com (which sadly no longer appears to be there). It used a large blur filter, however, which soon became a memory issue for my application. So I rewrote it from the ground up to use a particle system. This is the result.

As the speed of the blur or the magnitude of the jitter increase, the blur turns into less of a blur, and the discrete circles become more visible. This could be easily be fixed by adding more particles to cover the gaps.

package  
{
  import flash.display.BitmapData;
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.display.Bitmap;
  import flash.events.Event;
  import flash.events.KeyboardEvent;
  import flash.filters.BlurFilter;
  import flash.geom.Point;
  import flash.geom.Rectangle;
  import flash.text.TextField;
  import flash.text.TextFormat;
  import flash.utils.setInterval;
  import flash.utils.getTimer;
  import flash.system.System;
 
  public class ParticleBlur extends Sprite
  {
    // framespeed monitor variables
    private var iMonitor:TextField = new TextField;
    private var iSpdMon:TextField = new TextField;
    private var iFrames:int = 0;
    private var iLastTime:int = 0;
    private var iRunningTot:Number =0;
    private var iAveOver:int = 0;
 
    private const particleSize:Number = 8;
    private const pbmFrameFactor:Number = 3;
    private const pbmHalfFrameFactor:Number = pbmFrameFactor/2;
    private const blurAmount:Number = 2
 
    private var centerPt:Point = new Point(particleSize, particleSize); 
 
    private var vanillaParticle:BitmapData = new BitmapData(particleSize, particleSize,true,0x000000);
    private var pRect:Rectangle = new Rectangle(0, 0, particleSize, particleSize);
    private var bRect:Rectangle = new Rectangle(0, 0, particleSize * pbmFrameFactor, particleSize * pbmFrameFactor);
    private var blurEffect:BlurFilter = new BlurFilter(blurAmount, blurAmount, 1);
    private var effectPt:Point = new Point(0, 0);
 
    private var pArr:Array = new Array();
    private var curP:int = 0;
    private var ix:Number = 0;
    private var iy:Number = 80;
 
    private var speed:Number = 1.0;
    private var dirX:Number = 1;
    private var dirY:Number = 1;
    private var jitter:Number = 1.0;
 
    private var iNumParticles: int = 70;
 
    public function ParticleBlur() 
    {
      var pCircle:Shape = new Shape()
      pCircle.graphics.beginFill(0xffffff);
      pCircle.graphics.drawCircle(particleSize * .5, particleSize * .5, particleSize * .5);
      pCircle.graphics.endFill();
      vanillaParticle.draw(pCircle);
 
      // Frame rate monitor
      iMonitor.defaultTextFormat = new TextFormat("Arial", 11,0x000000,true);
      iMonitor.width = 400;
      addChild(iMonitor);
 
      iSpdMon.defaultTextFormat = new TextFormat("Arial", 11,0x000000,true);
      iSpdMon.x = 350;
      iSpdMon.width = 200;
      iSpdMon.text = "Speed = " + speed.toFixed(1) + ". Jitter = " +  jitter.toFixed(1) + ".";
      addChild(iSpdMon);
 
      //Kick off the events
      addEventListener(Event.ENTER_FRAME, perFrame, false, 0, true);
      stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
      setInterval(UpdateMonitor, 1000);
    }
 
    private function keyDown(e:KeyboardEvent):void
    {
      if (e.keyCode == 38) speed += .1;
      if (e.keyCode == 40) speed -= .1;
      if (e.keyCode == 37) jitter -= .2;
      if (e.keyCode == 39) jitter += .2;
 
      iSpdMon.text = "Speed = " + speed.toFixed(1) + ". Jitter = " +  jitter.toFixed(1) + ".";
    }
 
    private function NewParticle():Bitmap
    {
      var pbmd:BitmapData = new BitmapData(particleSize * pbmFrameFactor, particleSize * pbmFrameFactor,true,0x000000);
      var pbm:Bitmap = new Bitmap(pbmd);
 
      return pbm;
    }
 
    private function perFrame(e:Event):void
    {
      var tBMD:BitmapData;
      var tBM:Bitmap;
 
      if (pArr.length <= curP)
      {
        pArr[curP] = NewParticle();
        addChild(Bitmap(pArr[curP]));
      }
 
      tBM = Bitmap(pArr[curP])
      tBM.bitmapData.copyPixels(vanillaParticle, pRect, centerPt);
 
      ix += dirX * speed;
      iy += dirY * speed;
 
      if (ix >= stage.stageWidth || ix <= 0 ) dirX = -dirX;
      if (iy >= stage.stageHeight || iy <= 0 ) dirY = -dirY;
 
      tBM.x = ix + (Math.random()*jitter)-jitter/2
      tBM.y = iy + (Math.random()*jitter)-jitter/2
 
      curP++;
      if (curP >= iNumParticles) curP = 0;
 
      for (var i:int = 0; i < pArr.length; i++) 
      {
        tBMD = Bitmap(pArr[i]).bitmapData
        tBMD.applyFilter(tBMD, bRect, effectPt, blurEffect);
      }
      iFrames++
    }
 
    private function UpdateMonitor():void
    {
      var t:int = getTimer();
      var elapsed:int = t-iLastTime;
      var fps:Number = 1000 * iFrames / elapsed;
      iRunningTot += fps;
      iAveOver++;
 
      iMonitor.text = "Mem: " + String(Math.round(System.totalMemory/104857.6)/10) + "Mb FPS " + String(Math.round(100 * fps) / 100) +
                      " : " + String(Math.round(100*iRunningTot/iAveOver)/100)
      iFrames = 0;
 
      iLastTime = t;
    }
  }
}


Leave your comment

Menu