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: loco roco v0.2 (改造PuyoDot)

改造 from http://wonderfl.net/c/kwty
too many changes are made, i'll say it's more than fork
i think i should keep most of the original comments

thanks @tail_y @http://wonderfl.net/user/tail_y

zonnbe@2010

PuyoDot
プヨっとしたドット。 
下のほうにあるパレットから拾ってきて表示するよ。
ぐりぐりしたり、引っ張ったり、新しいドット絵を追加して遊んでね。
(マップが意外と見ずらくなった。wonderflって等倍フォントじゃないんだね
等倍のテキストエディタか何かで編集すると楽かも)

本当はドットを編集する機能も入れたかったんだけど
力尽きるどころの話じゃなかったから今回は諦めた。
でもいつか作りたいね。

ドット状、任意外形の弾性体を表現します。
こういう、ぐにぐにしたものは、各頂点をテンションで繋ぐfladdict式が一番軽くて綺麗なのですが、
そうすると自由な形にはしにくいという欠点があります。
今回の手法では、小さな点が、バネで繋がっているモデルをしており、一部が欠けてもそれらしい動作をします。
バネは回転方向への力も持ち、隣の点を、距離だけではなく正常な角度に保とうとします。
欠点として、点の数が多くなるため圧倒的に重いことと
力の伝わり方が遅いため、伸びやすい物体になってしまうことです。
前者はリファクタリングしていく必要があります。
後者は、今回解決のために点を2個先まで接続する手法をとりました。

キング・カズマのドットバージョンを入れたかったんだけど
16x32ドットは重くなりすぎて断念。
軽量化して、そのくらいは動くようになりたい。
/**
 * Copyright harada0523 ( http://wonderfl.net/user/harada0523 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/sVNR
 */

// forked from zonnbe's loco roco v0.2 (改造PuyoDot)
/**
 * 
 * 改造 from http://wonderfl.net/c/kwty
 * too many changes are made, i'll say it's more than fork
 * i think i should keep most of the original comments
 *
 * thanks @tail_y @http://wonderfl.net/user/tail_y
 *
 * zonnbe@2010
 */

