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

mercury ball

drag to interact
Get Adobe Flash player
by zob 18 Jan 2011
/**
 * Copyright zob ( http://wonderfl.net/user/zob )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3U1P
 */

package  {
    import flash.display.Sprite
    import flash.display.Loader;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Shape;
    import flash.display.TriangleCulling;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.utils.Dictionary;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Vector3D;
    import flash.geom.Matrix3D;
    import flash.geom.Point;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Utils3D;
    import flash.events.KeyboardEvent;
    import com.bit101.components.Label;
    import com.bit101.components.HUISlider;
    import com.bit101.components.InputText;
    import com.bit101.components.PushButton;
    import com.bit101.components.RotarySelector;
    import com.bit101.components.NumericStepper;

    public class IcoSphere extends Sprite {
        private var icoSphere      :IcoSphereCreator      = new IcoSphereCreator(0,-400,0);
        private var matrix         :Matrix3D              = new Matrix3D();
        private var drag           :Boolean               = false;
        private var start_m        :Vector3D              = new Vector3D();
        private var old_mouse      :Vector3D              = new Vector3D();
        private var new_mouse      :Vector3D              = new Vector3D();
        private var center         :Point                 = new Point(stage.stageWidth/2, stage.stageHeight/2);
        
        private var loader         :Loader;
        private var MAP            :BitmapData;
        private var GRAPHIC_URL    :String                = "http://www.k3lab.com/wonderfl/Amphisbaena/photo.jpg";
        
        private var viewport       :Shape                 = new Shape();
        private var world          :Matrix3D              = new Matrix3D();
        private var projected      :Vector.<Number>       = new Vector.<Number>;
        private var projection     :PerspectiveProjection = new PerspectiveProjection();
        
        private var gwidth         :int                   = 200;
        private var gheight        :int                   = 200;
        private var land_bmpd      :BitmapData            = new BitmapData(1, 1,false,0x0);
        private var landVertices   :Vector.<Number>       = new Vector.<Number>(0, false);
        private var landProjected  :Vector.<Number>       = new Vector.<Number>(0, false);
        private var landIndices    :Vector.<int>          = new Vector.<int>(0, false);
        private var landUvtData    :Vector.<Number>       = new Vector.<Number>(0, false);
        
        private var dragging       :Point                 = new Point();
        private var mouseStart     :Point                 = new Point();
        private var mouse3D        :Vector3D              = new Vector3D();
        
        private var dragMode       :Boolean               = true;
        
        private var levelLabel     :Label;
        private var levelStepper   :NumericStepper;
        private var sizeSlider     :HUISlider;
        private var shapeSelector  :RotarySelector;
        private var regenButton    :PushButton;
        
        private var regen          :Boolean               = false;
        
        public function IcoSphere() {
            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, init);
            loader.load(new URLRequest(GRAPHIC_URL), new LoaderContext(true));
        }
        
        private function init(e:Event):void
        {
            MAP = Bitmap(loader.content).bitmapData;
            viewport.x = stage.stageWidth / 2;
            viewport.y = stage.stageHeight / 2;

            addChild(viewport);
            var bitmap:Bitmap = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x0));
            var hidden:Sprite = new Sprite();
            addChild(hidden);
            hidden.addChild(bitmap);
            var panel:Sprite = new Sprite();
            addChild(panel);
            levelLabel = new Label(panel, 5, 5, "Level");
            levelStepper = new NumericStepper(panel, 35, 5, null);
            sizeSlider = new HUISlider(panel, 5, 22, "size", null);
            shapeSelector = new RotarySelector(panel, 195, 8, "shape", null);
            new PushButton(panel, 90, 5, "Give me ball!", regenerateBall).setSize(83, 16);
            
            levelStepper.setSize(50, 20);
            levelStepper.value = 2;
            levelStepper.minimum = 0;
            levelStepper.maximum = 3;
            sizeSlider.value = 50;
            sizeSlider.minimum = 20;
            sizeSlider.maximum = 100;
            shapeSelector.setSize(20,20);
            shapeSelector.numChoices = 2;
            shapeSelector.choice = 0;
            /*
            levelSlider = new HUISlider(panel, 80, 10, "Level", updateBaseX);
            levelSlider.value = 2;
            levelSlider.minimum = 0;
            levelSlider.maximum = 3;
            /**/
            
            icoSphere.Create(2);
            constructLand();
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown);
            //stage.addEventListener(KeyboardEvent.KEY_UP, onkeyUp);
            hidden.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
            hidden.addEventListener(MouseEvent.MOUSE_MOVE, onmouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onmouseUp);
            addEventListener(Event.ENTER_FRAME, processing);
        }
        
        private function regenerateBall(...arg):void
        {
            regen = true;
        }
        
        private function constructLand():void
        {
            landVertices.push(-gwidth/2, GB._GROUND_LINE, gheight/2); //TR
            landVertices.push(gwidth/2, GB._GROUND_LINE, gheight/2); //BR
            landVertices.push(-gwidth/2, GB._GROUND_LINE, -gheight/2); //TL
            landVertices.push(gwidth/2, GB._GROUND_LINE, -gheight/2); //BL
            landUvtData.push(0, 0, 0); //0
            landUvtData.push(1, 0, 0); //1
            landUvtData.push(0, 1, 0); //2
            landUvtData.push(1, 1, 0); //3
            landIndices.push(0, 2, 1, 2, 3, 1);
        }
        
        private function processing(e:Event):void
        {
            update();
            paint();
            if(regen)
            {
                icoSphere = new IcoSphereCreator(0,-400,0);
                icoSphere.size = sizeSlider.value;
                icoSphere.shape = shapeSelector.choice;
                icoSphere.Create(levelStepper.value);
                projected = new Vector.<Number>;
                regen = !regen;
            }
        }
        
        private function update():void
        {
            icoSphere.update(matrix);
        }
        
        private function paint():void
        {
            world.identity();
            world.append(matrix);
            
            world.appendTranslation(0, 0, 500);
            world.append(projection.toMatrix3D());
            
            viewport.graphics.clear();
            
            Utils3D.projectVectors(world, landVertices, landProjected, landUvtData);
            viewport.graphics.beginBitmapFill(land_bmpd, null, false, false);
            viewport.graphics.drawTriangles(landProjected, landIndices, landUvtData, TriangleCulling.POSITIVE);
            viewport.graphics.endFill();
            
            Utils3D.projectVectors(world, icoSphere.vertices, projected, icoSphere.uvts);
            viewport.graphics.beginBitmapFill(MAP, null, false, false);
            viewport.graphics.drawTriangles(projected, icoSphere.sortedIndices, icoSphere.uvts, TriangleCulling.POSITIVE);
            viewport.graphics.endFill();
        }
        
        private function onkeyDown(e:KeyboardEvent):void
        {
            dragMode = !dragMode;
        }

        private function onmouseDown(e:MouseEvent):void
        {
            drag = true;
            old_mouse.x = mouseX;
            old_mouse.y = mouseY;
            
            
            mouseStart.x = mouseX;
            mouseStart.y = mouseY;
            var dist:Number = 99999;
            var finder:int = -1;
            var tv1:Vector3D = new Vector3D();
            var tv2:Vector3D = new Vector3D();
            var tp1:Point = new Point();
            var tp2:Point = new Point();
            var tvp:Vector3D = new Vector3D();
            var ratio:Number = 0;
            var focalLength:Number = 500;
            var i:int = 0;
            var currdist:Number = 0;
            var currdist3D:Number = 0;
            
            var joints:Vector.<Joint> = icoSphere.joints;
            for(i = 0; i < joints.length; i++)
            {
                tv1 = matrix.transformVector(joints[i]);
                ratio = focalLength/(focalLength + tv1.z);
                tp1.x = tv1.x * ratio + center.x;
                tp1.y = tv1.y * ratio + center.y;
                currdist = Point.distance(tp1, new Point(mouseX, mouseY));
                
                if(currdist < 10)
                {
                    tvp.x = tv1.x;
                    tvp.y = tv1.y;
                    tvp.z = tv1.z;
                    currdist3D = Vector3D.distance(tvp, new Vector3D(mouseX-center.x, mouseY-center.y, -10000));
                    
                    if(currdist3D < dist)
                    {
                        dist = currdist3D;
                        finder = i;
                    }
                }
            }
            dragMode = finder == -1;
            if(!dragMode) icoSphere.dragAt(finder);
            
        }
        
        private function onmouseUp(e:MouseEvent):void
        {
            drag = false;
            icoSphere.undrag();
        }
        
        private function onmouseMove(e:MouseEvent):void
        {
            new_mouse.x = mouseX;
            new_mouse.y = mouseY;
            
            if(drag)
            if(dragMode)
            {
                var difference:Vector3D = new Vector3D(new_mouse.x - old_mouse.x, new_mouse.y - old_mouse.y);
                var vector:Vector3D = new Vector3D(difference.x, difference.y, 0);
 
                var rotationAxis:Vector3D = vector.crossProduct(new Vector3D(0,0,1));
                rotationAxis.normalize();
                
                var distance:Number = Math.sqrt(difference.x * difference.x + difference.y * difference.y);
                var rotationMatrix:Matrix3D = new Matrix3D();
                rotationMatrix.appendRotation(distance/150*180/Math.PI, rotationAxis);
                matrix.append(rotationMatrix);
            }
            else
            {
                var vx:Number = mouseX - mouseStart.x;
                var vy:Number = mouseY - mouseStart.y;
                var im:Matrix3D = matrix.clone();
                im.invert();
                var new_offset:Vector3D = im.transformVector(new Vector3D(vx, vy, 0));
                icoSphere.updateOffset(new_offset);
            }
            
            old_mouse.x = mouseX;
            old_mouse.y = mouseY;
        }
    }
    
}
import flash.geom.Vector3D;
import flash.utils.Dictionary;

