Skip to main content
Kh7
Participant
May 14, 2010
Question

Waving flag

  • May 14, 2010
  • 5 replies
  • 11420 views

Hi,

it is possible to create a waving flag effect from the image in Flash using ActionScript 3?

How can I do that? I found a lot of topics like this, but have not found a solution

This topic has been closed for replies.

5 replies

March 3, 2011

I know this is a bit late for this post, but I made an updated AS3 version with source here http://pixelpaton.com/?p=128

Cheers,

Terry

Inspiring
June 2, 2010

Several examples of this are done with use of perlinNoise. Here is the link to the chapter of ActionsScript 3 Image Effects that describes exactly that:

http://books.google.com/books?id=lXqBDRKsA4MC&pg=PA436&lpg=PA436&dq=as3+bitmapdata+waving+flag&source=bl&ots=2Zp-kQDpI1&sig=UQw3u-strJa-Y3HDqPIteoBtqpA&hl=en&ei=w0QGTL6HAYO8lQfe8uTxCg&sa=X&oi=book_result&ct=result&resnum=8&ved=0CDcQ6AEwBw#v=onepage&q&f=false

Here is the class:

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 FlagWaving extends 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 FlagWaving() {
               super("../../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.
          *
          * @param event Event dispatched by this sprite.
          */
          private function onSpriteEnterFrame(event:Event):void {
               waveFlag();
          }

     }

}

June 2, 2010

Hi, Have you found an answer?, im looking for the same. Seems to be loads AS2 versions but no AS3. Thanks, J

kglad
Community Expert
Community Expert
May 14, 2010

this is probably as2 so you'll need to update or use google to see if you find more suitable:

http://lab.andre-michelle.com/swf/f8/flag.zip

May 14, 2010