flash on 2011-12-3

by amashio
♥0 | Line 117 | Modified 2011-12-03 04:17:02 | MIT License
play

ActionScript3 source code

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

package {

    import aether.utils.ImageUtil;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filters.BlurFilter;
    import flash.filters.DisplacementMapFilter;
    import flash.filters.DisplacementMapFilterMode;
    import flash.filters.GradientGlowFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;

    [SWF(width=420, height=200, backgroundColor=0x000000)]

    /**
    * 炎をあらゆるオブジェクトからダイナミックに生成する方法を示すサンプル。
    * ここではダイナミックテキストを使用。時間経過にともなう一定の間隔で着色し直し歪曲させることで、炎の錯覚を生み出す
    */
    public class BurningLetters extends Sprite {

        // 炎を移動させるレート
        private static const FLICKER_RATE:Number = 10;

        private var _blackField:TextField;
        private var _flame:BitmapData;
        private var _perlinNoise:BitmapData;
        private var _perlinOffsets:Array;
        private var _perlinSeed:int;

        /**
        * コンストラクタ。テキストフィールドと炎のアニメーションに使用する火を作成し、ノイズのプロパティを設定。
        * アニメーション用のハンドラを設定
        */
        public function BurningLetters() {
            makeFlame();
            makeFields();
            makeNoise();
            addEventListener(Event.ENTER_FRAME, onSpriteEnterFrame);
        }

        /**
        * 炎の描画に使用するビットマップデータを作成
        */
        private function makeFlame():void {
            // 火のイメージはステージと同サイズで完全に透明
            _flame = new BitmapData(
                stage.stageWidth,
                stage.stageHeight,
                true,
                0x00000000
            );
            addChild(new Bitmap(_flame));
        }

        /**
        * テキストフィールドを2つ作成。1つは炎用のグラデーショングロー用、もう1つは黒いテキスト用
        */
        private function makeFields():void {
            var field:TextField = createField();
            field.filters = [
                new GradientGlowFilter(
                    0,
                    45,
                    [0xFF0000, 0xFFFF00],
                    [1, 1],
                    [50, 255],
                    15,
                    15
                )
            ];
            _blackField = createField();
        }

        /**
        * 炎の土台に使用するテキストフィールドを作成する
        *
        * @return 作成したテキストフィールド
        */
        private function createField():TextField {
            var field:TextField = new TextField();
            field.autoSize = TextFieldAutoSize.LEFT;
            field.selectable = false;
            // Impactがインストールされていることを確認
            field.defaultTextFormat = new TextFormat("Impact", 80);
            field.text = "HOT STUFF";
            field.x = (stage.stageWidth - field.width)/2;
            field.y = stage.stageHeight - field.height;
            addChild(field);
            return field;
        }

        /**
        * 炎のアニメーションで使用するPerlinノイズのプロパティを初期化
        */
        private function makeNoise():void {
            // ノイズのビットマップデータは炎のビットマップデータと同サイズ
            _perlinNoise = _flame.clone();
            _perlinSeed = int(new Date());
            // オクターブを2つにするので、2つのPointが必要
            _perlinOffsets = [new Point(), new Point()];
        }

        /**
        * Perlinノイズをビットマップデータに適用。
        * このメソッドが呼び出されるたびに、FLICKER_RATE分だけオクターブを補正
        */
        private function applyNoise():void {
            _perlinNoise.perlinNoise(
                50,
                30,
                2,
                _perlinSeed,
                false,
                true,
                BitmapDataChannel.RED,
                true,
                _perlinOffsets
            );
            // オフセットの変更によって、炎は上方向にアニメーションする
            (_perlinOffsets[0] as Point).y += FLICKER_RATE;
            (_perlinOffsets[1] as Point).y += FLICKER_RATE/2;
        }

        /**
        * 毎フレーム炎のビットマップデータを更新し、アニメーションを作成する
        */
        private function drawFlame():void {
            // 現在のステージのイメージを炎のビットマップデータに、明るさとアルファを少し小さくして描画
            _flame.draw(
                stage,
                null,
                new ColorTransform(.9, .9, .9, .7)
            );
            // イメージを少しぼかす。ぼかし量はy方向を大きくする
            ImageUtil.applyFilter(
                _flame,
                new BlurFilter(3, 5)
            );
            // 炎のイメージを少し移動して、炎の上方向への動きを作成
            _flame.scroll(0, -4);
            // 変更したオフセットを使って新しいPerlinノイズを適用
            applyNoise();
            // 炎のイメージを更新したPerlinノイズで置き換える
            ImageUtil.applyFilter(
                _flame,
                new DisplacementMapFilter(
                    _perlinNoise,
                    new Point(),
                    BitmapDataChannel.RED,
                    BitmapDataChannel.RED,
                    1,
                    10,
                    DisplacementMapFilterMode.CLAMP
                )
            );
        }

        /**
        * ENTER_FRAMEイベント用ハンドラ。炎を再描画する
        *
        * @param event このスプライトが送出するイベント
        */
        private function onSpriteEnterFrame(event:Event):void {
            // ステージ内容をビットマップデータに描画する前に、黒いテキストフィールドを一旦不可視にする。
            // これによって炎だけが描画されるようになる
            _blackField.visible = false;
            drawFlame();
            _blackField.visible = true;
        }

    }

}