class TriangleIndices
{
    public var v1:int;
    public var v2:int;
    public var v3:int;

    public function TriangleIndices(A:int, B:int, C:int)
    {
        v1 = A;
        v2 = B;
        v3 = C;
    }
}

// Icosphere generator from http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
// with some modification
class IcoSphereCreator
{
    private var index:int;
    private var middlePointIndexCache:Dictionary;// = new Dictionary(true);
    public var ifaces:Vector.<TriangleIndices>;
    public var sfaces:Array = new Array();
    public var faces:Vector.<Face3D> = new Vector.<Face3D>();
    public var joints:Vector.<Joint> = new Vector.<Joint>();
    private var jointCache:Dictionary;
    public var position:Joint = new Joint();
    
    public var vertices:Vector.<Number> = new Vector.<Number>();
    public var indices:Vector.<int> = new Vector.<int>();
    public var uvts:Vector.<Number> = new Vector.<Number>();
    public var sortedIndices:Vector.<int> = new Vector.<int>();
    
    public var dragging:int = -1;
    public var locked:Joint = new Joint();
    private var offset:Joint = new Joint();
    
    public var size:Number = 50;
    public var shape:int = 0;

    public function IcoSphereCreator(px:Number = 0, py:Number = 0, pz:Number = 0) {position.read(px, py, pz);}