package 
{
    /*
    PuyoDot
    プヨっとしたドット。 
    下のほうにあるパレットから拾ってきて表示するよ。
    ぐりぐりしたり、引っ張ったり、新しいドット絵を追加して遊んでね。
    (マップが意外と見ずらくなった。wonderflって等倍フォントじゃないんだね
    等倍のテキストエディタか何かで編集すると楽かも)
    
    本当はドットを編集する機能も入れたかったんだけど
    力尽きるどころの話じゃなかったから今回は諦めた。
    でもいつか作りたいね。
     */
     
     /*
    
    ドット状、任意外形の弾性体を表現します。
    こういう、ぐにぐにしたものは、各頂点をテンションで繋ぐfladdict式が一番軽くて綺麗なのですが、
    そうすると自由な形にはしにくいという欠点があります。
    今回の手法では、小さな点が、バネで繋がっているモデルをしており、一部が欠けてもそれらしい動作をします。
    バネは回転方向への力も持ち、隣の点を、距離だけではなく正常な角度に保とうとします。
    欠点として、点の数が多くなるため圧倒的に重いことと
    力の伝わり方が遅いため、伸びやすい物体になってしまうことです。
    前者はリファクタリングしていく必要があります。
    後者は、今回解決のために点を2個先まで接続する手法をとりました。
    
    
    キング・カズマのドットバージョンを入れたかったんだけど
    16x32ドットは重くなりすぎて断念。
    軽量化して、そのくらいは動くようになりたい。
    */
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.KeyboardEvent;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.system.LoaderContext;
    import flash.net.URLRequest;
    import flash.utils.*;
    import flash.ui.Keyboard;
    import frocessing.color.ColorHSV;
    import com.bit101.components.PushButton;
    import net.hires.debug.Stats;

    public class PuyoDot3 extends Sprite
    {
        public static const STAGE_W:uint = 465;
        public static const STAGE_H:uint = 465;
        
        private static const _WALL_LEFT:Number = 0;
        private static const _WALL_RIGHT:Number = 465;
        private static const _GROUND_LINE:Number = 350;

        // パーティクル
        //private var _dotMap:DotMap;
        private var _particleList:Array = [];    //:Array :Particle
        private var _particleDistance:int;
        private var _w:int;
        private var _h:int;
        
        // ドラッグ
        private var _dragIdX:int = -1;
        private var _dragIdY:int = -1;
        
        // レイヤー
        private var _bgLayer:Bitmap;
        private var _displayLayer:Bitmap;
        private var _debugLayer:Sprite;
        private var _debugDisplayList:Array = [];
        private var _dragLayer:Sprite;
        private var _dragList:Array = [];
        
        // ビットマップ
        private var _clearBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
        private var _displayBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
        private var _bgBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
        private var _gradiationBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
        private var _reflectAlphaBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
        
        private var _rect:Rectangle = new Rectangle(0, 0, STAGE_W, STAGE_H);
        private var _point:Point = new Point();
        private var _refrectPoint:Point = new Point(0, -2*_GROUND_LINE + STAGE_H);
        
        private var blobPuyos:Vector.<BlobPuyo> = new Vector.<BlobPuyo>(0, false);
        
        //plastic surgery
        public var GRAPHIC_URL:String = "http://nullurban.appspot.com/loco3.png";
        private var loader      :Loader;
        private var bmpd        :BitmapData;
        private var mouth_bmpd  :BitmapData;
        private var mouth2_bmpd :BitmapData;
        private var eyes_bmpd   :BitmapData;
        private var hair_bmpd   :BitmapData;
        
        private var blobsMouth  :Vector.<Bitmap>     = new Vector.<Bitmap>(0, false);
        private var blobsFace   :Vector.<MovieClip>     = new Vector.<MovieClip>(0, false);
        private var blobsEyes   :Vector.<MovieClip>     = new Vector.<MovieClip>(0, false);
        
        private var vcolor:ColorHSV = new ColorHSV(0,0.6,1,0.5);
        private var fps:int = 2;
        
        public function PuyoDot3()
        {
            addEventListener(Event.ADDED_TO_STAGE, initGRAPHIC);    // flexBuilderとの互換性。
        }
        private function initGRAPHIC(e:Event):void {    // ここから開始
            removeEventListener(Event.ADDED_TO_STAGE, initGRAPHIC);
            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, init);
            loader.load(new URLRequest(GRAPHIC_URL), new LoaderContext(true));
        }
        
        private function init(e:Event):void
        {
            //prepare organs
            bmpd = Bitmap(loader.content).bitmapData;
            mouth_bmpd = new BitmapData(7, 7, true, 0x0);
            mouth_bmpd.copyPixels(bmpd, new Rectangle(17,0,7,7), new Point());
            mouth2_bmpd = new BitmapData(7, 7, true, 0x0);
            mouth2_bmpd.copyPixels(bmpd, new Rectangle(24,0,3,7), new Point(3,0));
            eyes_bmpd = new BitmapData(17, 7, true, 0x0);
            eyes_bmpd.copyPixels(bmpd, new Rectangle(0,0,17,7), new Point());
            hair_bmpd = new BitmapData(25, 13, true, 0x0);
            hair_bmpd.copyPixels(bmpd, new Rectangle(0,8,25,14), new Point());
            
            // SWF設定
            stage.frameRate = 60;
////v0.2
            stage.quality = StageQuality.HIGH;  //LOW
            var bg:Sprite = new Sprite();    // wonderflではキャプチャに背景色が反映されないので、背景色Spriteで覆う。
            bg.graphics.beginFill(0xaaaaaa);
            bg.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
            addChild(bg);
            
            addChild(_bgLayer = new Bitmap(_bgBitmap));
            addChild(_displayLayer = new Bitmap(_displayBitmap));
            addChild(_debugLayer = new Sprite());
            addChild(_dragLayer = new Sprite());
            _debugLayer.visible = false;
            _bgLayer.scaleY = -1;
            _bgLayer.y = STAGE_H;

            
////v0.2
            var I:int = 0;
            var J:int = 0;
            var K:int = 0;
            var VX:Number = 0;
            var VY:Number = 0;
            var TRADIUS:Number = 0;
            var CRADIUS:Number = 0;
            
            for(I = 0; I < 3; I++)
            {
                addBlob(I);
                
            }

            // デバッグ表示
            //debugInit();
            
            displayInit();
            
            var panel:Sprite = new Sprite();
            addChild(panel);
            new PushButton(panel, stage.stageWidth-85, 5, "add blob", addMoreBlob).setSize(80, 16);
            
            // フレームの処理を登録
            addEventListener(Event.ENTER_FRAME, frame);
            // マウスドラッグ
            //stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEvent());
////v0.2
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onmouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP  , onmouseUp  );
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown);
            addChild(new Stats());
        }
        
        private function onkeyDown(e:KeyboardEvent):void
        {
            if(e.keyCode==Keyboard.UP)
            {
                if(++fps>3) fps = 1;
                stage.frameRate = fps * 30;
            }
        }
        
        private function addMoreBlob(...arg):void
        {
            addBlob(blobPuyos.length);
        }
        
        private function addBlob(id:int):void
        {
            vcolor.h = Math.random()*100;
            var plastic_organs:Bitmap;
            blobsFace.push(new MovieClip());
            addChild(blobsFace[id]);
            
            // plastic surgery
            plastic_organs = new Bitmap(hair_bmpd.clone());
            transformColor(plastic_organs.bitmapData, vcolor.value);
            plastic_organs.x = -hair_bmpd.width/2; plastic_organs.y = -hair_bmpd.height*0.9;
            blobsFace[id].addChild(plastic_organs);
            //eye
            blobsEyes.push(new MovieClip());
            plastic_organs = new Bitmap(eyes_bmpd);
            blobsEyes[id].addChild(plastic_organs);
            plastic_organs.y = -eyes_bmpd.height/2;
            blobsEyes[id].x = -eyes_bmpd.width/2; blobsEyes[id].y = 3+eyes_bmpd.height/2;
            blobsFace[id].addChild(blobsEyes[id]);
            //mouth
            plastic_organs = new Bitmap(mouth_bmpd);
            plastic_organs.x = -mouth_bmpd.width/2; plastic_organs.y = eyes_bmpd.height+3;
            blobsFace[id].addChild(plastic_organs);
            blobsMouth.push(plastic_organs);
            
            
            blobPuyos.push(new BlobPuyo(vcolor.value, 50+Math.random()*365, 50, 30 + Math.random()*5));
            blobPuyos[id].blink = Math.random() * 3000;
        }
        
        private function transformColor(bmd:BitmapData, c:uint):void
        {
            var i:int = 0;
            
            var to_R:uint = (c & 0xFF0000);
            var to_G:uint = (c & 0x00FF00);
            var to_B:uint = (c & 0x0000FF);
            var paletteR:Array = [];
            var paletteG:Array = [];
            var paletteB:Array = [];
            var r:Number;
            
            for (i = 0; i < 256; i++) {
                paletteR[i] = (to_R);
                paletteG[i] = (to_G);
                paletteB[i] = (to_B);
            }
            
            bmd.paletteMap(hair_bmpd, hair_bmpd.rect, hair_bmpd.rect.topLeft, paletteR, paletteG, paletteB);
        }
        
        // フレーム挙動
        private function frame(event:Event):void{
            /*
            for (var i:int=0; i<_DERIVATION; i++){
                rotate();    // 回転の計算
                force();    // 力の計算
                move();    // 移動処理
            }
            calcMID();
            /**/
            //debugDraw();
            var i:int = 0;
            var j:int = 0;
            var d:int = 0;
            //for (var d:int=0; d<GB._DERIVATION; d++){
            for (d=0; d<1; d++){
                //calculate diff
                for(i = 0; i<blobPuyos.length; i++)
                    blobPuyos[i].setup();
                
                //check contacts
                for(i = 0; i<blobPuyos.length; i++)
                    for(j = 0; j <blobPuyos.length; j++)
                        if(i != j)
                            blobPuyos[i].xcontact(blobPuyos[j]);
                /**/
                //response
                for(i = 0; i<blobPuyos.length; i++)
                    blobPuyos[i].update();
            }
            
            draw();    // 描画処理
        }
        
        private var _drawShape:Shape = new Shape();
        
        private function displayInit():void{
            var g:Graphics = _drawShape.graphics;
            g.clear();
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(STAGE_W, STAGE_H, Math.PI / 2, 0, 0);
            g.beginGradientFill(GradientType.LINEAR, [0xa3a3a3, 0x676767], [1, 1], [0, 255], matrix);
            g.drawRect(0, 0, STAGE_W, STAGE_H);
            _gradiationBitmap.draw(_drawShape);
            
            g.clear();
            g.beginGradientFill(GradientType.LINEAR, [0x000000, 0x000000], [0, 0.7], [125, 230], matrix);
            g.drawRect(0, 0, STAGE_W, STAGE_H);
            _reflectAlphaBitmap.draw(_drawShape);
        }
        private function draw():void{
            
            
            
            var g:Graphics = _drawShape.graphics;
            var particle:Particle;
            g.clear();
            
////v0.2
            //g.lineStyle(0.1, 0xFF0000);
            
            var I:int = 0;
            var J:int = 0;
            var K:int = 0;
            
            /*
            g.moveTo(_VERTS[0].x, _VERTS[0].y);
            for(I = 0; I < _VERTS.length; I++)
            {
                J = (I+1)%_VERTS.length;
                
                g.lineTo(_VERTS[J].x, _VERTS[J].y);
                //g.moveTo(_VERTS[I].x, _VERTS[I].y);
                //g.lineTo(CENT_PARTICLE.x, CENT_PARTICLE.y);
            }
            /**/
            
            var BVI:Particle;
            var BPI:Particle;
            for(I = 0; I < blobPuyos.length; I++)
            {
                BVI = blobPuyos[I]._VERTS[blobPuyos[I].head];
                BPI = blobPuyos[I].pvn[blobPuyos[I].head];
                blobsFace[I].x = BVI.x;
                blobsFace[I].y = BVI.y;
                blobsFace[I].rotation = Math.atan2(BPI.y, BPI.x)/(Math.PI/180) - 90;
                if(blobPuyos[I]._DRAG_ID!=-1)
                    blobsMouth[I].bitmapData = mouth2_bmpd;
                else 
                    blobsMouth[I].bitmapData = mouth_bmpd;
                
                if(int((blobPuyos[I].blink+getTimer())%3000)<200) blobsEyes[I].scaleY = ((blobPuyos[I].blink+getTimer())%200)/200;
                
                    
                g.beginFill(blobPuyos[I].color);
                g.moveTo(blobPuyos[I]._MIDS[0].x, blobPuyos[I]._MIDS[0].y);
                for(J = 0;J < blobPuyos[I]._VERTS.length; J++)
                {
                    K = (J+1) % blobPuyos[I]._VERTS.length;
                    g.curveTo(blobPuyos[I]._VERTS[K].x, blobPuyos[I]._VERTS[K].y, blobPuyos[I]._MIDS[K].x, blobPuyos[I]._MIDS[K].y);
                }
                
                
                g.endFill();
            }
            /**/
            
            _displayBitmap.copyPixels(_clearBitmap, _rect, _point);
            _displayBitmap.draw(_drawShape);
            
            _bgBitmap.copyPixels(_gradiationBitmap, _rect, _point);
            _bgBitmap.copyPixels(_displayBitmap, _rect, _refrectPoint, _reflectAlphaBitmap, _point, true);
        }
        
