Verlet Hinge

by fakestar0826 forked from Verlet Square (diff: 36)
♥0 | Line 205 | Modified 2011-01-13 10:46:30 | MIT License
play

ActionScript3 source code

/**
 * Copyright fakestar0826 ( http://wonderfl.net/user/fakestar0826 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/qpp8
 */

// forked from fakestar0826's Verlet Square
// forked from fakestar0826's Verlet Triangle
// forked from fakestar0826's Verlet Method
package {
    import flash.display.AVM1Movie;
    import flash.geom.Rectangle;
    import flash.events.Event;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        
        private var _pointA:VerletPoint;
        private var _pointB:VerletPoint;
        private var _pointC:VerletPoint;
        private var _pointD:VerletPoint;
        private var _pointE:VerletPoint;
        private var _pointF:VerletPoint;
        private var _pointG:VerletPoint;
        private var _stageRect:Rectangle;
        
        private var _points:Array;
        private var _sticks:Array;
        
        public function FlashTest() {
            // write as3 code here..
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            _points = new Array();
            _sticks = new Array();
            
            _stageRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            
            //土台
            _pointA = makePoint(stage.stageWidth / 2, stage.stageHeight - 350);
            _pointB = makePoint(0, stage.stageHeight);
            _pointC = makePoint(stage.stageWidth, stage.stageHeight);
            //振り子
            _pointD = makePoint(stage.stageWidth / 2 + 150, stage.stageHeight - 350);
            //重り。歪だな。。。
            _pointE = makePoint(stage.stageWidth / 2 + 120, stage.stageHeight - 410);//右側
            _pointF = makePoint(stage.stageWidth / 2 + 160, stage.stageHeight - 410);//左側
            _pointG = makePoint(stage.stageWidth / 2 + 140, stage.stageHeight - 440);//下側
            //土台
            makeStick(_pointA, _pointB);
            makeStick(_pointB, _pointC);
            makeStick(_pointC, _pointA);
            //振り子
            makeStick(_pointA, _pointD);
            //重り
            makeStick(_pointD, _pointE);
            makeStick(_pointD, _pointF);
            makeStick(_pointE, _pointF);
            makeStick(_pointE, _pointG);
            makeStick(_pointF, _pointG);
            
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }
        
        private function onEnterFrame(e:Event):void
        {
            updatePoints();
            
            //繰り返しを増やすと剛体に近づく。stickのupdateメソッドにより、点同士の斥力?が働くため
            for(var i:int = 0;i < 1;i++)
            {
                constrainPoints();
                updateSticks();
            }

            graphics.clear();
            renderPoints();
            renderSticks();
        }
        
        private function makePoint(xpos:Number, ypos:Number):VerletPoint
        {
            var point:VerletPoint = new VerletPoint(xpos, ypos);
            _points.push(point);
            return point;
        }
        
        private function makeStick(pointA:VerletPoint, pointB:VerletPoint, length:Number = -1):VerletStick
        {
            var stick:VerletStick = new VerletStick(pointA, pointB, length);
            _sticks.push(stick);
            return stick;
        }
        
        private function updatePoints():void
        {
            for(var i:int = 0 ;i < _points.length; i++)
            {
                var point:VerletPoint = _points[i] as VerletPoint;
                point.y += 0.5;
                point.update();
            }

        }
        
        private function updateSticks():void
        {
            for(var i:int = 0; i < _sticks.length; i++)
            {
                var stick:VerletStick = _sticks[i] as VerletStick;
                stick.update();
            }

        }
        
        private function constrainPoints():void
        {
            for(var i:int = 0 ;i < _points.length; i++)
            {
                var point:VerletPoint = _points[i] as VerletPoint;
                point.constrain(_stageRect);
            }

        }
        
        private function renderPoints():void
        {
            for(var i:int = 0 ;i < _points.length; i++)
            {
                var point:VerletPoint = _points[i] as VerletPoint;
                point.render(graphics);
            }
        }
        
        private function renderSticks():void
        {
            for(var i:int = 0; i < _sticks.length; i++)
            {
                var stick:VerletStick = _sticks[i] as VerletStick;
                stick.render(graphics);
            }
        }







        
        
    }
    
    

}
import flash.display.Graphics;
import flash.geom.Rectangle;

class VerletPoint
{
    public var x:Number;
    public var y:Number;
    
    private var _oldX:Number;
    private var _oldY:Number;
    
    public function VerletPoint(x:Number, y:Number)
    {
        setPosition(x, y);
    }
    
    public function update():void
    {
        var tempX:Number = x;
        var tempY:Number = y;
        x += vx;
        y += vy;
        _oldX = tempX;
        _oldY = tempY;
    }
    
    public function setPosition(x:Number, y:Number):void
    {
        this.x = _oldX = x;
        this.y = _oldY = y;
    }
    
    public function constrain(rect:Rectangle):void
    {
        x = Math.max(rect.left, Math.min(rect.right, x));
        y = Math.max(rect.top, Math.min(rect.bottom, y));
    }
    
    public function set vx(value:Number):void
    {
        _oldX = x - value;
    }
    
    public function get vx():Number
    {
        return x - _oldX;
    }
    
    public function set vy(value:Number):void
    {
        _oldY = y - value;
    }
    
    public function get vy():Number
    {
        return y - _oldY;
    }
    
    public function render(g:Graphics):void
    {
        g.beginFill(0);
        g.drawCircle(x, y, 4);
        g.endFill();
    }
}

class VerletStick
{
    private var _pointA:VerletPoint;
    private var _pointB:VerletPoint;
    private var _length:Number;
    
    public function VerletStick(pointA:VerletPoint, pointB:VerletPoint, length:Number = -1)
    {
        _pointA = pointA;
        _pointB = pointB;
        
        if(length == -1)
        {
            var dx:Number = _pointA.x - _pointB.x;
            var dy:Number = _pointA.y - _pointB.y;
            _length = Math.sqrt(dx * dx + dy * dy);
        }
        else
        {
            _length = length;
        }
    }
    
    /**
     * 長さを、設定された長さに拘束する。
     *
     */
    public function update():void
    {
        var dx:Number = _pointB.x - _pointA.x;
        var dy:Number = _pointB.y - _pointA.y;
        var dist:Number = Math.sqrt(dx * dx + dy * dy);//2点間の距離
        var diff:Number = _length - dist;//設定された長さと↑↑で求めた2点間の距離との差分
        var offsetX:Number = (diff * dx / dist)/* <- this means "diff * cos(θ)" */ / 2;//拘束すべき長さのX成分(ちょっと違うな)
        var offsetY:Number = (diff * dy / dist)/* <- this means "diff * sin(θ)" */ / 2;//拘束すべき長さのY成分
        
        _pointA.x -= offsetX;
        _pointA.y -= offsetY;
        _pointB.x += offsetX;
        _pointB.y += offsetY;
    }
    
    public function render(g:Graphics):void
    {
        g.lineStyle(0);
        g.moveTo(_pointA.x, _pointA.y);
        g.lineTo(_pointB.x, _pointB.y);
    }



}