    // add vertex to mesh, fix position to be on unit sphere, return index
    private function addVertex(p:Vector3D):int
    {
        var length:Number = Math.sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
        if(!shape)
               joints.push(new Joint(p.x/length, p.y/length, p.z/length));
        else
            joints.push(new Joint(p.x, p.y, p.z));
        return index++;
    }

    // return index of point in the middle of p1 and p2
    private function getMiddlePoint(p1:int, p2:int):int
    {
        // first check if we have it already
        var firstIsSmaller:Boolean = p1 < p2;
        var smallerIndex:uint = firstIsSmaller ? p1 : p2;
        var greaterIndex:uint = firstIsSmaller ? p2 : p1;
        var key:uint = (smallerIndex << 16) + greaterIndex;
        var ret:int;
        if (ret = middlePointIndexCache[key])
        {
            return ret;
        }

        // not in cache, calculate it
        var point1:Joint = joints[p1];
        var point2:Joint = joints[p2];
        var middle:Joint = new Joint((point1.x + point2.x) / 2.0, (point1.y + point2.y) / 2.0, (point1.z + point2.z) / 2.0);

        // add vertex makes sure point is on unit sphere
        var i:int = addVertex(middle); 

        // store it, return index
        middlePointIndexCache[key] = i;
        return i;
    }

