サイブリッジラボでタグ「actionscript」が付けられている記事一覧

続・フラクタルノイズの雲Flash

こんにちは。逆から読んでもきつつきです。


前回、フラクタルノイズを用いた雲をFLASHで描画するサンプルを掲載いたしました。

今回はこちらを改良し、時間経過とともに雲が変化していくものを作成してみました。


・・・なんか速いですね。。フレームレートを落とせば調整できると思います。

改良箇所は5カ所。まずは変数の追加です。

        public var CloudDataV:Array;    // 乱数速度テーブル
        public var CloudDataA:Array;    // 乱数加速度テーブル

次に、init関数にタイマー処理を追加します。

        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
           
            // 背景色との加算合成
            this.blendMode = BlendMode.ADD;

            // BitmasDataの初期化
            screen = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0xFF000000 );
            addChild( new Bitmap( screen ) );

            // 雲データの初期化
            initCloud();

            var timer:Timer = new Timer(1, 0);
            timer.addEventListener(TimerEvent.TIMER, refresh);
            timer.start();
           
        }

タイマー処理に伴い、新たにコールバック関数を一つ追加します。

        private function refresh(e:TimerEvent):void
        {
            renderCloudData();
        }

雲の初期化関数initCloudに、速度テーブルと加速度テーブルの初期化処理を加えます。

        private function initCloud():void {
           
            // 配列の確保+乱数テーブルの作成
            CloudData = new Array(SIZE + 1);
            CloudDataD = new Array(SIZE + 1);
            CloudDataV = new Array(SIZE + 1);
            CloudDataA = new Array(SIZE + 1);
           
            var i:int;
            var j:int;
            for (i = 0; i < SIZE + 1;++i)
            {
                CloudData[i] = new Array(SIZE + 1);
                CloudDataD[i] = new Array(SIZE + 1);
                CloudDataV[i] = new Array(SIZE + 1);
                CloudDataA[i] = new Array(SIZE + 1);
               
                for (j = 0; j < SIZE + 1;++j) {
                    CloudDataD[i][j] = (Math.random()*2-1.0);
                    CloudDataV[i][j] = 0;
                    CloudDataA[i][j] = 0;
                }
            }
           
            // 乱数テーブルから雲データの作成
            updateCloud();
        }

最後に、renderCloudData関数の変数宣言直後に雲の更新処理を加えます。

            // 雲の更新
            for (i = 0; i < SIZE+1;++i) {
                for (j = 0; j < SIZE+1;++j ) {
                   
                    // 加速度をランダムに変化
                    CloudDataA[i][j] += (Math.random() * 2 - 1.0);
                    CloudDataA[i][j] *= 0.9;
                   
                    // 速度に加速度を加算
                    CloudDataV[i][j] += CloudDataA[i][j];
                    CloudDataV[i][j] *= 0.9;
                   
                    // 速度を乱数テーブルに加算
                    CloudDataD[i][j] += CloudDataV[i][j];
                    CloudDataD[i][j] *= 0.9;
                }
            }

            updateCloud();

処理の内容としては、雲の濃度値を変化させるために、濃度値の1フレームあたりの変化量(速度)と、変化量の変化量(加速度)を設けて、乱数テーブルを毎フレーム変化させています。

FLASH的な部分としては、タイマーによるビットマップデータオブジェクトの描画アニメーションのサンプルです。無駄なフラクタルノイズで着飾ってます。

フラクタルノイズの雲Flash

こんにちは。逆から読んでもきつつきです。


最近、やっとFLASHに目覚め初めています。
そんなわけで今回はActionScript3.0の話題ですが、勉強中の適当なサンプルを掲載しても面白くないので、学生時代に一度書いたことのあるフラクタルノイズの雲をAS3で書いてみました。