////v0.2
        private function onmouseDown(e:MouseEvent):void
        {
            var I:int = 0;
            for(I = 0; I < blobPuyos.length; I++)
            {
                blobPuyos[I].detectDrag(mouseX, mouseY);
            }
        }
        
        private function onmouseMove(e:MouseEvent):void
        {
            var I:int = 0;
            for(I = 0; I < blobPuyos.length; I++)
            {
                blobPuyos[I].moveDrag(mouseX, mouseY);
            }
        }
        
        private function onmouseUp(e:MouseEvent):void
        {
            var I:int = 0;
            for(I = 0; I < blobPuyos.length; I++)
            {
                blobPuyos[I].cancelDrag();
            }
        }
    }
}

class BlobPuyo {

    //EXXXXXTRA!!!!
    private var _OLD_PARTICLE_AREA  :Number            = 0;
    

    private var VERT_COUNT          :int               = 16;
    public var RADIUS               :Number            = 30;
    public var _VERTS              :Vector.<Particle> = new Vector.<Particle>(0, false);
    public var _MIDS               :Vector.<Particle> = new Vector.<Particle>(0, false);
    //private var _VERT_DISTANCE      :Number            = 0;
    //private var _CENT_DISTANCE      :Number            = 0;
    public var _DRAG_ID            :int               = -1;
    //private var _CENTERX            :Number            = stage.stageWidth/2;
    //private var _CENTERY            :Number            = 50;
    public var CENT_PARTICLE       :Particle          = new Particle();  //SPECIAL, center of blob
    