    //public MeshGeometry3D Create(int recursionLevel)
    public function Create(recursionLevel:int):void
    {
        //this.geometry = new MeshGeometry3D();
        middlePointIndexCache = new Dictionary(true);
        index = 0;

        // create 12 vertices of a icosahedron
        var t:Number = (1.0 + Math.sqrt(5.0)) / 2.0;

        addVertex(new Joint(-1,  t,  0));
        addVertex(new Joint( 1,  t,  0));
        addVertex(new Joint(-1, -t,  0));
        addVertex(new Joint( 1, -t,  0));

        addVertex(new Joint( 0, -1,  t));
        addVertex(new Joint( 0,  1,  t));
        addVertex(new Joint( 0, -1, -t));
        addVertex(new Joint( 0,  1, -t));

        addVertex(new Joint( t,  0, -1));
        addVertex(new Joint( t,  0,  1));
        addVertex(new Joint(-t,  0, -1));
        addVertex(new Joint(-t,  0,  1));


        // create 20 triangles of the icosahedron
        ifaces = new Vector.<TriangleIndices>();

        // 5 faces around point 0
        ifaces.push(new TriangleIndices(0, 11, 5));
        ifaces.push(new TriangleIndices(0, 5, 1));
        ifaces.push(new TriangleIndices(0, 1, 7));
        ifaces.push(new TriangleIndices(0, 7, 10));
        ifaces.push(new TriangleIndices(0, 10, 11));

        // 5 adjacent faces 
        ifaces.push(new TriangleIndices(1, 5, 9));
        ifaces.push(new TriangleIndices(5, 11, 4));
        ifaces.push(new TriangleIndices(11, 10, 2));
        ifaces.push(new TriangleIndices(10, 7, 6));
        ifaces.push(new TriangleIndices(7, 1, 8));

        // 5 faces around point 3
        ifaces.push(new TriangleIndices(3, 9, 4));
        ifaces.push(new TriangleIndices(3, 4, 2));
        ifaces.push(new TriangleIndices(3, 2, 6));
        ifaces.push(new TriangleIndices(3, 6, 8));
        ifaces.push(new TriangleIndices(3, 8, 9));

        // 5 adjacent faces 
        ifaces.push(new TriangleIndices(4, 9, 5));
        ifaces.push(new TriangleIndices(2, 4, 11));
        ifaces.push(new TriangleIndices(6, 2, 10));
        ifaces.push(new TriangleIndices(8, 6, 7));
        ifaces.push(new TriangleIndices(9, 8, 1));

        var i:int = 0
        var tri:TriangleIndices;
        // refine triangles
        for (i = 0; i < recursionLevel; i++)
        {
            var faces2:Vector.<TriangleIndices> = new Vector.<TriangleIndices>();
            for each (tri in ifaces)
            {
                // replace triangle by 4 triangles
                var a:int = getMiddlePoint(tri.v1, tri.v2);
                var b:int = getMiddlePoint(tri.v2, tri.v3);
                var c:int = getMiddlePoint(tri.v3, tri.v1);

                faces2.push(new TriangleIndices(tri.v1, a, c));
                faces2.push(new TriangleIndices(tri.v2, b, a));
                faces2.push(new TriangleIndices(tri.v3, c, b));
                faces2.push(new TriangleIndices(a, b, c));
            }
            ifaces = faces2;
        }
        
        for(i = 0; i < joints.length; i++)
        {
            //positions[i].normalize();
            //joints[i].scaleBy(GB._RADIUS);
            joints[i].scaleBy(size);
            joints[i].x += position.x;
            joints[i].y += position.y;
            joints[i].z += position.z;
            joints[i].addConstraint(position);
            vertices.push(joints[i].x, joints[i].y, joints[i].z);
            uvts.push(0,0,0);
        }
        
        jointCache = new Dictionary(true);
        var f:int = 0;
        for(i = 0; i < ifaces.length; i++)
        {
            addJoint(ifaces[i].v1, ifaces[i].v2);
            addJoint(ifaces[i].v2, ifaces[i].v3);
            addJoint(ifaces[i].v1, ifaces[i].v3);
            f = faces.length;
            faces.push(createFace(ifaces[i].v1, ifaces[i].v2, ifaces[i].v3));
            sfaces.push(new Vector3D());
            joints[ifaces[i].v1].faces.push(faces[f]);
            joints[ifaces[i].v2].faces.push(faces[f]);
            joints[ifaces[i].v3].faces.push(faces[f]);
            indices.push(ifaces[i].v1, ifaces[i].v2, ifaces[i].v3);
            sortedIndices.push(ifaces[i].v1, ifaces[i].v2, ifaces[i].v3);
        }     
    }
    
