topical media & game development
#graphic-flex-image-effects-08-Flex-FlagWaving.ax
#graphic-flex-image-effects-08-Flex-FlagWaving.ax
[swf]
[flash]
flex
package {
import aether.utils.ImageUtil;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.GradientType;
import flash.display.Shape;
import flash.events.Event;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
[SWF(width=420, height=280, backgroundColor=0xBEEBF0)]
Demonstrates the use of Perlin noise and a displacement map to animate an image
of a flag waving in the wind. In order to limit the amount of displacement,
a gradient is drawn into the displacement map using medium gray.
public class @ax-graphic-flex-image-effects-08-Flex-FlagWaving extends graphic_flex_image_effects_08_Flex_AbstractImageLoader {
// controls how fast flag will flap
private static const WIND_RATE:Number = 30;
private var _gradient:BitmapData;
private var _flag:BitmapData;
private var _perlinNoise:BitmapData;
private var _perlinOffsets:Array;
private var _perlinSeed:int;
Constructor. Sends path of asset to super class to load.
public function @ax-graphic-flex-image-effects-08-Flex-FlagWaving() {
super("graphic-flex-image-effects-08-assets-flag.png");
}
Called after super class loads image. This creates assets and sets up
handler for animation.
override protected function runPostImageLoad():void {
makeFlag();
makeGradientOverlay();
makeNoise();
addEventListener(Event.ENTER_FRAME, onSpriteEnterFrame);
}
Uses the loaded image of the flag, then uses the drawing API to create
a pole and cords to attach to the flag.
private function makeFlag():void {
var stageWidth:Number = stage.stageWidth;
var stageHeight:Number = stage.stageHeight;
var bitmapData:BitmapData = _loadedBitmap.bitmapData;
var bitmapWidth:Number = bitmapData.width;
var bitmapHeight:Number = bitmapData.height;
// settings for the size and position of pole
var poleWidth:Number = 15;
var poleHeight:Number = 250;
var poleX:Number = 35;
var poleY:Number = stageHeight - poleHeight;
// draws a horizontal linera gradient for the pole
var matrix:Matrix = new Matrix();
matrix.createGradientBox(poleWidth, poleHeight);
var pole:Shape = new Shape();
pole.graphics.beginGradientFill(
GradientType.LINEAR,
[0x333333, 0x999999, 0xCCCCCC, 0xAAAAAA, 0x666666],
[1, 1, 1, 1, 1],
[0, 50, 160, 200, 255],
matrix
);
pole.graphics.drawRect(0, 0, poleWidth, poleHeight);
pole.graphics.endFill();
pole.x = poleX;
pole.y = poleY;
addChild(pole);
// point at top left of flag
var point:Point = new Point(
(stageWidth - bitmapWidth)/2,
(stageHeight - bitmapHeight)/2
);
// draws two cords from pole to flag's left side
var cord:Shape = new Shape();
cord.graphics.lineStyle(2, 0x333333);
cord.graphics.moveTo(poleX, poleY+3);
cord.graphics.lineTo(point.x, point.y);
cord.graphics.moveTo(point.x, point.y + bitmapHeight);
cord.graphics.lineTo(poleX, poleY + bitmapHeight+20);
// draws cord shape into bitmap data with flag, so that all can be distorted
_flag = new BitmapData(stageWidth, stageHeight, true, 0x00000000);
_flag.draw(cord);
_flag.copyPixels(bitmapData, bitmapData.rect, point);
_loadedBitmap.bitmapData = _flag;
addChild(_loadedBitmap);
}
Creates the bitmap data that will be used to draw into the displacement
map in order to limit the amount of distortion. This is accomplished by
drawing a gradient of medium gray going from full opacity to none over the
left side of the displacement map, preventing displacement on the left of the image.
private function makeGradientOverlay():void {
var width:Number = stage.stageWidth;
var height:Number = stage.stageHeight;
var matrix:Matrix = new Matrix();
matrix.createGradientBox(width, height);
var shape:Shape = new Shape();
shape.graphics.beginGradientFill(
GradientType.LINEAR,
[0x7F7F7F, 0x7F7F7F],
[1, 0],
[20, 80],
matrix
);
shape.graphics.drawRect(0, 0, width, height);
shape.graphics.endFill();
// draw gradient shape into bitmap data for use later
_gradient = new BitmapData(width, height, true, 0x00000000);
_gradient.draw(shape);
}
Initializes Perlin noise properties that will be used in flame animation.
private function makeNoise():void {
_perlinNoise = new BitmapData(stage.stageWidth, stage.stageHeight);
_perlinSeed = int(new Date());
// only one octave requires only one point
_perlinOffsets = [new Point()];
}
Applies the Perlin noise to the bitmap data, offsetting the octave displacement
by the WIND_RATE each time this method is called.
private function applyNoise():void {
_perlinNoise.perlinNoise(
200,
200,
1,
_perlinSeed,
false,
true,
BitmapDataChannel.RED,
true,
_perlinOffsets
);
// altering offset contributes to horizontal animation of flag
(_perlinOffsets[0] as Point).x -= WIND_RATE;
}
Redraws the flag with new distortion to create animated effect of flapping.
private function waveFlag():void {
// generate new Perlin noise
applyNoise();
var flag:BitmapData = _flag.clone();
// copy the gradient overlay to limit the displacement
_perlinNoise.copyPixels(
_gradient,
_gradient.rect,
new Point(),
_perlinNoise,
new Point(),
true
);
// displace original flag with new displacement map
ImageUtil.applyFilter(
flag,
new DisplacementMapFilter(
_perlinNoise,
new Point(),
BitmapDataChannel.RED,
BitmapDataChannel.RED,
40,
60
)
);
// copy the alpha channel from the noise into the flag
ImageUtil.copyChannel(flag, _perlinNoise, BitmapDataChannel.ALPHA);
// overlay the displacement map for a lighting effect using darks and lights
flag.draw(
_perlinNoise,
null,
new ColorTransform(1, 1, 1, 0.5),
BlendMode.HARDLIGHT
);
_loadedBitmap.bitmapData = flag;
}
Handler for ENTER_FRAME event. Redraws flag.
parameter: event Event dispatched by this sprite.
private function onSpriteEnterFrame(event:Event):void {
waveFlag();
}
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.