package { import aether.effects.transformations.TranslateEffect; import aether.utils.Adjustments; import aether.utils.ImageUtil; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.BlendMode; import flash.display.Sprite; import flash.events.Event; import flash.filters.BlurFilter; import flash.geom.Matrix; import flash.geom.Point; [SWF(width=550, height=400, backgroundColor=0xABC8D2)] /** * Demonstrates how snowfall can be simulated using multiple planes of bitmap data * overlaid and animated at different rates. */ public class graphic_flex_image_effects_08_Flex_Snowfall extends Sprite { private static const NUM_PLANES:uint = 3; private static const VERTICAL_MOVEMENT_RATE:Number = 0.3; private static const HORIZONTAL_MOVEMENT_RATE:Number = 0.05; // the amount the snow planes should move back and forth horizontally private static const HORIZONTAL_MOVEMENT_RANGE:Number = 20; private var _snowPlanesData:Vector.; private var _snowPlanesBitmaps:Vector.; private var _angles:Vector.; private var _verticalOffsets:Vector.; /** * Constructor. Creates assets and sets up ENTER_FRAME handler for animation. */ public function graphic_flex_image_effects_08_Flex_Snowfall() { makeSky(); makeSnowPlanes(); addEventListener(Event.ENTER_FRAME, onSpriteEnterFrame); } /** * Creates the bitmap data with the sky image. */ private function makeSky():void { var sky:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight); sky.perlinNoise(250, 200, 3, Math.random(), false, true, BitmapDataChannel.RED, true); Adjustments.setLevels(sky, 0, 150, 240); var bitmap:Bitmap = new Bitmap(sky); // overlay clouds over colored background bitmap.blendMode = BlendMode.SCREEN; addChild(bitmap); } /** * Creates the multiple planes that will be used for the snow. */ private function makeSnowPlanes():void { // save the data into vectors to be used in animation _snowPlanesData = new Vector.(); _snowPlanesBitmaps = new Vector.(); _angles = new Vector.(); _verticalOffsets = new Vector.(); var width:Number = stage.stageWidth; var height:Number = stage.stageHeight; var bitmapData:BitmapData; var bitmap:Bitmap; // create all of the planes based on the NUM_PLANES constant for (var i:uint = 0; i < NUM_PLANES; i++) { // create texture -- the third argument is the density of the plane, the fourth the scale of the flakes bitmapData = getSnowPlane(width, height, 0.05 + 0.001*i, i+1); _snowPlanesData.push(bitmapData); bitmap = new Bitmap(bitmapData.clone()); // all planes should just overlay their lighter elements over planes and sky below bitmap.blendMode = BlendMode.SCREEN; _snowPlanesBitmaps.push(bitmap); addChild(bitmap); // each plane starts its animation off at a different angle _angles.push(Math.PI/NUM_PLANES*i); _verticalOffsets.push(0); } } /** * Generates a snow texture using a pixel dissolve that is scaled up and a blur. * * @param density Controls the amount of flakes that should appear. * * @return The bitmap data created. */ private function getSnowPlane(width:Number, height:Number, density:Number, scale:Number):BitmapData { var snow:BitmapData = new BitmapData(width, height, true, 0x00000000); var dissolve:BitmapData = snow.clone(); // pixel dissolve transparent image to a white color to create white dots dissolve.pixelDissolve(dissolve, dissolve.rect, new Point(), int(Math.random()*255), width*height*density, 0xFFFFFFFF); // scale up dissolve so that dots become larger and blurred var matrix:Matrix = new Matrix(); matrix.scale(2*scale, 2*scale); snow.draw(dissolve, matrix, null, null, null, true); // blur it more ImageUtil.applyFilter(snow, new BlurFilter(4, 4)); return snow; } /** * Handler for ENTER_FRAME to control animation of multiple planes of bitmap data. * * @param event Event dispatched by this sprite. */ private function onSpriteEnterFrame(event:Event):void { var x:Number; for (var i:uint = 0; i < NUM_PLANES; i++) { // each plane is animated using sine values x = Math.sin(_angles[i]) * HORIZONTAL_MOVEMENT_RANGE; // planes move vertically at different rates based on their depth _verticalOffsets[i] += (VERTICAL_MOVEMENT_RATE + (i*VERTICAL_MOVEMENT_RATE)/2); // translate the original data, not the previously translated data var clone:BitmapData = _snowPlanesData[i].clone(); new TranslateEffect(x, _verticalOffsets[i], true, 0x000000, true).apply(clone); // put new data in bitmap _snowPlanesBitmaps[i].bitmapData = clone; _angles[i] += HORIZONTAL_MOVEMENT_RATE; } } } }