    private function addJoint(A:int, B:int):void
    {
        // first check if we have it already
        var firstIsSmaller:Boolean = A < B;
        var smallerIndex:uint = firstIsSmaller ? A : B;
        var greaterIndex:uint = firstIsSmaller ? B : A;
        var key:uint = (smallerIndex << 16) + greaterIndex;
        if (jointCache[key])
        {
            return;
        }

        joints[A].addConstraint(joints[B]);

        // store it, return index
        jointCache[key] = true;
    }
    
    private function createFace(A:int, B:int, C:int):Face3D
    {
        return new Face3D(joints[A], joints[B], joints[C]);
    }
    
    private function calcNORMS():void
    {
        var i:int = 0;
        for(i = 0; i < faces.length; i++)
        {
            faces[i].calculateFaceNormal();
        }
    }
    
    public function updateOffset(m:Vector3D):void
    {
        offset.eat(m);
    }
    
    public function dragAt(i:int):void
    {
        locked.eat(joints[dragging = i]);
    }
    
    public function undrag():void
    {
        dragging = -1;
    }
    
    public function update(trans:Matrix3D):void
    {
        var j:Joint;
        for each(j in joints) j.updateRForce(dragging >= 0 && joints[dragging]==j);
        for each(j in joints) j.updateForce(dragging >= 0 && joints[dragging]==j, locked.add(offset)/**/);
        for each(j in joints) j.move();
        position.updateRForce();
        position.updateForce();
        position.move();
        calcNORMS();
        var i:int = 0;
        for(i = 0; i < joints.length; i++)
        {
            joints[i].calculateNorm();
            joints[i].norm = trans.transformVector(joints[i].norm);
            //joints[i].norm = joints[i].norm;
            vertices[i*3  ] = joints[i].x;
            vertices[i*3+1] = joints[i].y;
            vertices[i*3+2] = joints[i].z;
            uvts[i*3  ] = 0.5+joints[i].norm.x*0.5;
            uvts[i*3+1] = 0.5+joints[i].norm.y*0.5;
            uvts[i*3+2] = 0.5+joints[i].norm.z*0.5;
        }
        resort();
    }
    
    public function resort():void
    {
        var i:int = 0;
        var face:Vector3D;
        var inc:int = 0;
        var i1:uint = 0x0;
        var i2:uint = 0x0;
        var i3:uint = 0x0;
        for (i = 0; i < indices.length; i+=3){
            i1 = indices[ i+0 ];
            i2 = indices[ i+1 ];
            i3 = indices[ i+2 ];
            face = sfaces[inc];
            face.x = i1;
            face.y = i2;
            face.z = i3;
            face.w = (uvts[i1 * 3 + 2] + uvts[i2 * 3 + 2] + uvts[i3 * 3 + 2]) * 0.333333;
            inc++;
        }
        sfaces.sortOn("w", Array.DESCENDING | Array.NUMERIC);
        inc = 0;
        for each (face in sfaces){
            sortedIndices[inc++] = face.x;
            sortedIndices[inc++] = face.y;
            sortedIndices[inc++] = face.z;
        }
    }
}

import flash.geom.Vector3D;
import flash.geom.Matrix3D;

class Joint extends Vector3D
{
    private var vertices:Vector.<int> = new Vector.<int>();
    private var angles:Matrix3D = new Matrix3D();
    private var vr:Matrix3D = new Matrix3D();
    public var constraints:Vector.<Constraint> = new Vector.<Constraint>();
    public var faces:Vector.<Face3D> = new Vector.<Face3D>();
    public var fixed:Boolean = false;
    public var locked:Boolean = false;
    public var a:Vector3D = new Vector3D();
    public var vt:Vector3D = new Vector3D();
    public var norm:Vector3D = new Vector3D();
    