    public var d                   :Vector.<Particle> = new Vector.<Particle>(0, false);
    public var disp                :Vector.<Particle> = new Vector.<Particle>(0, false);
    public var cdiv                :int               = 0;
    public var fdiv                :Vector.<int>      = new Vector.<int>(0, false);
    public var pvn                 :Vector.<Particle> = new Vector.<Particle>(0, false);
    public var sd                  :Number            = 0.3;
    
    private var mouse_x:Number = 0;
    private var mouse_y:Number = 0;
    
    public var blink:Number = 0;
    
    public var color:uint = 0;
    
    public var head:int = 0;

    public function BlobPuyo(c:uint, px:Number, py:Number, ra:Number = 30, v:int = 16) {
        color = c;
        VERT_COUNT = v;
        CENT_PARTICLE.x = px;
        CENT_PARTICLE.y = py;
        RADIUS = ra;
        // constructor code
        var D_RAD:Number = GB._RADIAN360 / VERT_COUNT;
        var I:int = 0;
        var J:int = 0;
        var K:int = 0;
        var VX:Number = 0;
        var VY:Number = 0;
        var TRADIUS:Number = 0;
        var CRADIUS:Number = 0;
        
        switch(int(Math.random()*5))
        {
            case 0:
                //ピーナッツ
                head = 4;
                for(I = 0; I < VERT_COUNT; I++)
                {
                    CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI)-(Math.PI/2));
                    TRADIUS = RADIUS*1/2 + (RADIUS*1/2 * (CRADIUS)/(Math.PI/2));
                    VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
                    VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
                    _VERTS.push(new Particle(VX, VY));
                    _MIDS.push(new Particle());
                    d.push(new Particle(0, 0));
                    disp.push(new Particle(0, 0));
                    fdiv.push(0);
                    pvn.push(new Particle());
                }
                /**/
                break;
            case 1:
                //三角
                head = 5;
                for(I = 0; I < VERT_COUNT; I++)
                {
                    CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI*2/3)-(Math.PI/3));
                    TRADIUS = RADIUS*3/4 + (RADIUS*1/4 * (CRADIUS)/(Math.PI/3));
                    VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
                    VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
                    _VERTS.push(new Particle(VX, VY));
                    _MIDS.push(new Particle());
                    d.push(new Particle(0, 0));
                    disp.push(new Particle(0, 0));
                    fdiv.push(0);
                    pvn.push(new Particle());
                }
                /**/
                break;
            case 2:
                //方
                head = 4;
                for(I = 0; I < VERT_COUNT; I++)
                {
                    CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI/2)-(Math.PI/4));
                    TRADIUS = RADIUS*3/4 + (RADIUS/4 * (Math.PI/4-CRADIUS)/(Math.PI/4));
                    VX = CENT_PARTICLE.x + Math.cos(I*D_RAD+Math.PI/4) * TRADIUS;
                    VY = CENT_PARTICLE.y + Math.sin(I*D_RAD+Math.PI/4) * TRADIUS;
                    _VERTS.push(new Particle(VX, VY));
                    _MIDS.push(new Particle());
                    d.push(new Particle(0, 0));
                    disp.push(new Particle(0, 0));
                    fdiv.push(0);
                    pvn.push(new Particle());
                }
                /**/
                break;
            case 3:
                //円
                head = 0;
                for(I = 0; I < VERT_COUNT; I++)
                {
                    VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * RADIUS;
                    VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * RADIUS;
                    _VERTS.push(new Particle(VX, VY));
                    _MIDS.push(new Particle());
                    d.push(new Particle(0, 0));
                    disp.push(new Particle(0, 0));
                    fdiv.push(0);
                    pvn.push(new Particle());
                }
                /**/
                break;
            case 4:
                //星
                head = 0;
                for(I = 0; I < VERT_COUNT; I++)
                {
                    CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI*2/5)-(Math.PI/5));
                    TRADIUS = RADIUS*1/2 + (RADIUS*1/2 * (CRADIUS)/(Math.PI/5));
                    VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
                    VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
                    _VERTS.push(new Particle(VX, VY));
                    _MIDS.push(new Particle());
                    d.push(new Particle(0, 0));
                    disp.push(new Particle(0, 0));
                    fdiv.push(0);
                    pvn.push(new Particle());
                }
                /**/
                break;
        }
        _VERTS.fixed = true;
        _MIDS.fixed = true;
        d.fixed = true;
        disp.fixed = true;
        fdiv.fixed = true;
        pvn.fixed = true;
        
        var NEXT_PARTICLE:Particle;
        var PREV_PARTICLE:Particle;
        var CURR_PARTICLE:Particle;
        var TARR:Array;
        for(I = 0; I < VERT_COUNT; I++)
        {
            J = (VERT_COUNT+I-1)%VERT_COUNT;  //PREV
            K = (I+1)%VERT_COUNT
            CURR_PARTICLE = _VERTS[I];
            PREV_PARTICLE = _VERTS[J];
            NEXT_PARTICLE = _VERTS[K];
            CURR_PARTICLE.upRADIAN   = calcRADIAN  (CENT_PARTICLE, CURR_PARTICLE);
            CURR_PARTICLE.downRADIAN = calcRADIAN  (CURR_PARTICLE, CENT_PARTICLE);
            CURR_PARTICLE.nextRADIAN = calcRADIAN  (CURR_PARTICLE, NEXT_PARTICLE);
            CURR_PARTICLE.prevRADIAN = calcRADIAN  (CURR_PARTICLE, PREV_PARTICLE);
            CURR_PARTICLE.hDISTANCE  = calcDISTANCE(CURR_PARTICLE, NEXT_PARTICLE);
            CURR_PARTICLE.vDISTANCE  = calcDISTANCE(CURR_PARTICLE, CENT_PARTICLE);
            TARR = [CURR_PARTICLE, NEXT_PARTICLE, CENT_PARTICLE];
            CURR_PARTICLE.AREA = calcAREA(TARR);  //FOR GAS
        }
    }
    
    private function   calcRADIAN(PA:*, PB:*):Number { return Math.atan2(PB.y - PA.y, PB.x - PA.x); }
    private function calcDISTANCE(PA:*, PB:*):Number 
    {
        var VX:Number = PB.x - PA.x;
        var VY:Number = PB.y - PA.y;
        return Math.sqrt(VX*VX+VY*VY);
    }
    
    private function calcMID():void
    {
        var I:int = 0;
        var J:int = 0;
        for (I=0; I<_VERTS.length; I++)
        {
            J = (I+1) % _VERTS.length;
            _MIDS[I].x = (_VERTS[I].x+_VERTS[J].x)/2;
            _MIDS[I].y = (_VERTS[I].y+_VERTS[J].y)/2;
        }
    }
    