読み込むたびに模様が変わります。
以下、サンプルコードです。

    package
    {
        import flash.display.*;
        import flash.events.*;
        import flash.geom.*;
        import flash.utils.Timer;

        [SWF(backgroundColor="#3333cc", frameRate="60",width="128",height="128" )]
        /**
         * ...
         * @author 啄木鳥@cybridge.jp
         */
        public class Main extends Sprite
        {
            public const SIZE:Number = 128;
            public var screen:BitmapData;

            public var CloudData:Array;        // 濃度
            public var CloudDataD:Array;    // 乱数テーブル
           
            public function Main():void
            {
                if (stage) init();
                else addEventListener(Event.ADDED_TO_STAGE, init);
            }
           
            private function init(e:Event = null):void
            {
                removeEventListener(Event.ADDED_TO_STAGE, init);
                // entry point
               
                // 背景色との加算合成
                this.blendMode = BlendMode.ADD;

                // BitmasDataの初期化
                screen = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0xFF000000 );
                addChild( new Bitmap( screen ) );

                // 雲データの初期化
                initCloud();

                // 描画
                renderCloudData();
            }
           
            private function initCloud():void {
               
                // 配列の確保+乱数テーブルの作成
                CloudData = new Array(SIZE + 1);
                CloudDataD = new Array(SIZE + 1);
               
                var i:int;
                var j:int;
                for (i = 0; i < SIZE + 1;++i)
                {
                    CloudData[i] = new Array(SIZE + 1);
                    CloudDataD[i] = new Array(SIZE + 1);
                   
                    for (j = 0; j < SIZE + 1;++j) {
                        CloudDataD[i][j] = (Math.random()*2-1.0);
                    }
                }
               
                // 乱数テーブルから雲データの作成
                updateCloud();
            }
           
            private function updateCloud():void{

                // 初期の4点を求める
               
                CloudData[0][0] = CloudDataD[0][0] * SIZE ;
                CloudData[0][SIZE] = CloudDataD[0][SIZE] * SIZE ;
                CloudData[SIZE][0] = CloudDataD[SIZE][0] * SIZE ;
                CloudData[SIZE][SIZE] = CloudDataD[SIZE][SIZE] * SIZE ;
               
                // 再帰処理で残りの点を求める
                updateCloud_r(SIZE / 2);
            }
           
            private function updateCloud_r(level:int):void {

                // 再帰処理脱出
                if (level == 0)
                {
                    return;
                }
               
                var i:int;
                var j:int;

                // 前に計算した4点の中間点を求める
                for (i = level; i < SIZE; i += level*2 )
                {
                    for (j = level; j < SIZE; j += level*2 ) {
                        CloudData[i][j] = (CloudData[i - level][j - level] + CloudData[i - level][j + level] + CloudData[i + level][j - level] + CloudData[i + level][j + level]) / 4 + (CloudDataD[i][j] * level);
                    }
                }
               
                // 前に計算した2点と↑で計算した2点から中間点を求める
                var count:int;
                var c:Number;

                for (i = level; i < SIZE; i += level * 2 ) {
                    for (j = 0; j < SIZE + 1; j += level * 2 )
                    {
                        count = 0;
                        c = 0;
                        if (checkPoint(i - level, j)) {
                            ++count;
                            c += CloudData[i - level][ j];
                        }

                        if (checkPoint(i + level, j)) {
                            ++count;
                            c += CloudData[i + level][ j];
                        }

                        if (checkPoint(i, j - level)) {
                            ++count;
                            c += CloudData[i][ j - level];
                        }

                        if (checkPoint(i, j + level)) {
                            ++count;
                            c += CloudData[i][ j + level];
                        }
                       
                        CloudData[i][j] = c / count + (CloudDataD[i][j] * level);
                    }
                }
               
                for (i = 0; i < SIZE + 1 ; i += level * 2 )
                    for (j = level; j < SIZE; j += level * 2 ) {
                    {
                        count = 0;
                        c = 0;

                        if (checkPoint(i - level, j)) {
                            ++count;
                            c += CloudData[i - level][ j];
                        }

                        if (checkPoint(i + level, j)) {
                            ++count;
                            c += CloudData[i + level][ j];
                        }

                        if (checkPoint(i, j - level)) {
                            ++count;
                            c += CloudData[i][ j - level];
                        }

                        if (checkPoint(i, j + level)) {
                            ++count;
                            c += CloudData[i][ j + level];
                        }
                       
                        CloudData[i][j] = c / count+ (CloudDataD[i][j]*level);
                    }
                }
               
                // 再帰呼び出し
                updateCloud_r(level / 2);
            }
           
            // 座標が適切かどうか調べる
            private function checkPoint(i:int, j:int):Boolean
            {
                if (0 <= i && i < SIZE + 1 && 0 <= j && j < SIZE + 1) {
                    return true;
                }
               
                return false;
            }
           
            // レンダリング
            private function renderCloudData():void
            {
                var i:int;
                var j:int;
                var c:int;
                var c_max:Number;
                var c_min:Number;
                var d:Number;

                c_max = CloudData[0][0];
                c_min = -CloudData[0][0];

               
                for (i = 0; i < SIZE;++i) {
                    for (j = 0; j < SIZE;++j ) {
                        c_max = Math.max(c_max, CloudData[i][j]);
                        c_min = Math.min(c_min, CloudData[i][j]);
                    }
                }
               
                d = c_max - c_min;

                screen.lock();
               
                for (i = 0; i < SIZE;++i) {
                    for (j = 0; j < SIZE;++j ) {
                        c = 255 * (CloudData[i][j] - c_min) / d;
                        screen.setPixel32(i, j, (0xff000000 | (c<<16) | (c<<8) | c ));
                    }
                }
               
                screen.unlock();
            }
        }
       
    }

