Beautifl - Flash Gallery

Preview

forked from: Marimo : moves by mouse.
nutsu 2009年8月27日 MIT License
?
動かしてみる。けど重いね…  
目を入れてみる。
      // forked from tail_y's Marimo
// 動かしてみる。けど重いね…
// 目を入れてみる。
package {
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.Event;
    import frocessing.geom.FGradientMatrix;
    import frocessing.math.FMath;
    
    public class Marimo extends Sprite {
        // 空飛ぶマリモ的な物を作る。
        // 実際の構造は、マリモというか、やわらかいウニ。
        // 球形の表面からパーティクルを飛ばして、それを線で繋ぐ。
        // 問題点:線のつなぎ目が汚い 毛の長さが重力によって伸びてしまう ちょっと重い
        // できそうなこと:ビットマップにピクセルで描いて縮小するようにすれば、軽くなるかも。パーティクルを制御すれば、地面と毛が接する表現になるかも
        
        public static const STAGE_W:uint = 465;
        public static const STAGE_H:uint = 465;
        
        public static const SPHERE_R:Number = 40;        // マリモの体の(毛以外の部分の)半径。
    
        public static const PARTICLE_NUM_RATE:uint = 40;    // 球体の半円を分割する数。
        public static const PARTICLE_STEP:uint = 4;    // 線の描画回数。大きいほど長くなる。
        public static const PARTICLE_V:uint = 8*PARTICLE_STEP;    // 線の勢い。大きいほど長く、粗くなる。
        public static const GRAVITY:Number = 0.8;    // 重力。毛の長さ補正をしていないので、重力が強すぎると毛が伸びる    
        public static const RANDOM_RATE:Number = 0.8;    // バラつき具合        
        public static const COLOR_RANDOM_RATE:Number = 0.3;    // 色のバラつき具合        
        
        public static const GROUND_Y:Number = 400;    // 地面位置    
        public static const SHADOW_W:Number = 150;    // 影サイズ
        public static const GROUND_H:Number = 30;    // 影サイズ
        
        private var _marimoX:Number = STAGE_W/2;    // マリモの位置
        private var _marimoY:Number = STAGE_H/2 - 50;
        private var _display2:Sprite;
        
        public static const COLOR_TIP_TOP:Number     = 0x77cc44;        // 毛先上部
        public static const COLOR_TIP_BOTTOM:Number  = 0x339900;        // 毛先下部
        public static const COLOR_BACE_TOP:Number    = 0x116600;        // 本体上部
        public static const COLOR_BACE_BOTTOM:Number = 0x003300;        // 本体下部
        
        private var g:Graphics;
        private var gmtx:FGradientMatrix;
        private var furalphas:Array = [1,0];
        private var furratios:Array = [0,255];
        private var furs:Array;
        private var offsetX:Number;
        private var offsetY:Number;
        private var targetX:Number;
        private var targetY:Number;
        private var draw_gravity:Number;
        
        private var eyeX1:Number = SPHERE_R / 2;
        private var eyeX2:Number = -eyeX1;
        private var eyeY:Number = -SPHERE_R/4;
        private var eyeR:Number = 6;
        
        public function Marimo() {
            addEventListener( Event.ADDED_TO_STAGE, init );
        }
        
        private function init(e:Event):void {
            
            stage.quality = "medium";
            //
            _display2 = new Sprite();
            addChild(_display2);
            
            //matrix for gradient
            gmtx = new FGradientMatrix();
            
            // graphics
            g = _display2.graphics;
            g.lineStyle();
            
            // 
            makeFurs();
            offsetX = targetX = 0;
            offsetY = targetY = 0;
            
            //
            addEventListener( Event.ENTER_FRAME, drawMarimo );
        }
        
        private function makeFurs():void
        {            
            furs = [];
            // 毛
            for (var xri:uint = 0; xri < PARTICLE_NUM_RATE; xri++){    // zを先に計算して、奥から手前へ描画
                var xAngle:Number = Math.PI*xri / PARTICLE_NUM_RATE;    // マリモ中心点から、マリモ表面へのx方向に対する角度
                var z:Number = Math.cos(xAngle) * SPHERE_R;                // パーティクルを飛ばす原点Z
                var r:Number = Math.sin(xAngle) * SPHERE_R;                // その時の、断面の半径
                
                // z方向に向いた面の円周上にある点の数。円周の比(=半径の比)で割り出すが、整数に丸めるので、正確ではない。
                // (右側でそろっちゃうのが気持ち悪い。ランダムでz回転させてもいいかも。)
                var particleRateZ:int = PARTICLE_NUM_RATE * 2 * r / SPHERE_R;
                
                for (var zri:uint = 0; zri < particleRateZ; zri++){    // z方向面に対して、時計回りに描画
                    var zAngle:Number = Math.PI*zri*2 / particleRateZ;    // マリモ中心点から、マリモ表面へのz方向に対する角度
                    var x:Number = Math.cos(zAngle) * r;    // パーティクルを飛ばす原点X
                    var y:Number = Math.sin(zAngle) * r;    // パーティクルを飛ばす原点Y
                    var vx:Number = PARTICLE_V * x / SPHERE_R;    // パーティクルの速度X
                    var vy:Number = PARTICLE_V * y / SPHERE_R;    // パーティクルの速度Y
                    // 方向をランダムでバラす。(本来は、円形方向へランダムにしなきゃいけないのだけど、面倒なのでこれで)
                    vx += (PARTICLE_V * RANDOM_RATE) * (0.5 - Math.random());
                    vy += (PARTICLE_V * RANDOM_RATE) * (0.5 - Math.random());
                    
                    // 色を決める。上下の位置と、根本までの割合で色を決定する。ランダムもちょっと入れておく。
                    var yColorRate:Number = ((SPHERE_R + y)/ 2 / SPHERE_R) + COLOR_RANDOM_RATE * (0.5 - Math.random());
                    var color0:Number = mixColor(COLOR_BACE_TOP, COLOR_BACE_BOTTOM, yColorRate);
                    var color1:Number = mixColor(COLOR_TIP_TOP, COLOR_TIP_BOTTOM, yColorRate);
                    
                    // 毛
                    if( FMath.dist(x,y,eyeX1,eyeY)<eyeR || FMath.dist(x,y,eyeX2,eyeY)<eyeR )continue;
                    
                    var fur:FurInfo = new FurInfo();
                    fur.x = _marimoX + x;
                    fur.y = _marimoY + y;
                    fur.vx = vx;
                    fur.vy = vy;
                    fur.colors = [color0, color1];
                    furs.push( fur );
                }
            }
            eyeX1 += _marimoX;
            eyeX2 += _marimoX;
            eyeY  += _marimoY;
        }
        
        private function drawMarimo( e:Event ):void
        {
            g.clear();
            
            targetX = (mouseX - _marimoX);
            targetY = (mouseY - _marimoY) / 2;
            var ax:Number = ( targetX - offsetX );
            var ay:Number = ( targetY - offsetY );
            var gr:Number = FMath.constrain( GRAVITY -  ay / 30, -GRAVITY, 1.5 * GRAVITY );
            offsetX  += ax * 0.2;
            offsetY  += ay * 0.2;
            draw_gravity = GRAVITY * gr * PARTICLE_STEP * PARTICLE_STEP; 
            
            ax = FMath.constrain( ax, -PARTICLE_V/5, PARTICLE_V/5 );
            
            // 影
            var ss:Number = ( mouseY + 100 )/ 465;
            gmtx.identity();
            gmtx.scale( SHADOW_W*ss, GROUND_H*ss );
            gmtx.translate( _marimoX+offsetX, GROUND_Y );
            g.beginGradientFill(GradientType.RADIAL, [0x000000, 0x000000], [0.3, 0.0], [60, 255], gmtx);
            g.drawRect(0, 0, STAGE_W, STAGE_H);
            g.endFill();
            
            // 本体
            g.beginFill(COLOR_BACE_BOTTOM);
            g.drawCircle(_marimoX+offsetX, _marimoY+offsetY, SPHERE_R);
            g.endFill();
            
            gmtx.createRadial( eyeX1+offsetX, eyeY+offsetY, eyeR, -Math.PI*0.25 );
            g.beginGradientFill( "radial", [0xffffff,0],[1,1],[0,127],gmtx, "pad", "rgb", 0.6 );
            g.drawCircle( eyeX1+offsetX, eyeY+offsetY, eyeR );
            g.endFill();
            gmtx.createRadial( eyeX2+offsetX, eyeY+offsetY, eyeR, -Math.PI*0.75 );
            g.beginGradientFill( "radial", [0xffffff,0],[1,1],[0,127],gmtx, "pad", "rgb", 0.6 );
            g.drawCircle( eyeX2+offsetX, eyeY+offsetY, eyeR );
            g.endFill();
            
            var len:int = furs.length;
            for ( var i:int = 0; i < len; i++ )
            {
                var fur:FurInfo = furs[i];
                drawFur( fur.x+offsetX, fur.y+offsetY, fur.vx-ax, fur.vy, fur.colors );
            }
        }
        
        // 毛を描く
        private function drawFur(x:Number, y:Number, vx:Number, vy:Number, colors:Array):void {
            var x0:Number = x + vx * 0.75;
            var y0:Number = y + vy * 0.75;
            var x1:Number = x + vx;
            var y1:Number = y + vy + draw_gravity;
            var d:Number  = Math.sqrt( vx * vx + vy * vy ) / 1.5;
            gmtx.createLinear( x, y, x1, y1 );
            g.beginGradientFill( "linear", colors, furalphas, furratios, gmtx );
            g.moveTo( x, y );
            g.curveTo( x0, y0, x1, y1 );
            vx /= d;
            vy /= d;
            g.curveTo( x0+vy, y0-vx, x+vy, y-vx );
            g.endFill();
        }
        
        // 2つの色を指定した割合で混ぜた色を返す(rate=0ならcolor0)。(ここもかなり軽量化できるはず。グラデーションをキャッシュとして使うとか)
        private function mixColor(color0:uint, color1:uint, rate:Number):uint{
            if (rate <= 0) return color0;
            if (rate >= 1) return color1;
            var r:uint = (color0>>16) * (1-rate) 
                            + (color1>>16) * rate;
            var g:uint = ((color0 & 0x00ff00 ) >>8) * (1-rate) 
                            + ((color1 & 0x00ff00 ) >>8) * rate;
            var b:uint = (color0 & 0xff) * (1-rate) 
                            + (color1 & 0xff) * rate;
             return (r << 16) | (g << 8) | (b);
        }
        
    }
}

class FurInfo {
    public var x:Number;
    public var y:Number;
    public var vx:Number;
    public var vy:Number;
    public var colors:Array;
    public function FurInfo() {
        
    }
}