高等物理:数值积分
1、欧拉积分
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Point; 7 import flash.utils.getTimer; 8 public class Euler extends Sprite 9 { 10 private var _ball:Sprite; 11 private var _position:Point; 12 private var _velocity:Point; 13 private var _gravity:Number = 32; 14 private var _bounce:Number = -0.6; 15 private var _oldTime:int; 16 private var _pixelsPerFoot:Number = 10; 17 18 public function Euler() 19 { 20 stage.align = StageAlign.TOP_LEFT; 21 stage.scaleMode = StageScaleMode.NO_SCALE; 22 _ball = new Sprite(); 23 _ball.graphics.beginFill(0xff0000); 24 _ball.graphics.drawCircle(0, 0, 20); 25 _ball.graphics.endFill(); 26 _ball.x = 50; 27 _ball.y = 50; 28 addChild(_ball); 179 29 _velocity = new Point(10, 0); 30 _position = new Point( _ball.x / _pixelsPerFoot, _ball.y / _pixelsPerFoot ); 31 _oldTime = getTimer(); 32 addEventListener(Event.ENTER_FRAME, onEnterFrame); 33 } 34 private function onEnterFrame(event:Event):void 35 { 36 var time:int = getTimer(); 37 var elapsed:Number = (time - _oldTime) / 1000; 38 _oldTime = time; 39 var accel:Point = acceleration(_position, _velocity); 40 _position.x += _velocity.x * elapsed; 41 _position.y += _velocity.y * elapsed; 42 _velocity.x += accel.x * elapsed; 43 _velocity.y += accel.y * elapsed; 44 // 检测如果对象超过边缘就弹回 45 if(_position.y > ( stage.stageHeight - 20 ) / _pixelsPerFoot ) 46 { 47 _position.y = ( stage.stageHeight - 20 ) / _pixelsPerFoot; 48 _velocity.y *= _bounce; 49 } 50 if(_position.x > ( stage.stageWidth - 20 ) / _pixelsPerFoot ) 51 { 52 _position.x = ( stage.stageWidth - 20 ) / _pixelsPerFoot; 53 _velocity.x *= _bounce 54 } 55 else if(_position.x < 20 / _pixelsPerFoot) 56 { 57 _position.x = 20 / _pixelsPerFoot; 58 _velocity.x *= _bounce; 59 } 60 _ball.x = _position.x * _pixelsPerFoot; 61 _ball.y = _position.y * _pixelsPerFoot; 62 } 63 private function acceleration(p:Point, v:Point):Point 64 { 65 return new Point(0, _gravity); 66 } 67 } 68 }
2、Runge-Kutta积分
RK2:计算出每段开始时和结束时的加速度和速度,然后取平均值。
首先,计算开始时的加速度,然后是位置和速度,这些和欧拉法是完全一致的。不过我们用新的变量来保存这些信息。
// position1是对象的当前位置
// velocity1是对象的当前速度
acceleration1 = acceleration(position1, velocity1)
position2 = position1 + velocity1 * time
velocity2 = velocity1 + acceleration1 * time
position2和velocity2就是结束时对象的位置和速度。接下来求结束时的加速度:
acceleration2 = acceleration(position2, velocity2)
然后是RK2的关键一步,求两个状态下的平均速度和加速度:
position1 += (velocity1 + velocity2) / 2 * time
velocity1 += (acceleration1 + acceleration2) / 2 * time
开始时和结束时的平均速度乘以时间,得到改变的位移,加于当前位置,就是改变后的位置。同理加速度,就是改变后的速度。
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Point; 7 import flash.utils.getTimer; 8 public class RK2 extends Sprite 9 { 10 private var _ball:Sprite; 11 private var _position:Point; 12 private var _velocity:Point; 13 private var _gravity:Number = 32; 14 private var _bounce:Number = -0.6; 15 private var _oldTime:int; 16 private var _pixelsPerFoot:Number = 10; 17 public function RK2() 18 { 19 stage.align = StageAlign.TOP_LEFT; 20 stage.scaleMode = StageScaleMode.NO_SCALE; 21 _ball = new Sprite(); 22 _ball.graphics.beginFill(0xff0000); 23 _ball.graphics.drawCircle(0, 0, 20); 24 _ball.graphics.endFill(); 25 _ball.x = 50; 26 _ball.y = 50; 27 addChild(_ball); 28 _velocity = new Point(10, 0); 29 _position = new Point(_ball.x / _pixelsPerFoot, _ball.y / _pixelsPerFoot); 30 _oldTime = getTimer(); 31 addEventListener(Event.ENTER_FRAME, onEnterFrame); 32 } 33 private function onEnterFrame(event:Event):void 34 { 35 var time:int = getTimer(); 36 var elapsed:Number = (time - _oldTime) / 1000; 37 _oldTime = time; 38 var accel1:Point = acceleration(_position, _velocity); 39 var position2:Point = new Point(); 40 position2.x = _position.x + _velocity.x * elapsed; 41 position2.y = _position.y + _velocity.y * elapsed; 42 var velocity2:Point = new Point(); 43 velocity2.x = _velocity.x + accel1.x * elapsed; 183 44 velocity2.y = _velocity.y + accel1.x * elapsed; 45 var accel2:Point = acceleration(position2, velocity2); 46 _position.x += (_velocity.x + velocity2.x) / 2 * elapsed; 47 _position.y += (_velocity.y + velocity2.y) / 2 * elapsed; 48 _velocity.x += (accel1.x + accel2.x) / 2 * elapsed; 49 _velocity.y += (accel1.y + accel2.y) / 2 * elapsed; 50 if(_position.y > (stage.stageHeight - 20) / _pixelsPerFoot) 51 { 52 _position.y = (stage.stageHeight - 20) / _pixelsPerFoot; 53 _velocity.y *= _bounce; 54 } 55 if(_position.x > (stage.stageWidth - 20) / _pixelsPerFoot) 56 { 57 _position.x = (stage.stageWidth - 20) / _pixelsPerFoot; 58 _velocity.x *= _bounce 59 } 60 else if(_position.x < 20 / _pixelsPerFoot) 61 { 62 _position.x = 20 / _pixelsPerFoot; 63 _velocity.x *= _bounce; 64 } 65 _ball.x = _position.x * _pixelsPerFoot; 66 _ball.y = _position.y * _pixelsPerFoot; 67 } 68 private function acceleration(p:Point, v:Point):Point 69 { 70 return new Point(0, _gravity); 71 } 72 } 73 }
3、RK4:。如果人们提及“Runge-Kutta”,几乎总是讨论RK4。
和RK2比,我们要做差不多类似的事情,只是不再采用开始和结束端的信息,而是要用4处的信息。
在RK4中,求平均值的方式有点不同。先让我们看看伪码,很长,所以名词我都用了简称。
// pos1是对象的当前位置
// vel1是对象的当前速度
acc1 = acceleration(pos1, vel1)
pos2 = pos1 + vel1 / 2 * time
vel2 = vel1 + acc1 / 2 * time
acc2 = acceleration(pos2, vel2)
pos3 = pos1 + vel2 / 2 * time
vel3 = vel1 + acc2 / 2 * time
acc3 = acceleration(pos3, vel3)
pos4 = pos1 + vel3 * time
vel4 = vel1 + acc3 * time
acc4 = acceleration(pos4, vel4)
pos1 += (vel1 + vel2 * 2 + vel3 * 2 + vel4) / 6 * time
vel1 += (acc1 + acc2 * 2 + acc3 * 2 + acc4) / 6 * time
注意,第一、第四步的求解和第二、第三步不同,在第二、第三步时候先除以了2,在最后求平均时又乘以了2。
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Point; 7 import flash.utils.getTimer; 8 public class RK4 extends Sprite 9 { 10 private var _ball:Sprite; 11 private var _position:Point; 12 private var _velocity:Point; 13 private var _gravity:Number = 32; 14 private var _bounce:Number = -0.6; 15 private var _oldTime:int; 16 private var _pixelsPerFoot:Number = 10; 17 public function RK4() 18 { 19 stage.align = StageAlign.TOP_LEFT; 20 stage.scaleMode = StageScaleMode.NO_SCALE; 21 _ball = new Sprite(); 22 _ball.graphics.beginFill(0xff0000); 23 _ball.graphics.drawCircle(0, 0, 20); 24 _ball.graphics.endFill(); 25 _ball.x = 50; 26 _ball.y = 50; 27 addChild(_ball); 28 _velocity = new Point(10, 0); 29 185 30 _position = new Point(_ball.x / _pixelsPerFoot, _ball.y / _pixelsPerFoot); 31 _oldTime = getTimer(); 32 addEventListener(Event.ENTER_FRAME, onEnterFrame); 33 } 34 private function onEnterFrame(event:Event):void 35 { 36 var time:int = getTimer(); 37 var elapsed:Number = (time - _oldTime) / 1000; 38 _oldTime = time; 39 var accel1:Point = acceleration(_position, _velocity); 40 var position2:Point = new Point(); 41 position2.x = _position.x + _velocity.x / 2 * elapsed; 42 position2.y = _position.y + _velocity.y / 2 * elapsed; 43 var velocity2:Point = new Point(); 44 velocity2.x = _velocity.x + accel1.x / 2 * elapsed; 45 velocity2.y = _velocity.y + accel1.x / 2 * elapsed; 46 var accel2:Point = acceleration(position2, velocity2); 47 var position3:Point = new Point(); 48 position3.x = _position.x + velocity2.x / 2 * elapsed; 49 position3.y = _position.y + velocity2.y / 2 * elapsed; 50 var velocity3:Point = new Point(); 51 velocity3.x = _velocity.x + accel2.x / 2 * elapsed; 52 velocity3.y = _velocity.y + accel2.y / 2 * elapsed; 53 var accel3:Point = acceleration(position3, velocity3); 54 var position4:Point = new Point(); 55 position4.x = _position.x + velocity3.x * elapsed; 56 position4.y = _position.y + velocity3.y * elapsed; 57 var velocity4:Point = new Point(); 58 velocity4.x = _velocity.x + accel3.x * elapsed; 59 velocity4.y = _velocity.y + accel3.y * elapsed; 60 var accel4:Point = acceleration(position4, velocity4); 61 _position.x += (_velocity.x + 2 * velocity2.x + 2 * velocity3.x + velocity4.x) / 6 * elapsed; 62 _position.y += (_velocity.y + 2 * velocity2.y + 2 * velocity3.y + velocity4.y) / 6 * elapsed; 63 _velocity.x += (accel1.x + 2 * accel2.x + 2 * accel3.x + accel4.x) / 6 * elapsed; 64 _velocity.y += (accel1.y + 2 * accel2.y + 2 * accel3.y + accel4.y) / 6 * elapsed; 65 if(_position.y > (stage.stageHeight - 20) / _pixelsPerFoot) 66 { 67 _position.y = (stage.stageHeight - 20) / _pixelsPerFoot; 68 186 69 _velocity.y *= _bounce; 70 } 71 if(_position.x > (stage.stageWidth - 20) / _pixelsPerFoot) 72 { 73 _position.x = (stage.stageWidth - 20) / _pixelsPerFoot; 74 _velocity.x *= _bounce 75 } 76 else if(_position.x < 20 / _pixelsPerFoot) 77 { 78 _position.x = 20 / _pixelsPerFoot; 79 _velocity.x *= _bounce; 80 } 81 _ball.x = _position.x * _pixelsPerFoot; 82 _ball.y = _position.y * _pixelsPerFoot; 83 } 84 private function acceleration(p:Point, v:Point):Point 85 { 86 return new Point(0, _gravity); 87 } 88 } 89 }
3、Verlet积分法:
Verlet积分法最初作为模拟分子运动来开发的。
Verlet积分法的优势不像Runge-Kutta那样以超精确为主。
Verlet积分法最突出的一点是不用保存对象的速度,取而代之的是保存对象的位置。
Verlet点:
创建一个VerletPoint类,它封装了一个点所拥有的Verlet积分法的所有行为。是点,就需要x和y属性,还有old x和old y以及一个update函数。update函数是告诉点之前在哪里,然后该去哪里,并使用什么样的速度。然后保存当前位置为之前位置,以便下次使用。基本逻辑如下:
temp = currentPosition
velocity = currentPosition - oldPosition
currentPosition += velocity
oldPosition = temp
因为当前位置会被改变,所以需要先把当前位置保存在一个临时变量里。
然后计算出速度,并加于当前位置下,最后把之前保存的当前位置作为之前位置保留下来。
1 package 2 { 3 import flash.display.Graphics; 4 import flash.geom.Rectangle; 5 public class VerletPoint 6 { 7 public var x:Number; 8 public var y:Number; 9 private var _oldX:Number; 10 private var _oldY:Number; 11 public function VerletPoint(x:Number, y:Number) 12 { 13 setPosition(x, y); 14 15 } 16 public function update():void 17 { 18 var tempX:Number = x; 19 var tempY:Number = y; 20 x += vx; 21 y += vy; 22 _oldX = tempX; 23 _oldY = tempY; 24 } 25 public function setPosition(x:Number, y:Number):void 26 { 27 this.x = _oldX = x; 28 this.y = _oldY = y; 29 } 30 public function constrain(rect:Rectangle):void 31 { 32 x = Math.max(rect.left, Math.min(rect.right, x)); 33 y = Math.max(rect.top, Math.min(rect.bottom, y)); 34 } 35 public function set vx(value:Number):void 36 { 37 _oldX = x - value; 38 } 39 public function get vx():Number 40 { 41 return x - _oldX; 42 } 43 public function set vy(value:Number):void 44 { 45 _oldY = y - value; 46 } 47 public function get vy():Number 48 { 49 return y - _oldY; 50 } 51 public function render(g:Graphics):void 52 { 53 g.beginFill(0); 54 g.drawCircle(x, y, 4); 55 g.endFill(); 56 } 57 } 58 }
vx和vy采用getter/setter方式,因为Verlet积分法是不保存速度的。其实getter/setter方式并不保存任何信息。当设置vx时,_oldX等于当前x减去给定的值,这就好像在说速度的由来,而类似getter得到的也是位置相减的结果。所以并没有去保存一个叫速度的信息。
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Rectangle; 7 public class VerletPointTest extends Sprite 8 { 9 private var _point:VerletPoint; 10 public function VerletPointTest() 11 { 12 stage.align = StageAlign.TOP_LEFT; 13 stage.scaleMode = StageScaleMode.NO_SCALE; 14 _point = new VerletPoint(100, 100); 15 16 //尽管通过vx、vy来改变速度概念上更清晰, 17 //但是用位置却有着更高的效率,因为这么做只需改变一个变量。 18 //如果有众多粒子进行交互,效率问题是首先要考虑的。 19 //_point.vx = 1; 20 _point.x += 1; 21 //_point.vy = 1; 22 _point.y += 1; 23 24 addEventListener(Event.ENTER_FRAME, onEnterFrame); 25 } 26 private function onEnterFrame(event:Event):void 27 { 28 _point.update(); 29 graphics.clear(); 30 _point.render(graphics); 31 } 32 } 33 }
点的约束:把点控制在场景内。
创建了一个场景大小的矩形(你可以定义任意大小的矩形),然后在调用update之前,把它作为参数传给constrain函数。
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)); }
Verlet线段:
一个线段确定两个点。线段有length属性,它代表着两个点之间的距离大小。如果两点之间的距离和length有差异,就适当的贴近或者远离。
1 package 2 { 3 import flash.display.Graphics; 4 public class VerletStick 5 { 6 private var _pointA:VerletPoint; 7 private var _pointB:VerletPoint; 8 private var _length:Number; 9 public function VerletStick(pointA:VerletPoint, pointB:VerletPoint, length:Number = -1) 10 { 11 _pointA = pointA; 12 _pointB = pointB; 13 if(length == -1) 14 { 15 var dx:Number = _pointA.x - _pointB.x; 16 var dy:Number = _pointA.y - _pointB.y; 17 _length = Math.sqrt(dx * dx + dy * dy); 18 } 19 else 20 { 21 _length = length; 22 } 23 } 24 public function update():void 25 { 26 var dx:Number = _pointB.x - _pointA.x; 27 var dy:Number = _pointB.y - _pointA.y; 28 var dist:Number = Math.sqrt(dx * dx + dy * dy); 29 var diff:Number = _length - dist; 30 var offsetX:Number = (diff * dx / dist) / 2; 31 var offsetY:Number = (diff * dy / dist) / 2; 32 33 // 第一个点减去x、y偏移量的一半,第二个点加上x、y偏移量的一半。这样做 34 // 让两个点都有反应,并保证之间的距离和length一致。 35 _pointA.x -= offsetX; 36 _pointA.y -= offsetY; 37 _pointB.x += offsetX; 38 _pointB.y += offsetY; 39 } 40 public function render(g:Graphics):void 41 { 42 g.lineStyle(0); 43 g.moveTo(_pointA.x, _pointA.y); 44 g.lineTo(_pointB.x, _pointB.y); 45 } 46 } 47 }
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Rectangle; 7 public class VerletStickTest extends Sprite 8 { 9 private var _pointA:VerletPoint; 10 private var _pointB:VerletPoint; 11 private var _stick:VerletStick; 12 private var _stageRect:Rectangle; 13 public function VerletStickTest() 14 { 15 stage.align = StageAlign.TOP_LEFT; 16 stage.scaleMode = StageScaleMode.NO_SCALE; 17 _stageRect = new Rectangle(0, 0, stage.stageWidth,stage.stageHeight); 18 _pointA = new VerletPoint(100, 100); 19 _pointB = new VerletPoint(105, 200); 20 _stick = new VerletStick(_pointA, _pointB); 21 addEventListener(Event.ENTER_FRAME, onEnterFrame); 22 } 23 24 // 看起来好像有弹性一样 25 /*private function onEnterFrame(event:Event):void 26 { 27 _pointA.y += .5; 28 _pointA.update(); 29 _pointA.constrain(_stageRect); 30 _pointB.y += .5; 31 _pointB.update(); 32 _pointB.constrain(_stageRect); 33 _stick.update(); 34 graphics.clear(); 35 _pointA.render(graphics); 36 _pointB.render(graphics); 37 _stick.render(graphics); 38 }*/ 39 40 41 private function onEnterFrame(event:Event):void 42 { 43 _pointA.y += .5; 44 _pointA.update(); 45 _pointB.y += .5; 46 _pointB.update(); 47 48 // 线段的update函数在试着推进两个点时, 49 // 接触到矩形底部的点又被强制拉了回来。 50 // 同时作用的两个反作用力,导致两个点稍稍向上弹起以适应所有的约束条件。 51 // 我们就需要多调用几次点的 52 // constrain函数和线段的update函数,让它们尽快适应条件,来去掉这个弹性 53 for(var i:int = 0; i < 5; i++) 54 { 55 _pointA.constrain(_stageRect); 56 _pointB.constrain(_stageRect); 57 _stick.update(); 58 } 59 graphics.clear(); 60 _pointA.render(graphics); 61 _pointB.render(graphics); 62 _stick.render(graphics); 63 } 64 65 } 66 }
Verlet结构体:
一个Verlet结构体由多条线段组成。最简单的实心结构体是三角形。
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Rectangle; 7 public class Triangle extends Sprite 8 { 9 private var _pointA:VerletPoint; 10 private var _pointB:VerletPoint; 11 private var _pointC:VerletPoint; 12 private var _stickA:VerletStick; 13 private var _stickB:VerletStick; 14 private var _stickC:VerletStick; 15 private var _stageRect:Rectangle; 16 public function Triangle() 17 { 18 stage.align = StageAlign.TOP_LEFT; 19 stage.scaleMode = StageScaleMode.NO_SCALE; 20 _stageRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); 21 _pointA = new VerletPoint(100, 100); 22 _pointB = new VerletPoint(200, 100); 23 _pointC = new VerletPoint(150, 200); 24 _stickA = new VerletStick(_pointA, _pointB); 25 _stickB = new VerletStick(_pointB, _pointC); 26 _stickC = new VerletStick(_pointC, _pointA); 27 addEventListener(Event.ENTER_FRAME, onEnterFrame); 28 } 29 private function onEnterFrame(event:Event):void 30 { 31 _pointA.y += .5; 32 _pointA.update(); 33 _pointB.y += .5; 34 _pointB.update(); 35 _pointC.y += .5; 36 _pointC.update(); 37 38 // 加大循环次数可提高钢性 39 for(var i:int = 0; i < 1; i++) 40 { 41 _pointA.constrain(_stageRect); 42 _pointB.constrain(_stageRect); 43 _pointC.constrain(_stageRect); 44 _stickA.update(); 45 _stickB.update(); 46 _stickC.update(); 47 } 48 graphics.clear(); 49 _pointA.render(graphics); 50 _pointB.render(graphics); 51 _pointC.render(graphics); 52 _stickA.render(graphics); 53 _stickB.render(graphics); 54 _stickC.render(graphics); 55 } 56 } 57 }
1 package { 2 import flash.display.Sprite; 3 import flash.display.StageAlign; 4 import flash.display.StageScaleMode; 5 import flash.events.Event; 6 import flash.geom.Rectangle; 7 public class Square extends Sprite 8 { 9 private var _points:Array; 10 private var _sticks:Array; 11 private var _stageRect:Rectangle; 12 public function Square() 13 { 14 stage.align = StageAlign.TOP_LEFT; 15 stage.scaleMode = StageScaleMode.NO_SCALE; 16 _stageRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); 17 _points = new Array(); 18 _sticks = new Array(); 19 var pointA:VerletPoint = makePoint(100, 100); 20 pointA.vx = 10; 21 var pointB:VerletPoint = makePoint(200, 100); 22 var pointC:VerletPoint = makePoint(200, 200); 23 var pointD:VerletPoint = makePoint(100, 200); 24 makeStick(pointA, pointB); 25 makeStick(pointB, pointC); 26 makeStick(pointC, pointD); 27 makeStick(pointD, pointA); 28 makeStick(pointA, pointC); 29 addEventListener(Event.ENTER_FRAME, onEnterFrame); 30 } 200 31 private function onEnterFrame(event:Event):void 32 { 33 updatePoints(); 34 for(var i:int = 0; i < 1; i++) 35 { 36 constrainPoints(); 37 updateSticks(); 38 } 39 graphics.clear(); 40 renderPoints(); 41 renderSticks(); 42 } 43 private function makePoint(xpos:Number, ypos:Number):VerletPoint 44 { 45 var point:VerletPoint = new VerletPoint(xpos, ypos); 46 _points.push(point); 47 return point; 48 } 49 private function makeStick(pointA:VerletPoint, pointB:VerletPoint, length:Number = -1):VerletStick 50 { 51 var stick:VerletStick = new VerletStick(pointA, pointB, length); 52 _sticks.push(stick); 53 return stick; 54 } 55 private function updatePoints():void 56 { 57 for(var i:int = 0; i < _points.length; i++) 58 { 59 var point:VerletPoint = _points[i] as VerletPoint; 60 point.y += .5; 61 point.update(); 62 } 63 } 64 private function constrainPoints():void 65 { 66 for(var i:int = 0; i < _points.length; i++) 67 { 68 var point:VerletPoint = _points[i] as VerletPoint; 69 point.constrain(_stageRect); 70 } 71 } 72 private function updateSticks():void 73 { 74 for(var i:int = 0; i < _sticks.length; i++) 75 201 76 { 77 var stick:VerletStick = _sticks[i] as VerletStick; 78 stick.update(); 79 } 80 } 81 private function renderPoints():void 82 { 83 for(var i:int = 0; i < _points.length; i++) 84 { 85 var point:VerletPoint = _points[i] as VerletPoint; 86 point.render(graphics); 87 } 88 } 89 private function renderSticks():void 90 { 91 for(var i:int = 0; i < _sticks.length; i++) 92 { 93 var stick:VerletStick = _sticks[i] as VerletStick; 94 stick.render(graphics); 95 } 96 } 97 } 98 }
拉链式结构:
这种结构由两种结构共享与一点所组成。它们可以自由移动,但都围绕在同一枢轴处。这里将介绍如何制作一个单摆器。
1 public function Hinge() 2 { 3 stage.align = StageAlign.TOP_LEFT; 4 stage.scaleMode = StageScaleMode.NO_SCALE; 5 _stageRect = new Rectangle(0, 0, stage.stageWidth,stage.stageHeight); 6 _points = new Array(); 7 _sticks = new Array(); 8 // 根基 9 var pointA:VerletPoint = makePoint(stage.stageWidth / 2,stage.stageHeight - 500); 10 var pointB:VerletPoint = makePoint(0, stage.stageHeight); 11 var pointC:VerletPoint = makePoint(stage.stageWidth,stage.stageHeight); 12 // 臂摆 13 var pointD:VerletPoint = makePoint(stage.stageWidth / 2 + 350,stage.stageHeight - 500); 14 // 秤砣 15 var pointE:VerletPoint = makePoint(stage.stageWidth / 2 + 360,stage.stageHeight - 510); 16 var pointF:VerletPoint = makePoint(stage.stageWidth / 2 + 360,stage.stageHeight - 490); 17 var pointG:VerletPoint = makePoint(stage.stageWidth / 2 + 370,stage.stageHeight - 500); 18 // 根基 19 makeStick(pointA, pointB); 20 makeStick(pointB, pointC); 21 makeStick(pointC, pointA); 22 // 臂摆 23 makeStick(pointA, pointD); 24 // 秤砣 25 makeStick(pointD, pointE); 26 makeStick(pointD, pointF); 27 makeStick(pointE, pointF); 28 makeStick(pointE, pointG); 29 makeStick(pointF, pointG); 30 addEventListener(Event.ENTER_FRAME, onEnterFrame); 31 }