初期4点をランダムに求めたあと、その4点の中間点を、4点の濃度値の平均+ノイズで求め、そこからさらに4点を使って別の点を求め、・・・と再帰的に処理を行っていきます。
乱数をテーブル化しているのは次回への布石です。次回は雲を徐々に変化させます。

actionscript3.0でストップウォッチの作成Flash

しんぶーです。

・[mixiアプリ]四則演算ゲーム携帯版のflashliteの処理構造
・[mixiアプリ]対戦リバーシの通信対戦の処理構造

に関して書こうと思ったのですが、また次の機会に。

今回は、actionscript3.0でストップウォッチの作成方法に関して。

ストップウォッチの作成方法にはenterframeとtimerの2種類があり
ざっと検索してみたところ、enterframe系の処理はサンプルソースがたくさんあったのですが、
timer系で処理しているものがみあたらなかったので書いてみました。

動作サンプル(左の四角をクリックでSTART、右の四角をクリックでSTOP)

あまり時間をかけないでサクッと書いたため、
命名や処理構造が最適化されていない部分はご了承下さい。

package {

    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.MouseEvent;
    import flash.text.TextField;

    public class FlashTest extends Sprite {
       
        public var MiliSeconds = 0;
        public var Clock = new Timer(10);
        public var myTextField:TextField = new TextField();
        public var startBTN:Sprite = new Sprite();
        public var stopBTN:Sprite = new Sprite();
       
        public function FlashTest() {
           
            // timer text
           
            myTextField.x = 100;
            myTextField.y = 70;
            myTextField.text ="0:00:00";
            this.addChild(myTextField);
           
            // start button
           
            startBTN.graphics.beginFill(0xFFCC00);
            startBTN.graphics.drawRect(60, 5, 40, 40);
            this.addChild(startBTN);
           
            startBTN.addEventListener(MouseEvent.MOUSE_UP, ClockStart);
            startBTN.addEventListener(MouseEvent.MOUSE_OVER, mOver);
            startBTN.addEventListener(MouseEvent.MOUSE_OUT, mOut);
           
            // stop button
           
            stopBTN.graphics.beginFill(0xCCFF00);
            stopBTN.graphics.drawRect(160, 5, 40, 40);
            this.addChild(stopBTN);
           
            stopBTN.addEventListener(MouseEvent.MOUSE_UP, ClockStop);
            stopBTN.addEventListener(MouseEvent.MOUSE_OVER, mOver);
            stopBTN.addEventListener(MouseEvent.MOUSE_OUT, mOut);
           
            // clock
            Clock.addEventListener(TimerEvent.TIMER, this.Tick);
           
        }
       
        public function Tick(e:TimerEvent):void{
            MiliSeconds++;
            var s:int = Math.floor(MiliSeconds / 100);
            var minutes:int = Math.floor( s / 60);
            var seconds:int = s % 60;
            var mili:int = MiliSeconds % 100 ;
            myTextField.text = minutes + ":" + (seconds > 9 ? seconds : "0" + seconds) +":"+ (mili > 9 ? mili : "0" + mili);
        }
       
        public function mOver( e){
            e.target.alpha=0.5
        }
       
        public function mOut( e ){
            e.target.alpha =1
        }
       
        public function ClockStart(e){
            MiliSeconds = 0;
            Clock.start();
        }
       
        public function ClockStop(e){
            Clock.stop();
        }
       
    }
}