    //temp
    public var verts:Vector.<Vector3D> = new Vector.<Vector3D>();
    public var vert:Vector3D = new Vector3D();
    
    public function Joint(px:Number = 0, py:Number = 0, pz:Number = 0)
    {
        super(px, py, pz);
    }
    
    public function eat(j:Vector3D):Joint
    {
        x = j.x; y = j.y; z = j.z; return this;
    }
    
    public function read(px:Number = 0, py:Number = 0, pz:Number = 0):Joint
    {
        x = px; y = py; z = pz; return this;
    }
    
    public function checkConnection(v:Joint):void
    {
        if(!locked && v.locked && Vector3D.distance(Vector3D(this), v) < GB._DISTANCE)
        {
            addConstraint(v, GB._DISTANCE);
            locked = true;
        }
    }
    
    public function addConstraint(v:Joint, d:Number = -1):void
    {
        constraints.push(new Constraint(this, v, d));
    }
    
    public function has(v:Joint):Boolean
    {
        for each(var c:Constraint in constraints) if(c.to == v) return true;
        return false;
    }
    
    public function updateConnectRForce(c:Constraint):void
    {
        connectRForce(this, c.to, c.vTo);
        connectRForce(c.to, this, c.vFrom);
    }
    
    public function connectRForce(aj:Joint, bj:Joint, cv:Vector3D):void
    {
        var CURR_VECTOR:Vector3D = bj.subtract(Vector3D(aj));
        var NEW_VECTOR:Vector3D = aj.angles.transformVector(cv);
        var degree:Number = Vector3D.angleBetween(NEW_VECTOR, CURR_VECTOR);
        if(isNaN(degree)) degree = 0;
        var right:Vector3D = NEW_VECTOR.crossProduct(CURR_VECTOR);
        right.normalize();
        var matrix:Matrix3D = new Matrix3D();
        matrix.identity();
        matrix.appendRotation(degree/Math.PI*180, right);
        aj.vr.append(Matrix3D.interpolate(GB._originMATRIX, matrix, GB._ROTATION_RATE));
    }
    
    public function updateConnectForce(c:Constraint):void
    {
        connectForce(this, c.to, c.vTo);
        connectForce(c.to, this, c.vFrom);
    }
    
    public function connectForce(aj:Joint, bj:Joint, cv:Vector3D):void
    {
        var v:Vector3D = aj.angles.transformVector(cv);
        var toVector:Vector3D = aj.add(v);
        var ax:Number = (bj.x - toVector.x) * GB._VERTICAL_RATE;
        var ay:Number = (bj.y - toVector.y) * GB._VERTICAL_RATE;
        var az:Number = (bj.z - toVector.z) * GB._VERTICAL_RATE;
        aj.a.x += ax;
        aj.a.y += ay;
        aj.a.z += az;
        bj.a.x -= ax;
        bj.a.y -= ay;
        bj.a.z -= az;
    }
    
    public function move():void
    {
        a.x += -GB._FRICTION * vt.x;
        a.y += -GB._FRICTION * vt.y;
        a.z += -GB._FRICTION * vt.z;
        vt.x += a.x;
        vt.y += a.y;
        vt.z += a.z;
        x += vt.x;
        y += vt.y;
        z += vt.z;
        a.x = 0;
        a.y = 0;
        a.z = 0;
        if (GB._GROUND_LINE < y){
            y = GB._GROUND_LINE;
            vt.y *= -GB._GBOUNCE;
            if (vt.y < -30) vt.y = -50;
            vt.x *= GB._GROUND_FRICTION;
            vt.z *= GB._GROUND_FRICTION;
        }
        
        vert = angles.transformVector(new Vector3D(1,0,0));
        vert.scaleBy(20);
    }
    
    public function updateRForce(k:Boolean = false):void
    {
        for each(var cR:Constraint in constraints)
        {
            updateConnectRForce(cR);
        }
        vr = Matrix3D.interpolate(GB._originMATRIX, vr, (k)?GB._MOUSE_ROTATE_FRICTION:GB._ROTATE_FRICTION);
        angles.append(vr);
    }
    
