Verlet Hinge
forked from Verlet Square (diff: 36)
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);
}
}
