Трение реализовал) но с WeakJoint связями возникают какие-то баги. Верёвка начинает сама шевелиться!

Код AS3:
package gerich.verlet
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite{
private var pt:Array = new Array();
private var joints:Array = new Array();
private var particles:Sprite = new Sprite();
private var canvas:Shape = new Shape();
private var grav:Number = 500;
private var friction:Number = 10;
private var timeSqr:Number;
// ========================================================== //
public function Main():void{
stage.frameRate = 40;
timeSqr=1/stage.frameRate;timeSqr*=timeSqr;
addChild(canvas);
addChild(particles);
pt.push(new Particle(270,150,true));
for (var j:int=0;j<60;j++)
{
pt.push(new Particle(270,150));
joints.push(new WeakJoint(pt[j], pt[j+1], 8));
}
for (var i in pt){
particles.addChild(pt[i]);
}
addEventListener(Event.ENTER_FRAME, checkJoints);
addEventListener(Event.ENTER_FRAME, ptMouse);
}
// ========================================================== //
private function checkJoints(event:Event):void{
var dx:Number;
var dy:Number;
var fx:Number;
var fy:Number;
canvas.graphics.clear();
// Gravity
for (var i in pt){
dx = (pt[i].xx - pt[i].old_x);
dy = (pt[i].yy - pt[i].old_y);
pt[i].old_x = pt[i].xx;
pt[i].old_y = pt[i].yy;
fx=pt[i].xx+dx;
fy=pt[i].yy+dy+grav*timeSqr;
pt[i].xx=fx;
pt[i].yy=fy;
if(fx<0){
if(dy>0)
pt[i].old_y=Math.max(pt[i].old_y+fx*friction,pt[i].yy);
else
pt[i].old_y=Math.min(pt[i].old_y-fx*friction,pt[i].yy);
}
if(fx>stage.stageWidth){
if(dy>0)
pt[i].old_y=Math.max(pt[i].old_y+(stage.stageWidth-fx)*friction,pt[i].yy);
else
pt[i].old_y=Math.min(pt[i].old_y-(stage.stageWidth-fx)*friction,pt[i].yy);
}
if(fy<0){
if(dx>0)
pt[i].old_x=Math.max(pt[i].old_x+fy*friction,pt[i].xx);
else
pt[i].old_x=Math.min(pt[i].old_x-fy*friction,pt[i].xx);
}
if(fy>stage.stageHeight){
if(dx>0)
pt[i].old_x=Math.max(pt[i].old_x+(stage.stageHeight-fy)*friction,pt[i].xx);
else
pt[i].old_x=Math.min(pt[i].old_x-(stage.stageHeight-fy)*friction,pt[i].xx);
}
}
// Joints
for (var z:int=0; z<30; z++){
for (var i in joints){
joints[i].Apply();
}
for (var i in pt){
pt[i].xx=Math.max(pt[i].xx,0);
pt[i].xx=Math.min(pt[i].xx,stage.stageWidth);
pt[i].yy=Math.max(pt[i].yy,0);
pt[i].yy=Math.min(pt[i].yy,stage.stageHeight);
}
}
for (var i in pt){
pt[i].x = pt[i].xx;
pt[i].y = pt[i].yy;
}
// Lines
for (var i in joints){
joints[i].Draw(canvas);
}
}
// ========================================================== //
private function ptMouse(event:Event):void{
for (var i in pt){
if(pt[i].isMouse){
pt[i].x=mouseX;
pt[i].y=mouseY;
pt[i].xx=mouseX;
pt[i].yy=mouseY;
}
}
canvas.graphics.clear();
// Lines
for (var i in joints){
joints[i].Draw(canvas);
}
}
}
}
// ***** [ Particle Class ] ***************************************** //
import flash.display.Sprite;
internal class Particle extends Sprite{
public var old_x:Number;
public var old_y:Number;
public var xx:Number;
public var yy:Number;
public var isMouse:Boolean;
// ========================================================== //
public function Particle(_x:int, _y:int, _isMouse:Boolean=false):void{
x = _x;
y = _y;
xx = _x;
yy = _y;
old_x = _x;
old_y = _y;
isMouse=_isMouse;
graphics.lineStyle(1, 0x000000);
graphics.beginFill(0xFFD22B);
graphics.drawCircle(0,0,5);
graphics.endFill();
}
// ========================================================== //
}
import flash.display.Shape;
internal class Joint{
public var p1:Particle;
public var p2:Particle;
public var len:Number;
// ========================================================== //
public function Joint(_p1:Particle, _p2:Particle, _len:Number):void{
p1=_p1;
p2=_p2;
len=_len;
}
// ========================================================== //
public function Draw(canvas:Shape):void{
canvas.graphics.lineStyle(1,0x000000);
canvas.graphics.moveTo(p1.x, p1.y);
canvas.graphics.lineTo(p2.x, p2.y);
}
// ========================================================== //
public function Apply():void{
var dx:Number;
var dy:Number;
var d_len:Number;
var diff:Number;
dx = p2.xx-p1.xx;
dy = p2.yy-p1.yy;
d_len = Math.sqrt(dx*dx + dy*dy);
if(d_len==0){
dx=Math.random();
dy=Math.random();
d_len = Math.sqrt(dx*dx + dy*dy);
}
diff = (d_len-len)/d_len;
dx *= 0.5*diff;
dy *= 0.5*diff;
if(!p2.isMouse){
p2.xx -= dx;
p2.yy -= dy;
}
if(!p1.isMouse){
p1.xx += dx;
p1.yy += dy;
}
}
// ========================================================== //
}
internal class WeakJoint extends Joint
{
// ========================================================== //
public function WeakJoint(_p1:Particle, _p2:Particle, _len:Number):void{
super(_p1,_p2,_len);
}
// ========================================================== //
override public function Apply():void{
var dx:Number;
var dy:Number;
var d_len:Number;
var diff:Number;
dx = p2.xx-p1.xx;
dy = p2.yy-p1.yy;
d_len = Math.sqrt(dx*dx + dy*dy);
if(d_len==0){
dx=Math.random();
dy=Math.random();
d_len = Math.sqrt(dx*dx + dy*dy);
}
if(d_len>len){
diff = (d_len-len)/d_len;
dx *= diff;
dy *= diff;
if(!p2.isMouse){
p2.xx -= dx;
p2.yy -= dy;
}
if(!p1.isMouse){
p1.xx += dx;
p1.yy += dy;
}
}
}
// ========================================================== //
}
internal class RangeJoint extends Joint
{
public var lenmax:Number;
public var lenmin:Number;
// ========================================================== //
public function RangeJoint(_p1:Particle, _p2:Particle, _lenmin:Number, _lenmax:Number):void
{
lenmax=_lenmax;
lenmin=_lenmin;
super(_p1,_p2,_lenmax);
}
// ========================================================== //
override public function Apply():void
{
var dx:Number;
var dy:Number;
var d_len:Number;
var diff:Number;
dx = p2.xx-p1.xx;
dy = p2.yy-p1.yy;
d_len = Math.sqrt(dx*dx + dy*dy);
if(d_len==0){
dx=Math.random();
dy=Math.random();
d_len = Math.sqrt(dx*dx + dy*dy);
}
if((d_len>lenmax)||(d_len<lenmin)){
if(d_len>lenmax)
diff = (d_len-lenmax)/d_len;
if(d_len<lenmin)
diff = (d_len-lenmin)/d_len;
dx *= diff;
dy *= diff;
if(!p2.isMouse){
p2.xx -= dx;
p2.yy -= dy;
}
if(!p1.isMouse){
p1.xx += dx;
p1.yy += dy;
}
}
}
// ========================================================== //
}