    public function updateForce(k:Boolean = false, m:Vector3D = null):void
    {
        for each(var c:Constraint in constraints)
        {
            updateConnectForce(c);
        }
        a.y += GB._GRAVITY;
        if (k)
        {
            var point:Joint = pullForce(this, m, GB._MOUSE_PULL_RATE);
            a.x += point.x;
            a.y += point.y;
            a.z += point.z;
            
            vt.x *= GB._MOUSE_MOVE_FRICTION;
            vt.y *= GB._MOUSE_MOVE_FRICTION;
            vt.z *= GB._MOUSE_MOVE_FRICTION;
        }
    }
    
    private function pullForce(A:Vector3D, B:Vector3D, rate:Number):Joint {
        var dist:Number = Vector3D.distance(A,B);
        return (dist>0)?new Joint((B.x - A.x) / dist * rate, (B.y - A.y) / dist * rate, (B.z - A.z) / dist * rate):new Joint();
    }
    
    public function calculateNorm():void
    {
        var I:int = 0;
        //norm.x = x; norm.y = y; norm.z = z;
        //norm.normalize();
        norm.x = 0; norm.y = 0; norm.z = 0;
        for(I = 0; I < faces.length; I++)
        {
            norm.x += faces[I].norm.x;
            norm.y += faces[I].norm.y;
            norm.z += faces[I].norm.z;
        }
        norm.normalize();
    }
}

class Constraint
{
    public var to:Joint;
    public var vTo:Vector3D;
    public var vFrom:Vector3D;
    public function Constraint(J:Joint, v:Joint, d:Number = -1)
    {
        to = v;
        vTo = to.subtract(Vector3D(J));
        vFrom = J.subtract(Vector3D(to));
        if(d>=0)
        {
            vTo.normalize();
            vTo.scaleBy(d);
            vFrom.normalize();
            vFrom.scaleBy(d);
        }
    }
}

class Face3D
{
    public var vertex1:Joint;
    public var vertex2:Joint;
    public var vertex3:Joint;
    public var norm:Vector3D = new Vector3D();
    public function Face3D(A:Joint, B:Joint, C:Joint) {vertex1 = A; vertex2 = B; vertex3 = C;}
    
    public function calculateFaceNormal():void
    {
        var TV2:Vector3D = vertex2.subtract(vertex1);
        var TV3:Vector3D = vertex3.subtract(vertex1);
        norm = TV2.crossProduct(Vector3D(TV3));
        norm.normalize();
    }
}

class GB
{
    public static const _DISTANCE              :Number = 30;
    public static const _LIMIT_DISTANCE        :Number = 50;
    public static const _WALL_LEFT             :Number = 0;
    public static const _WALL_RIGHT            :Number = 465;
    public static const _GROUND_LINE           :Number = 150;
    
    public static const _DOT_CONNECT_MAX       :int    = 4;
    public static const _DERIVATION            :int    = 5;    // 計算の分割数。  //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 _RADIUS                :Number = 50;
    
    public static const _MAXCOMP               :Number = 0.0000133;
    public static const _COMP                  :Number = 0.0000133;  //0.1
    public static const _GRAVITY               :Number = 0.3 / _DERIVATION;  //0.3  //0.6
    public static const _ROTATION_RATE         :Number = 0.03 / _DERIVATION;    // 自身バネ(根元) //0.05
    public static const _VERTICAL_RATE         :Number = 0.01 / _DERIVATION;    // ターゲットバネ(さきっぽ) //0.2  //0.133
    public static const _MOUSE_PULL_RATE       :Number = 10 / _DERIVATION;
    
    public static const _GBOUNCE               :Number = 0.8;  // 0.8
    
    public static const _FRICTION              :Number = 0.1 / _DERIVATION;      // 0.1
    public static const _ROTATE_FRICTION       :Number = 1 - 0.2 / _DERIVATION;  // 1 - 0.2
    public static const _MOUSE_ROTATE_FRICTION :Number = 1 - 0.8 / _DERIVATION;  // 1 - 0.8
    public static const _MOUSE_MOVE_FRICTION   :Number = 1 - 0.5 / _DERIVATION;  // 1 - 0.5
    public static const _GROUND_FRICTION       :Number = 1 - 0.2 / _DERIVATION;  // 1 - 0.2
    public static const _originMATRIX          :Matrix3D = new Matrix3D();
    
    public function GB()
    {
        
    }
}