////v0.1
    private function calcAREA(arr:Array):Number
    {
        var a:Number=0;
        var n1:*;
        var n2:*;
        for (var i:int=0; i<arr.length; i++)
        {
            n1 = arr[i];
            n2 = arr[(i+1)%arr.length];
            a += (n1.x-n2.x)*(n1.y+n2.y);
        }
        return a/2;
    }
    
    private function vertexNORMAL(np:*, n:*, nn:*):Particle
    {
        var dpx:Number=np.x-n.x;
        var dpy:Number=np.y-n.y;
        var dnx:Number=nn.x-n.x;
        var dny:Number=nn.y-n.y;

        var nx:Number=-dny;
        var ny:Number=dnx;
        var na:Number=Math.sqrt(nx*nx+ny*ny);
        if (na==0)
        {
            nx=1; ny=0;
        } else {
            nx/=na; ny/=na;
        }

        //rotate dp anti-clockwise by 90C
        var px:Number=dpy;
        var py:Number=-dpx;
        var pa:Number=Math.sqrt(px*px+py*py);
        if (pa==0)
        {
            px=1; py=0;
        } else {
            px/=pa; py/=pa;
        }

        var fx:Number=nx+px;
        var fy:Number=ny+py;
        var fa:Number=Math.sqrt(fx*fx+fy*fy);
        if (fa==0)
        {
            fx=1; fy=0;
        } else {
            fx/=fa; fy/=fa;
        }
        
        return new Particle(fx,fy);
    }
    
    // ボーンの向きを決定する
    private function rotate():void{
///v0.2
        var I:int = 0;
        var J:int = 0;
        var CURR_PARTICLE:Particle;
        var NEXT_PARTICLE:Particle;
        for(I = 0; I < _VERTS.length; I++)
        {
            J = (I+1)%_VERTS.length;
            CURR_PARTICLE = _VERTS[I];
            NEXT_PARTICLE = _VERTS[J];
            calcConnectRForce(CURR_PARTICLE, NEXT_PARTICLE, CURR_PARTICLE.nextRADIAN);
            calcConnectRForce(NEXT_PARTICLE, CURR_PARTICLE, NEXT_PARTICLE.prevRADIAN);
            calcConnectRForce(CURR_PARTICLE, CENT_PARTICLE, CURR_PARTICLE.downRADIAN);
            calcConnectRForce(CENT_PARTICLE, CURR_PARTICLE, CURR_PARTICLE.upRADIAN  );
            if (_DRAG_ID == I)
                CURR_PARTICLE.vr *= GB._MOUSE_ROTATE_FRICTION;
            else
                CURR_PARTICLE.vr *= GB._ROTATE_FRICTION;    // 摩擦
                
            CURR_PARTICLE.radian += CURR_PARTICLE.vr;
        }
        CENT_PARTICLE.vr *= GB._ROTATE_FRICTION;
        CENT_PARTICLE.radian += CENT_PARTICLE.vr;
    }
    // 接続されたパーツの回転方向を計算する
    private function calcConnectRForce(particle:Particle, targetParticle:Particle, connectAngle:Number):void{
        var angle:Number = Math.atan2(targetParticle.y - particle.y, targetParticle.x - particle.x);
        particle.vr += ajustRadian(angle - (connectAngle + particle.radian)) * GB._ROTATION_RATE;
    }

    private function force():void{
////v0.2
        var I:int = 0;
        var J:int = 0;
        var K:int = 0;
        var CURR_PARTICLE:Particle;
        var NEXT_PARTICLE:Particle;
        //var TARR:Array;
        var NEW_PARTICLE_AREA:Number = 0;
        var GAS_PRESSURE:Number = 0;
        var PREV_PARTICLE:Particle;
        var VERT_PARTICLE:Particle;
        var FCOMP:Number = 0;
        var AREA_DIFF:Number = 0;
        for(I = 0; I < _VERTS.length; I++)
        {
            CURR_PARTICLE = _VERTS[I];
            NEXT_PARTICLE = _VERTS[(I+1)%_VERTS.length];
            var TARR:Array = [CURR_PARTICLE, NEXT_PARTICLE, CENT_PARTICLE];
            NEW_PARTICLE_AREA = calcAREA(TARR);  //FOR GAS
            AREA_DIFF = NEW_PARTICLE_AREA - CURR_PARTICLE.AREA;
            FCOMP = (AREA_DIFF>100 || AREA_DIFF<-100)?0.00333:GB._COMP;
            GAS_PRESSURE = (AREA_DIFF)*FCOMP/TARR.length;
            for (J = 0; J < TARR.length; J++)
            {
                PREV_PARTICLE = TARR[(TARR.length+J-1)%TARR.length];
                CURR_PARTICLE = TARR[J];
                NEXT_PARTICLE = TARR[(J+1)%TARR.length];
                VERT_PARTICLE = vertexNORMAL(PREV_PARTICLE,CURR_PARTICLE,NEXT_PARTICLE);
                CURR_PARTICLE.vx += VERT_PARTICLE.x*GAS_PRESSURE;
                CURR_PARTICLE.vy += VERT_PARTICLE.y*GAS_PRESSURE;
            }
            /**/
            PREV_PARTICLE = _VERTS[(_VERTS.length+I-1)%_VERTS.length];
            CURR_PARTICLE = _VERTS[I];
            NEXT_PARTICLE = _VERTS[(I+1)%_VERTS.length];
            VERT_PARTICLE = vertexNORMAL(PREV_PARTICLE,CURR_PARTICLE,NEXT_PARTICLE);
            pvn[I].x = VERT_PARTICLE.x;
            pvn[I].y = VERT_PARTICLE.y;
            calcConnectFoce(CURR_PARTICLE, NEXT_PARTICLE, CURR_PARTICLE.nextRADIAN, CURR_PARTICLE.hDISTANCE, I, (I+1)%_VERTS.length);
            calcConnectFoce(NEXT_PARTICLE, CURR_PARTICLE, NEXT_PARTICLE.prevRADIAN, CURR_PARTICLE.hDISTANCE, (I+1)%_VERTS.length, I);
            calcConnectFoce(CURR_PARTICLE, CENT_PARTICLE, CURR_PARTICLE.downRADIAN, CURR_PARTICLE.vDISTANCE, I, -1);
            calcConnectFoce(CENT_PARTICLE, CURR_PARTICLE, CURR_PARTICLE.upRADIAN  , CURR_PARTICLE.vDISTANCE, -1, I);
            
            CURR_PARTICLE.ay += GB._GRAVITY;
            if (_DRAG_ID == I){    // マウスで引っ張る
                var point:Particle = pullForce(CURR_PARTICLE.x, CURR_PARTICLE.y, mouse_x, mouse_y, GB._MOUSE_PULL_RATE);
                CURR_PARTICLE.ax += point.x;
                CURR_PARTICLE.ay += point.y;
                CURR_PARTICLE.vx *= GB._MOUSE_MOVE_FRICTION;
                CURR_PARTICLE.vy *= GB._MOUSE_MOVE_FRICTION;
            }
        }
        CENT_PARTICLE.ay += GB._GRAVITY;
    }
    // 接続された2パーツの力を計算する
    private function calcConnectFoce(particle:Particle, targetParticle:Particle, connectAngle:Number, distance:Number, A:int, B:int):void{
        var toAngle:Number = ajustRadian(connectAngle + particle.radian);
        var toX:Number = particle.x + Math.cos(toAngle) * distance;
        var toY:Number = particle.y + Math.sin(toAngle) * distance;
        var ax:Number = (targetParticle.x - toX) * GB._VERTICAL_RATE;
        var ay:Number = (targetParticle.y - toY) * GB._VERTICAL_RATE;
        particle.ax += ax;
        particle.ay += ay;
        
        if(A<0)
        {
            cdiv++;
        } else {
            fdiv[A]++;
        }
        /**/
        targetParticle.ax -= ax;
        targetParticle.ay -= ay;
        
        if(B<0)
        {
            cdiv++;
        } else {
            fdiv[B]++;
        }
        /**/
    }
    
    // radian角度を、-π~πの範囲に修正する
    private function ajustRadian(radian:Number):Number{
        return radian - GB._PI2 * Math.floor( 0.5 + radian / GB._PI2);
    }
    // ポイントx1 y1を、ポイントx2 y2へ、係数rateだけ移動させる場合の、XYの力を返す
    private function pullForce(x1:Number, y1:Number, x2:Number, y2:Number, rate:Number):Particle{
        var point:Particle = new Particle();
        var distance:Number = calcDistance(x1, y1, x2, y2);
        
        var angle:Number = Math.atan2(y2 - y1, x2 - x1);
        point.x = Math.cos(angle) * distance * rate;
        point.y = Math.sin(angle) * distance * rate;
        return point;
    }
    // ポイントx1 y1から、ポイントx2 y2までの距離
    private function calcDistance(x1:Number, y1:Number, x2:Number, y2:Number):Number{
        return Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
    }
    
    private function updatePARTICLE(CURR_PARTICLE:Particle):void
    {
        CURR_PARTICLE.ax += -GB._FRICTION * CURR_PARTICLE.vx;
        CURR_PARTICLE.ay += -GB._FRICTION * CURR_PARTICLE.vy;
        
        // 速度、位置への反映
        CURR_PARTICLE.vx += CURR_PARTICLE.ax;
        CURR_PARTICLE.vy += CURR_PARTICLE.ay;
        CURR_PARTICLE.x  += CURR_PARTICLE.vx;
        CURR_PARTICLE.y  += CURR_PARTICLE.vy;
        CURR_PARTICLE.ax = 0;
        CURR_PARTICLE.ay = 0;    // 力をクリア
        
        // 壁チェック
        if (0 < CURR_PARTICLE.vy && GB._GROUND_LINE < CURR_PARTICLE.y){
            CURR_PARTICLE.y = GB._GROUND_LINE;
            CURR_PARTICLE.vy *= -0.8;
            if (CURR_PARTICLE.vy < -50) CURR_PARTICLE.vy = -50;
            CURR_PARTICLE.vx *= GB._GROUND_FRICTION;
        }
        if (CURR_PARTICLE.vx < 0 && CURR_PARTICLE.x < GB._WALL_LEFT){
            CURR_PARTICLE.x = GB._WALL_LEFT;
            CURR_PARTICLE.vx = 0;
            CURR_PARTICLE.vy *= GB._GROUND_FRICTION;
        }else if (0 < CURR_PARTICLE.vx && GB._WALL_RIGHT < CURR_PARTICLE.x){
            CURR_PARTICLE.x = GB._WALL_RIGHT;
            CURR_PARTICLE.vx = 0;
            CURR_PARTICLE.vy *= GB._GROUND_FRICTION;
        }
    }
    
    private function move():void
    {
////v0.2
        var I:int = 0;
        var CURR_PARTICLE:Particle;
        for(I = 0; I < _VERTS.length; I++)
        {
            updatePARTICLE(_VERTS[I]);
        }
        updatePARTICLE(CENT_PARTICLE);
    }
    
    public function detectDrag(m_x:Number, m_y:Number):void
    {
        var MAX_DISTANCE:Number = 9999;
        var VX:Number = 0;
        var VY:Number = 0;
        var DIST:Number = 0;
        for(var I:int = 0; I < _VERTS.length; I++)
        {
            VX = m_x - _VERTS[I].x;
            VY = m_y - _VERTS[I].y;
            DIST = Math.sqrt(VX*VX+VY*VY);
            if(DIST<MAX_DISTANCE && DIST<15)
            {
                MAX_DISTANCE = DIST;
                _DRAG_ID = I;
            }
        }
    }
    
    public function moveDrag(m_x:Number, m_y:Number):void
    {
        mouse_x = m_x; mouse_y = m_y;
    }
    
    public function cancelDrag():void
    {
        _DRAG_ID = -1;
    }
    
    public function setup():void
    {
        var i    :int = 0;
        var k    :int;
        var vx   :Number = 0;
        var vy   :Number = 0;
        var len  :Number = 0;
        var diff :Number = 0;
        var nx   :Number = 0;
        var ny   :Number = 0;
        var ux   :Number = 0;
        var uy   :Number = 0;
        var VI   :Particle;
        var VK   :Particle;
        
        for(i = 0; i < _VERTS.length; i++)
        {
            k = (i + 1) % _VERTS.length;
            VI = _VERTS[i];
            VK = _VERTS[k];
            vx = VK.x - VI.x;
            vy = VK.y - VI.y;
            len = Math.sqrt(vx * vx + vy * vy);
            diff = VI.nextRADIAN - len;

            nx = vx / len;
            ny = vy / len;

            ux = diff * nx;
            uy = diff * ny;

            d[i].x = nx;
            d[i].y = ny;
        }
    }
    
    public function update():void
    {
        //for (var i:int=0; i<GB._DERIVATION; i++){
        
            response();
            rotate();    // 回転の計算
            force();    // 力の計算
            move();    // 移動処理
        //}
        calcMID();
        //draw();    // 描画処理
    }
    
    private function response():void
    {
        var i:int = 0;
        var j:int = 0;
        var n1:Particle;
        var n2:Particle;
        var np:Particle;
        var n :Particle;
        var nn:Particle;
        var vn:Particle;
        var fx:Number=0;
        var fy:Number=0;
        var dx:Number=0;
        var dy:Number=0;
        var da:Number=0;
        var px:Number=0;
        var py:Number=0;
        var gx:Number =0;
        var gy:Number = 0;
        var vx:Number = 0;
        var vy:Number = 0;
        var xlen:Number = 0;
        var VI:Particle;
        var DI:Particle;

        for(i = 0; i < _VERTS.length; i++)
            if(fdiv[i] > 0)
            {
                VI = _VERTS[i];
                DI = disp[i];
                gx = DI.x / (fdiv[i]);
                gy = DI.y / (fdiv[i]);

                VI.x = VI.x + gx;
                VI.y = VI.y + gy;

                VI.vx = VI.vx + gx;
                VI.vy = VI.vy + gy;
                
                DI.x = 0.0;
                DI.y = 0.0;
                
                fdiv[i] = 0;

            }
    }
    
    public function inPoly(px:Number, py:Number):Boolean
    {
        var i:int, j:int;
        var c:Boolean = false;
        var VI:Particle;
        var VJ:Particle;
        for (i = 0, j = _VERTS.length-1; i < _VERTS.length; j = i++) {
            VI = _VERTS[i]; VJ = _VERTS[j];
            if ( ((VI.y>py) != (VJ.y>py)) && (px < (VJ.x-VI.x) * (py-VI.y) / (VJ.y-VI.y) + VI.x) )
                c = !c;
        }
        return c;
    }
    
    public function notTooClose(b:BlobPuyo):Boolean
    {
        return (calcDISTANCE(CENT_PARTICLE, b.CENT_PARTICLE)>RADIUS+b.RADIUS);
    }
    
    public function intersected(p1:*, p2:*, p3:*, p4:*):Boolean
    {
        var s1_x:Number, s1_y:Number, s2_x:Number, s2_y:Number;
        s1_x = p2.x - p1.x;     s1_y = p2.y - p1.y;
        s2_x = p4.x - p3.x;     s2_y = p4.y - p3.y;
    
        var s:Number, t:Number;
        s = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / (-s2_x * s1_y + s1_x * s2_y);
        t = ( s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / (-s2_x * s1_y + s1_x * s2_y);
    
        if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
        {
            return true;
        }
    
        return false;
    }
    
    public function xcontact(blob:BlobPuyo):void
    {
        if(notTooClose(blob)) return; 
        var i:int = 0;
        var j:int;
        var l:int = 0;
        var k:int = 0;
        var o:int = 0;
        var sx:Number = 0;
        var sy:Number = 0;
        var angle:Number = 0;
        var cosa:Number = 0;
        var sina:Number = 0;
        var x1:Number = 0;
        var y1:Number = 0;
        var vx1:Number = 0;
        var yb:Number = 0;
        var vy1:Number = 0;
        var yy1:Number = 0;
        var adj:Number = 0;
        
        var gx   :Number = 0;
        var gy   :Number = 0;
        var cx   :Number = 0;
        var cy   :Number = 0;
        var dp   :Number = 0;
        var f1   :Number = 0;
        var f2   :Number = 0;
        var vx   :Number = 0;
        var vy   :Number = 0;
        var len  :Number = 0;
        var diff :Number = 0;

        var bvx:Number = 0;
        var bvy:Number = 0;
        var blen:Number = 0;
        var pavn:Particle = new Particle(0, 0);
        
        var VI:Particle;
        var VK:Particle;
        var VO:Particle;
        var BV:Particle;
        var DI:Particle;
        var BD:Particle;
        var BDJ:Particle;
        var BDK:Particle;
        var PV:Particle;

        for(i = 0; i < _VERTS.length; i++) {
            VI = _VERTS[i];
            DI = disp[i];
            PV = pvn[i];
            if(blob.inPoly(VI.x, VI.y))
            {
                j = (i+1) % _VERTS.length;
                BDJ = blob.disp[j];
                for(o = 0; o < blob._VERTS.length; o++) {
                    k = (o+1) % blob._VERTS.length;
                    VO = blob._VERTS[o];
                    VK = blob._VERTS[k];
                    BD = blob.d[o];
                    BDK = blob.disp[k];
                    
                    //if(inBetween(_VERTS[o], _VERTS[i], _VERTS[l]) || ){
                        sx = VI.x-VO.x;
                        sy = VI.y-VO.y;
                        angle = Math.atan2(VK.y-VO.y,VK.x-VO.x);
                        cosa = Math.cos(angle);
                        sina = Math.sin(angle);
                        x1 = sx*cosa+sy*sina;
                        y1 = sy*cosa-sx*sina;

                        pavn.x = VI.x + PV.x * RADIUS;
                        pavn.y = VI.y + PV.y * RADIUS;

                        if (y1>0 && intersected(VI, pavn, VK, VO)) {
                            
                            vx = VI.x - VO.x;
                            vy = VI.y - VO.y;
                            
                            dp = vx * BD.x + vy * BD.y;
    
                            bvx = VK.x-VO.x;
                            bvy = VK.y-VO.y;
                            
                            blen = Math.sqrt(bvx*bvx+bvy*bvy);

                            cx = VO.x + dp * BD.x;
                            cy = VO.y + dp * BD.y;
                            
                            vx = VI.x - cx;
                            vy = VI.y - cy;
                            
                            diff = 4 /4;
                            gx = diff * vx;
                            gy = diff * vy;

                            DI.x -= gx;
                            DI.y -= gy;
                            fdiv[i]++;

                            f1 = dp / blen;
                            f2 = 1.0 - f1;

                            BDJ.x += f2 * gx;
                            BDJ.y += f2 * gy;
                            blob.fdiv[j]++;
                            BDK.x += f1 * gx;
                            BDK.y += f1 * gy;
                            blob.fdiv[k]++;
    
                            VI.vx = vx1*cosa-vy1*sina;
                            VI.vy = vy1*cosa+vx1*sina;
                            VI.x += VI.vx;
                            VI.y += VI.vy;
                            break;
                        }
                    }
                //}
            }
        }
    }
}

