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

反応拡散系をBitmapで

反応拡散系をBitmapDataとFilterで実現してみた。

特にインタラクションの要素はなく、ただ変形していくのを眺めるだけ。
/**
 * 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/y8zU
 */

/*
 「反応拡散系をBitmapで」

 以下のサイトを参考に、BitmapDataとFilterで反応拡散系を実現してみた
 ・http://www.bio.nagoya-u.ac.jp/~z3/research/rdsoft.htm

 放っておくとだんだん形が変わる
 ・インタラクション要素はなし

 ランダムな値からでもちゃんと動作するものの、四角から始まるやつが格好良かったのでここではそれを採用
*/

package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import flash.media.*;
 
    [SWF(width="465", height="465", frameRate="60", backgroundColor="0x000000")]
    public class GameMain extends Sprite {

        //==Const==

        //サイズ
        static public const SCL:int = 2;//4;//大きくすると荒くなる(高速化される)
        static public const BMD_W:int = 465/SCL;//100;

        //Utility
        static public const BMD_RECT:Rectangle = new Rectangle(0,0,BMD_W,BMD_W);
        static public const POS_ZERO:Point = new Point(0,0);

        //Debug
        static public const DEBUG:Boolean = false;


        //==Var==

        //表示用
        public var m_BitmapData_View:BitmapData;
        public var PALLETE_MAP:Array;

        //Debug
        public var m_BitmapData_View_U:BitmapData;
        public var m_BitmapData_View_V:BitmapData;

        //拡散反応用
        public var m_BitmapData_Src_U:BitmapData;
        public var m_BitmapData_Src_V:BitmapData;
        public var m_BitmapData_Dst_U:BitmapData;
        public var m_BitmapData_Dst_V:BitmapData;


        //作業用
        public var dd:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
        public var AddU:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
        public var SubU:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
        public var AddV:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
        public var SubV:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);

        //==Function==

        //Init
        public function GameMain():void {
            //表示用
            {
                //画像
                {
                    m_BitmapData_View = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                    var bmp_view:Bitmap = new Bitmap(m_BitmapData_View);
                    bmp_view.scaleX = SCL;
                    bmp_view.scaleY = SCL;
                    addChild(bmp_view);
                }

                //Palette
                {
                    const COLOR_00:uint = 0x111111;
                    const COLOR_FF:uint = 0xCCCC33;

                    const COLOR_00_R:uint = (COLOR_00 >> 16) & 0xFF;
                    const COLOR_00_G:uint = (COLOR_00 >>  8) & 0xFF;
                    const COLOR_00_B:uint = (COLOR_00 >>  0) & 0xFF;
                    const COLOR_FF_R:uint = (COLOR_FF >> 16) & 0xFF;
                    const COLOR_FF_G:uint = (COLOR_FF >>  8) & 0xFF;
                    const COLOR_FF_B:uint = (COLOR_FF >>  0) & 0xFF;

                    const Lerp:Function = function(in_Src:uint, in_Dst:uint, in_Ratio:Number):uint{
                        return (in_Src * (1-in_Ratio)) + (in_Dst * in_Ratio);
                    };

                    PALLETE_MAP = new Array(256);
                    for(var i:int = 0; i < 256; i++){
                        var ratio:Number = i / (255.0);
                        ratio = 0.5 - 0.5*Math.cos(Math.PI*ratio);

                        var r:uint = Lerp(COLOR_00_R, COLOR_FF_R, ratio);
                        var g:uint = Lerp(COLOR_00_G, COLOR_FF_G, ratio);
                        var b:uint = Lerp(COLOR_00_B, COLOR_FF_B, ratio);

                        PALLETE_MAP[i] = (r << 16) | (g << 8) | (b << 0);
                    }
                }
            }

            //Debug
            if(DEBUG)
            {
                var bmp:Bitmap;

                m_BitmapData_View_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                bmp = new Bitmap(m_BitmapData_View_U);
                addChild(bmp);

                m_BitmapData_View_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                bmp = new Bitmap(m_BitmapData_View_V);
                bmp.x = BMD_W;
                addChild(bmp);
            }

            //拡散反応用
            {
                //生成
                {
                    m_BitmapData_Src_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                    m_BitmapData_Src_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                    m_BitmapData_Dst_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                    m_BitmapData_Dst_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
                }

                //初期値設定
                {
/*
                    //パーリンノイズ(あまり美しくない)
                    m_BitmapData_Src_U.perlinNoise(BMD_W, BMD_W, 6, Math.random()*100, false, true, BitmapDataChannel.BLUE);
                    m_BitmapData_Src_V.perlinNoise(BMD_W, BMD_W, 6, Math.random()*100, false, true, BitmapDataChannel.BLUE);
//*/
/*
                    //完全ランダム(わりと高速に安定化する)
                    m_BitmapData_Src_U.noise(Math.random()*100, 0x00,0xFF, BitmapDataChannel.BLUE);
                    m_BitmapData_Src_V.noise(Math.random()*100, 0x00,0xFF, BitmapDataChannel.BLUE);
//*/
//*
                    //中央に四角(なんか魔法陣的な感じになる)
                    m_BitmapData_Src_U.fillRect(new Rectangle(BMD_W*3/8, BMD_W*3/8, BMD_W/4, BMD_W/4), 0x0000FF);
                    m_BitmapData_Src_V.fillRect(new Rectangle(BMD_W*3/8, BMD_W*3/8, BMD_W/4, BMD_W/4), 0x0000FF);
//*/
                }
            }

            //Update
            {
                addEventListener(Event.ENTER_FRAME, Update);
            }
        }

        //Update
        public function Update(e:Event=null):void{
            //var DeltaTime:Number = 1.0 / stage.frameRate;

            //拡散反応処理
            Update_ReactionDiffusion();

            //結果を可視化
            Redraw();
        }

        //Update:拡散反応
        public function Update_ReactionDiffusion():void{
            //Calc

            //拡散
            {
                //大きくすると最終的な模様も大雑把になる
                const POW:Number = 6;//10;

                //U
                {
                    const BlurU:Number = Math.pow(1.01, POW);//1.01;
                    const filter_blur_u:BlurFilter = new BlurFilter(BlurU, BlurU);
                    m_BitmapData_Dst_U.applyFilter(m_BitmapData_Src_U, BMD_RECT, POS_ZERO, filter_blur_u);
                }

                //V
                {
                    const BlurV:Number = Math.pow(1.25, POW);//1.25;
                    const filter_blur_v:BlurFilter = new BlurFilter(BlurV, BlurV);
                    m_BitmapData_Dst_V.applyFilter(m_BitmapData_Src_V, BMD_RECT, POS_ZERO, filter_blur_v);
                }
            }

            //反応
            {
                //U
                {
                    //増える量
                    {
                        //a*u + b*v + c
                        const A:Number = 0.08;
                        const B:Number = -0.072;
                        const C:Number = 0.04;
                        const ct_add_u_ac:ColorTransform = new ColorTransform(0,0,A,1, 0,0,C*0xFF,0);
                        const ct_add_u_b:ColorTransform = new ColorTransform(0,0,Math.abs(B));
                        AddU.draw(m_BitmapData_Dst_U, null, ct_add_u_ac);
                        AddU.draw(m_BitmapData_Dst_V, null, ct_add_u_b, (B > 0)? BlendMode.ADD: BlendMode.SUBTRACT);

                        //制限
                        const SymUMax:Number = 0.1;
                        const ThrU:uint = uint(0xFF * SymUMax);
                        AddU.threshold(AddU, BMD_RECT, POS_ZERO, ">=", ThrU, ThrU, 0x0000FF);
                    }

                    //減る量
                    {
                        //-d*u
                        const D:Number = 0.05;
                        const ct_sub_u:ColorTransform = new ColorTransform(0,0,D);
                        SubU.draw(m_BitmapData_Dst_U, null, ct_sub_u);
                    }

                    //実際の反映はあとで実行する(V側の計算に影響を与えないように)
                }

                //V
                {
                    //増える量
                    {
                        //e*u+f
                        const E:Number = 0.06;
                        const F:Number = -0.0015;
                        const ct_add_v_ef:ColorTransform = new ColorTransform(0,0,E,1, 0,0,F*0xFF,0);
                        AddV.draw(m_BitmapData_Dst_U, null, ct_add_v_ef);

                        //制限
                        const SymVMax:Number = 0.25;
                        const ThrV:uint = uint(0xFF * SymVMax);
                        AddV.threshold(AddV, BMD_RECT, POS_ZERO, ">=", ThrV, ThrV, 0x0000FF);
                    }

                    //減る量
                    {
                        //-g*v
                        const G:Number = 0.03;
                        const ct_sub_v:ColorTransform = new ColorTransform(0,0,G);
                        SubV.draw(m_BitmapData_Dst_V, null, ct_sub_v);
                    }
                }

                //反映
                {
                    m_BitmapData_Dst_U.draw(AddU, null, null, BlendMode.ADD);
                    m_BitmapData_Dst_U.draw(SubU, null, null, BlendMode.SUBTRACT);
                    m_BitmapData_Dst_V.draw(AddV, null, null, BlendMode.ADD);
                    m_BitmapData_Dst_V.draw(SubV, null, null, BlendMode.SUBTRACT);
                }
            }

            //For Next
            {
                m_BitmapData_Src_U.copyPixels(m_BitmapData_Dst_U, BMD_RECT, POS_ZERO);
                m_BitmapData_Src_V.copyPixels(m_BitmapData_Dst_V, BMD_RECT, POS_ZERO);

                m_BitmapData_Dst_U.fillRect(m_BitmapData_Dst_U.rect, 0x000000);
                m_BitmapData_Dst_V.fillRect(m_BitmapData_Dst_V.rect, 0x000000);
            }
        }

        //Redraw
        public function Redraw():void{
            //可視化
            {
                //m_BitmapData_Src_Uの可視化(Src側に今回の結果がフィードバックされているものとする)
                m_BitmapData_View.paletteMap(m_BitmapData_Src_U, BMD_RECT, POS_ZERO, null, null, PALLETE_MAP);
            }

            //Debug
            if(DEBUG){
                m_BitmapData_View_U.copyPixels(m_BitmapData_Src_U, BMD_RECT, POS_ZERO);
                m_BitmapData_View_V.copyPixels(m_BitmapData_Src_V, BMD_RECT, POS_ZERO);
            }
        }
    }
}