In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

高速化実験:forked from: Blazing Effect

Blazing Effectの高速化実験
 ・家のノートPCでもそこそこの速度が出るように簡略化してみた

 対応
 ・パーリンノイズは毎回生成せずに、最初に一度だけ生成する
 ・代わりに2枚用意して、それぞれ逆方向にスクロールしたもので代用する
  ・1枚で十分かもしれない
/**
 * Copyright o_healer ( http://wonderfl.net/user/o_healer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gEJb
 */

// forked from alumican_net's Blazing Effect
// forked from tail_y's SmolderEffect

/*
 Blazing Effectの高速化実験
 ・家のノートPCでもそこそこの速度が出るように簡略化してみた

 対応
 ・パーリンノイズは毎回生成せずに、最初に一度だけ生成する
 ・代わりに2枚用意して、それぞれ逆方向にスクロールしたもので代用する
  ・1枚で十分かもしれない
*/

package
{
    /* しっぽのエフェクトと炎を組み合わせてみたよ
     * エフェクト終了後にクリックで赤、青、黒の三種類の炎が切り替わるよ
     * あと、とても重い
     * 
     **************************************************************************
     * 
     * カードが、ラスボスのように細かくなって消えていく演出。
     * カードグラフィックはエジエレキ(edielec)さんの作品だよ。
     * 次のゲームで使いたくて作ったけど、キラキラ部分がキラキラしすぎたので、その部分は消すかも。 
     */
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.display.DisplayObject;
    import flash.display.GradientType;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.ColorMatrixFilter;
    import flash.filters.ConvolutionFilter;
    import flash.filters.DropShadowFilter;
    import flash.filters.DisplacementMapFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.system.Security;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;

    public class BlazingEffect extends Sprite
    {
        // ステージ
        private const STAGE_W:uint   = 465;
        private const STAGE_H:uint   = 465;
        private const ZEROS:Point    = new Point(0, 0);
        private const RECT:Rectangle = new Rectangle(0, 0, STAGE_W, STAGE_H);
        
        // 設定
        private static const _CLOUD_SIZE:int           = 150;
        private static const _NUM_OCTVES:int           = 8;
        private static const _GRADIENT_STRENGTH:Number = 0.5;
        private static const _EFFECT_FRAME:int         = 200;
        private static const _FIRE_COLOR:uint          = 0xffffffff;
        private static const _PARTICLE_MOVE:int        = -1;
        private static const _PARTICLE_MARGIN:int      = 15;
        
        // URL
        private static const _CARD_URL:Array =
        [
            "http://asset.sipo.jp/wonderfl/img/smolderEffect/cardSample1.png",
            "http://asset.sipo.jp/wonderfl/img/smolderEffect/cardSample2.png",
            "http://asset.sipo.jp/wonderfl/img/smolderEffect/cardSample3.png"
        ];
        private static const _BG_URL:String    = "http://asset.sipo.jp/wonderfl/img/smolderEffect/bg1.jpg";
        private static const _BLAZE_URL:String = "http://lab.alumican.net/wonderfl/blazing_effect/color_map.png";
        
        // ロード
        private var _loadNum:int    = 0;
        private var _loadNumMax:int = 0;
        
        // 表示系
        private var _cardDisplayList:Array = [];
        private var _bgSprite:Sprite;    
        private var _displayData:BitmapData;
        private var _mainSprite:Sprite;    // エフェクト対象。これ自体は表示されない
        private var _display:Bitmap;
        
        // エフェクト要素
        private var _effectW:int;
        private var _effectH:int;
        private var _point:Point = new Point();
        private var _rect:Rectangle;
        private var _effectCount:int;
        private var _shadow:DropShadowFilter = new DropShadowFilter(2, 90, 0x000000, 0.5, 32, 32, 1, 3);
        
        // 使用画像
        private var _baseData:BitmapData;    // 最終的に表示されるビットマップ(加算以外)
        private var _clear:BitmapData;    // 消去用ビットマップ
        private var _black:BitmapData;    // 消去用ビットマップ(黒)
        private var _cloud:BitmapData;    // 雲
        private var _card:BitmapData;    // カードの部分
        private var _fire:BitmapData;    // 炎の部分
        private var _fireClear:BitmapData;
        private var _noise:BitmapData;
        
        // 炎
        private var _blazeIndex:int;
        
        private var _blazeEmitter:BitmapData;
        private var _blazeEffect:BitmapData;
        
        private var _blazeCooling1:BitmapData;
        private var _blazeCooling2:BitmapData;
        private var _blazeCoolingOffset:Array;
        
        private var _blazeSpreadFilter:ConvolutionFilter;
        private var _blazeColorFilter:ColorMatrixFilter;
        
        private var _blazePaletteSource:BitmapData;
        private var _blazePalette:Array;
        private var _zeroPalette:Array;
        
        public function BlazingEffect():void
        {
            addEventListener(Event.ADDED_TO_STAGE, init); // flexBuilderとの互換性。
            Wonderfl.capture_delay(15);//15秒後に実行
        }
        
        private function init(e:Event):void
        {
            // ここから開始
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            // SWF設定
            stage.frameRate = 30;
            stage.quality = StageQuality.LOW;
            
            // wonderflではキャプチャに背景色が反映されないので、背景を覆う。
            var bgBitmapData:BitmapData = new BitmapData(STAGE_W, STAGE_H, false, 0x888888);
            addChild(new Bitmap(bgBitmapData));
            
            _bgSprite = new Sprite();
            addChild(_bgSprite);
            
            _mainSprite = new Sprite();
            _display = new Bitmap();
            _display.filters = [_shadow];
            addChild(_display);
            
            Security.loadPolicyFile("http://asset.sipo.jp/wonderfl/crossdomain.xml");
            var context:LoaderContext = new LoaderContext(true);
            
            // カードグラフィックの読み込み
            for (var i:int=0; i < _CARD_URL.length; i++){
                var loader:Loader = new Loader();
                loader.contentLoaderInfo.addEventListener(Event.COMPLETE, cardLoadEnd);
                _loadNumMax++;
                loader.load(new URLRequest(_CARD_URL[i]), context);
            }
            
            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, bgLoadEnd);
            _loadNumMax++;
            loader.load(new URLRequest(_BG_URL), context);
            
            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, blazeLoadEnd);
            _loadNumMax++;
            loader.load(new URLRequest(_BLAZE_URL), context);
        }
        
        private function cardLoadEnd(e:Event):void
        {
            _cardDisplayList.push(e.target.content);
            countUp();
        }
        
        private function bgLoadEnd(e:Event):void
        {
            _bgSprite.addChild(e.target.content);
            countUp();
        }
        
        /**
         * 炎エフェクトの初期設定
         * Saqooshaさんのを元に、透過対応にしたりと改造して作ってます
         * http://wonderfl.net/code/bffb3437de866ffdfcdd5015b1fba5ca37fff72a
         */        private function blazeLoadEnd(e:Event):void
        {
            _blazePaletteSource = Bitmap(e.target.content).bitmapData;
            
            _blazeEmitter = new BitmapData(STAGE_W, STAGE_H, true, 0x0);
            _blazeCooling1 = new BitmapData(STAGE_W, STAGE_H, true, 0x0);
            _blazeCooling2 = new BitmapData(STAGE_W, STAGE_H, true, 0x0);
            _blazeEffect  = new BitmapData(STAGE_W, STAGE_H, true, 0x0);
            
            //発火元の拡張フィルター
            _blazeSpreadFilter = new ConvolutionFilter(3, 3, [
                0, 1, 0,
                1, 1, 1,
                0, 1, 0], 5
            );
            
            //冷却用雲模様のオフセット
            _blazeCoolingOffset = [
                new Point(0, 0),
                new Point(0, 0)
            ];
            
            //
            _blazeColorFilter = new ColorMatrixFilter(
            [
                0.08, 0   , 0   , 0, 0,
                0   , 0.08, 0   , 0, 0,
                0   , 0   , 0.08, 0, 0,
                0   , 0   , 0   , 1, 0
            ]);
            
            _createBlazePalette(_blazeIndex = 0);
            
            countUp();
        }
        
        private function _createBlazePalette(idx:int):void
        {
            _blazePalette = new Array();
            _zeroPalette  = new Array();
            for (var i:int = 0; i < 256; i++)
            {
                _blazePalette.push(_blazePaletteSource.getPixel32(i, idx * 32));
                _zeroPalette.push(0);
            }
        }
        
        private function countUp():void
        {
            _loadNum++;
            if (_loadNumMax <= _loadNum) startEffect();
        }
        
        private function startEffect():void
        {
            // エフェクトの開始
            _mainSprite.addChild(_cardDisplayList[int(Math.random()*_CARD_URL.length)])
            
            // 表示用MCの準備
            _effectW = Math.ceil(_mainSprite.width);
            _effectH = Math.ceil(_mainSprite.height) + _PARTICLE_MARGIN*2;
            _rect = new Rectangle(0, 0, _effectW, _effectH);
            
            _clear = new BitmapData(_effectW, _effectH, true, 0x00000000);
            _black = new BitmapData(_effectW, _effectH, true, 0xff000000);
            _displayData = _clear.clone();
            _display.bitmapData = _displayData;
            _baseData = _clear.clone();
            _baseData.draw(_mainSprite, new Matrix(1, 0, 0, 1, 0, _PARTICLE_MARGIN));
            _card = _black.clone();
            _card.copyPixels(_baseData, _rect, _point, null, null, true);
            _fireClear = new BitmapData(_effectW, _effectH, true, _FIRE_COLOR);
            _fire = _fireClear.clone();
            
            // 中央に配置
            _display.x = (STAGE_W - _effectW) / 2;
            _display.y = (STAGE_H - _effectH) / 2 - _PARTICLE_MARGIN;
            
            // 雲模様の作成
            _cloud = new BitmapData(_effectW, _effectH);
            _cloud.perlinNoise(_CLOUD_SIZE, _CLOUD_SIZE, _NUM_OCTVES, int(Math.random()*500), false, true, 0, true);
            var tmpGradient:Sprite = new Sprite();
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(_effectW, _effectH, Math.PI / 2, 0, 0);
            tmpGradient.graphics.beginGradientFill(GradientType.LINEAR, [0x000000, 0xffffff], [_GRADIENT_STRENGTH, _GRADIENT_STRENGTH], [0, 255], matrix);
            tmpGradient.graphics.drawRect(0, 0, _effectW, _effectH);
            _cloud.draw(tmpGradient);

            //炎をランダムっぽく消すためのパーリンノイズを作成
            _blazeCooling1.perlinNoise(_effectW, _effectH, 2, 982374, false, false, BitmapDataChannel.RED, true, _blazeCoolingOffset);
            _blazeCooling1.applyFilter(_blazeCooling1, RECT, ZEROS, _blazeColorFilter);
            _blazeCooling2.perlinNoise(_effectW, _effectH, 2, 982374, false, false, BitmapDataChannel.RED, true, _blazeCoolingOffset);
            _blazeCooling2.applyFilter(_blazeCooling2, RECT, ZEROS, _blazeColorFilter);
            
            // ノイズの作成
            var originalNoise:BitmapData = _clear.clone();
            originalNoise.noise(int(Math.random()*int.MAX_VALUE), 0, 255, 7, true);
            _noise = _black.clone();
            
            _noise.threshold(originalNoise, _rect, _point, ">", 0x00f00000, 0x00000000, 0x00ff0000, false);
            
            //addChild(new Bitmap(_blazeEffect));
            
            // フレーム開始
            _effectCount = 0;
            addEventListener(Event.ENTER_FRAME, frame);
        }
        
        private function frame(e:Event):void
        {
            _effectCount++;
            draw();
        }
        
        private function draw():void
        {
            _displayData.lock();
            _blazeEmitter.lock();
            _blazeCooling1.lock();
            _blazeCooling2.lock();
            _blazeEffect.lock();
            
            _displayData.copyPixels(_black, _rect, _point);
            var threshold:int = _effectCount * 0xff0000 / _EFFECT_FRAME;
            _displayData.copyPixels(_card, _rect, _point);
            
            _fire.copyPixels(_fireClear, _rect, _point);
            _fire.threshold(_cloud, _rect, _point, ">", threshold, 0x00000000, 0x00ff0000, false);
            threshold = (_effectCount - 1) * 0xff0000 / _EFFECT_FRAME;
            _fire.threshold(_cloud, _rect, _point, "<", threshold, 0x00000000, 0x00ff0000, false);
            
            //発火元の生成
            _blazeEmitter.copyPixels(_fire, RECT, ZEROS, null, null, true);
            _blazeEmitter.copyChannel(_baseData, RECT, ZEROS, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
            _blazeEmitter.applyFilter(_blazeEmitter, RECT, ZEROS, _blazeSpreadFilter);
            
            //炎用の雲模様の生成(スクロールさせるだけ)
            const scroll_bmd1:BitmapData = new BitmapData(_effectW, _effectH, false, 0x008476);
            const scroll_bmd2:BitmapData = new BitmapData(_effectW, _effectH, false, 0x007882);
            const scroll1:DisplacementMapFilter = new DisplacementMapFilter(
                scroll_bmd1, null,
                BitmapDataChannel.GREEN, BitmapDataChannel.BLUE,
                0x100, 0x100
            );
            const scroll2:DisplacementMapFilter = new DisplacementMapFilter(
                scroll_bmd2, null,
                BitmapDataChannel.GREEN, BitmapDataChannel.BLUE,
                0x100, 0x100
            );
            _blazeCooling1.applyFilter(_blazeCooling1, _blazeCooling1.rect, ZEROS, scroll1);
            _blazeCooling2.applyFilter(_blazeCooling2, _blazeCooling2.rect, ZEROS, scroll2);

            //発火元に雲模様を合成
            _blazeEmitter.draw(_blazeCooling1, null, null, BlendMode.SUBTRACT);
            _blazeEmitter.draw(_blazeCooling2, null, null, BlendMode.SUBTRACT);
            _blazeEffect.paletteMap(_blazeEmitter, RECT, ZEROS, _blazePalette, _zeroPalette, _zeroPalette, _zeroPalette);
            _blazeEmitter.scroll(0, -3);
            //_blazeEffect.copyChannel(_blazeEffect, RECT, ZEROS, BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
            
            //表示
            _displayData.copyChannel(_baseData, _rect, _point, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
            _displayData.threshold(_cloud, _rect, _point, "<", threshold, 0x00000000, 0x00ff0000, false);
            _displayData.draw(_blazeEffect);
            
            _blazeEmitter.unlock();
            _blazeCooling1.unlock();
            _blazeCooling2.unlock();
            _blazeEffect.unlock();
            _displayData.unlock();
            
            if (_EFFECT_FRAME <= _effectCount) end();
        }
        
        private function end():void
        {
            // 終了して、ユーザー操作待ち
            removeEventListener(Event.ENTER_FRAME, frame);;
            _mainSprite.removeChildAt(0);
            _displayData.copyPixels(_clear, _rect, _point);
            addEventListener(MouseEvent.CLICK, clickRestart);
        }
        
        private function clickRestart(e:Event):void
        {
            removeEventListener(MouseEvent.CLICK, clickRestart);
            
            //炎エフェクトの切り替え
            if (++_blazeIndex == int(_blazePaletteSource.height / 32)) _blazeIndex = 0;
            _createBlazePalette(_blazeIndex);
            
            startEffect();
        }
    }
}