class Particle
{
    public var x:Number = 0;    // 位置
    public var y:Number = 0;
    public var vx:Number = 0;    // 速度
    public var vy:Number = 0;
    public var ax:Number = 0;    // 加速度=力    TOTO:最後まで意味無かったら消す
    public var ay:Number = 0;
    
    public var radian:Number = 0;    // 向き
    public var vr:Number = 0;    // 向き速度
    
    //public var color:uint = 0x000000;    // パーティクルの色。右下の枠の色
    //public var connect:Array = [true, true, true, true];    // パーティクルの接続状態を毎回チェックしなくていいように、保持しておく
////v0.2
    public var   upRADIAN :Number = 0;
    public var downRADIAN :Number = 0;
    public var prevRADIAN :Number = 0;
    public var nextRADIAN :Number = 0;
    public var       AREA :Number = 0;
    public var  vDISTANCE :Number = 0;
    public var  hDISTANCE :Number = 0;
    
    public function Particle(px:Number = 0, py:Number = 0) { x = px; y = py; }
}

class GB {
    public static const _WALL_LEFT             :Number = 0;
    public static const _WALL_RIGHT            :Number = 465;
    public static const _GROUND_LINE           :Number = 350;
    
    public static const _DOT_CONNECT_MAX       :int    = 4;
    public static const _DERIVATION            :int    = 3;    // 計算の分割数。  //3
    public static const _MAP_SIZE              :Number = 400;
    
    public static const _PI                    :Number = Math.PI;
    public static const _PI2                   :Number = 2.0 * _PI;
    public static const _RADIAN90              :Number = _PI * 0.5;
    public static const _RADIAN180             :Number = _PI * 1.0;
    public static const _RADIAN270             :Number = _PI * -0.5;
////v0.2
    public static const _RADIAN360             :Number = _PI * 2;
    public static const _TO_DEGREE             :Number = 180 / _PI;
    
    public static const _COMP                  :Number = 0.0133;  //0.1
    public static const _GRAVITY               :Number = 0.6 / _DERIVATION;  //0.3  //0.6
    public static const _ROTATION_RATE         :Number = 0.05 / _DERIVATION;    // 自身バネ(根元) //0.05
    public static const _VERTICAL_RATE         :Number = 0.166 / _DERIVATION;    // ターゲットバネ(さきっぽ) //0.2  //0.133
    public static const _MOUSE_PULL_RATE       :Number = 2.0 / _DERIVATION;
    
    public static const _FRICTION              :Number = 0.1 / _DERIVATION;
    public static const _ROTATE_FRICTION       :Number = 1 - 0.2 / _DERIVATION;
    public static const _MOUSE_ROTATE_FRICTION :Number = 1 - 0.8 / _DERIVATION;
    public static const _MOUSE_MOVE_FRICTION   :Number = 1 - 0.5 / _DERIVATION;
    public static const _GROUND_FRICTION       :Number = 1 - 0.5 / _DERIVATION;  // 1 - 0.2  // 1 - 0.5
    
    public function GB() {}
}