首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Flash >

Flash/Flex学习札记(35):弹性运动续-弹簧

2012-10-12 
Flash/Flex学习笔记(35):弹性运动续--弹簧上一篇里演示的弹性运动加上摩擦力因素后,物体最终基本上都会比

Flash/Flex学习笔记(35):弹性运动续--弹簧

上一篇里演示的弹性运动加上摩擦力因素后,物体最终基本上都会比较准确的停在目标位置。但是我们回想一下现实世界中的弹簧,如果把弹簧的一头固定起来(即相当于目标点),而另一端栓一个球,把球拉开或压缩一定距离然后松手,事实上小球永远也不可能到达弹簧固定的那一端(因为弹簧即使压缩到最紧,也总有一定的长度)

所以如果要在Flash里模拟现实中的弹簧,真正的目标点绝不是弹簧的端点,而是目标点再偏移一段距离(即弹簧自然伸展时的长度)

var ball:Ball = new Ball(6);


addChild(ball);


ball.y = 20;

?
ball.x = 20;

var targetX:Number=stage.stageWidth/2;


var targetY:Number=ball.y;

?
var springLength = 100;//弹簧长度

?
var spring = 0.2;//弹性系数

?
var friction = 0.92;//摩擦系数

?
//画辅助线,以便看得更清楚

?
graphics.lineStyle(0.5,0xaaaaaa);

?
graphics.moveTo(ball.x,ball.y);

?
graphics.lineTo(stage.stageWidth-ball.x,ball.y);

?
graphics.moveTo(targetX,targetY-10);

?
graphics.lineTo(targetX,targetY+10);

?
graphics.moveTo(targetX-springLength,targetY-8);

?
graphics.lineTo(targetX-springLength,targetY+8);

?
var rect:Rectangle = new Rectangle(ball.x,ball.y,stage.stageWidth-ball.x*2,0);

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);


ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

?
stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);

function EnterFrameHandler(e:Event):void{

?
ball.vx += (targetX - springLength - ball.x)*spring;


ball.vx *= friction;

?
ball.x += ball.vx;


}

?
function MouseDownHandler(e:MouseEvent):void{

?
(e.target as Sprite).startDrag(true,rect);

?
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}

?


function MouseUpHandler(e:MouseEvent):void{

?
ball.stopDrag();

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);


}


ball.addEventListener(MouseEvent.MOUSE_OUT,function(){Mouse.cursor = MouseCursor.AUTO});


ball.addEventListener(MouseEvent.MOUSE_OVER,function(){Mouse.cursor = MouseCursor.HAND});

如果考虑到二维坐标的弹簧运动,要稍微复杂一点:

Flash/Flex学习札记(35):弹性运动续-弹簧

?

var ball:Ball = new Ball(10);

?
addChild(ball);

?
ball.y = 20;


ball.x = 20;


var targetX:Number=stage.stageWidth/2;

?
var targetY:Number=stage.stageHeight/2;

?
var springLength:uint = 100;//弹簧长度

?
var spring:Number = 0.2;//弹性系数

?
var friction:Number = 0.92;//摩擦系数

?
var angle:Number = 0;


addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

?
stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);

?
stage.addEventListener(MouseEvent.MOUSE_MOVE,function(){DrawLine()});

?
angle = Math.atan2(targetY - ball.y,targetX -ball.x);//确定夹角

?
trace(angle*180/Math.PI);

?
function EnterFrameHandler(e:Event):void{

?
ball.vx += (targetX - springLength*Math.cos(angle) - ball.x)*spring;//调整目标点

?
ball.vy += (targetY - springLength*Math.sin(angle) - ball.y)*spring;

?
ball.vx *= friction;

?
ball.vy *= friction;

?
ball.x += ball.vx;

?
ball.y += ball.vy;

?
DrawLine();

?
}


function DrawLine():void{

?
graphics.clear();


graphics.lineStyle(1);


graphics.moveTo(targetX,targetY-10);

?
graphics.lineTo(targetX,targetY+10);

?
graphics.moveTo(targetX-10,targetY);

?
graphics.lineTo(targetX+10,targetY);

?
graphics.moveTo(targetX,targetY);

?
graphics.lineStyle(0.5,0xaaaaaa);

?
graphics.lineTo(ball.x,ball.y);

?
}

?
function MouseDownHandler(e:MouseEvent):void{

?
(e.target as Sprite).startDrag(true);


removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}

?
function MouseUpHandler(e:MouseEvent):void{


ball.stopDrag();

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}

?
ball.addEventListener(MouseEvent.MOUSE_OUT,function(){Mouse.cursor = MouseCursor.AUTO});

?
ball.addEventListener(MouseEvent.MOUSE_OVER,function(){Mouse.cursor = MouseCursor.HAND});

上面的例子中,移动的方向(即夹角)与目标点都是固定的,如果改成动态的(比如鼠标当前所在位置),效果可能更逼真

?
function EnterFrameHandler(e:Event):void{

?
targetX = mouseX;//改成动态目标

?
targetY = mouseY;


angle = Math.atan2(targetY - ball.y,targetX -ball.x);//动态夹角

?
ball.vx += (targetX - springLength*Math.cos(angle) - ball.x)*spring;

?
ball.vy += (targetY - springLength*Math.sin(angle) - ball.y)*spring;

?
ball.vx *= friction;

?
ball.vy *= friction;


ball.x += ball.vx;

?
ball.y += ball.vy;

?
DrawLine();

}

如果二个物体相互以对方所在位置为目标做弹性运动,同时再考虑弹簧长度,边界检测等因素,可以用AS3模拟出一个极逼真的弹簧模型:

?
var ball_1:Ball = new Ball(10,0xff0000);


var ball_2:Ball = new Ball(10,0x0000ff);

?
ball_1.x = stage.stageWidth * Math.random();

?
ball_1.y = stage.stageHeight * Math.random();

?
ball_2.x = stage.stageWidth/2;

?
ball_2.y = stage.stageHeight/2;

?
addChild(ball_1);

?
addChild(ball_2);

?
var spring:Number = 0.1;

?
var springLength:uint = 100;

?
var friction:Number = 0.9;

?
var darggingBall:Ball;

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
ball_1.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

?
ball_2.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

?
stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);

?
stage.addEventListener(MouseEvent.MOUSE_MOVE,function(){DrawLine();});

?
ball_1.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);

?
ball_1.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);

?
ball_2.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);

?
ball_2.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);

?
function MouseOutHandler(e:MouseEvent){

?
Mouse.cursor = MouseCursor.AUTO;

?
}

?
function MouseOverHandler(e:MouseEvent){

?
Mouse.cursor = MouseCursor.HAND;

?
}

function MouseDownHandler(e:MouseEvent):void{

?
(e.target as Sprite).startDrag(true,new Rectangle(20,20,stage.stageWidth-40,stage.stageHeight-40));

?
darggingBall = e.target as Ball;

?
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}

?
function MouseUpHandler(e:MouseEvent):void{

?
if (darggingBall!=null){

?
darggingBall.stopDrag();

?
darggingBall = null;

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}???

?
}

?
function EnterFrameHandler(e:Event):void{

?
var dx1 = ball_2.x -ball_1.x;


var dy1 = ball_2.y -ball_1.y;???

?
var angle1:Number = Math.atan2(dy1,dx1);????


ball_1.vx += (ball_2.x - springLength * Math.cos(angle1) - ball_1.x) * spring;

?
ball_1.vy += (ball_2.y - springLength * Math.sin(angle1) - ball_1.y) * spring;??

?
ball_1.vx *= friction;

?
ball_1.vy *= friction;??

?
ball_1.x += ball_1.vx;

?
ball_1.y += ball_1.vy;

?
var dx2 = ball_1.x -ball_2.x;

?
var dy2 = ball_1.y -ball_2.y;???


var angle2:Number = Math.atan2(dy2,dx2);????

?
ball_2.vx += (ball_1.x - springLength * Math.cos(angle2) - ball_2.x) * spring;

?
ball_2.vy += (ball_1.y - springLength * Math.sin(angle2) - ball_2.y) * spring;??

?
ball_2.vx *= friction;

?
ball_2.vy *= friction;??

?
ball_2.x += ball_2.vx;

?
ball_2.y += ball_2.vy;

?
DrawLine();

?
CheckBoundary(ball_1);


CheckBoundary(ball_2);

?
}

?
function DrawLine():void{

?
graphics.clear();

?
graphics.lineStyle(0.5,0x666666);

?
graphics.moveTo(ball_1.x,ball_1.y);

?
graphics.lineTo(ball_2.x,ball_2.y);


}

?
function CheckBoundary(b:Ball){

?
if (b.x>stage.stageWidth-b.width/2 || b.x<=b.width/2){

?
b.x -= b.vx;????????


b.vx *= -1;

?
}

?
if (b.y>stage.stageHeight-b.height/2 || b.y<=b.height/2){

?
b.y -= b.vy;

?
b.vy *= -1;

?
}

?
}

如果玩得再疯狂一点,多放一些小球,让第二个以第一个为目标,第三个以第二个为目标...最后一个再以第一个为目标,这样构成一个环,大概就是下面这个样子:


var spring:Number=0.1;

?
var springLength:uint=150;

?
var friction:Number=0.8;//摩擦力

?
var darggingBall:Ball;


var ballNumber:uint = 3;//小球个数


var arrBalls:Array = new Array(ballNumber);

?
for(var i:uint=0,j=arrBalls.length;i<j;i++){

?
arrBalls[i] = new Ball(20,Math.random() * 0xffffff);

?
var _ball:Ball = arrBalls[i];

?
_ball.x=stage.stageWidth*Math.random();

?
_ball.y=stage.stageHeight*Math.random();

?
addChild(_ball);

?
_ball.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);


_ball.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);

?
_ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

?
}


addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?

?

stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);

?

stage.addEventListener(MouseEvent.MOUSE_MOVE,function(){DrawLine();});

?
//切换光标

?
function MouseOutHandler(e:MouseEvent) {

?
Mouse.cursor=MouseCursor.AUTO;

?
}


//切换光标

?
function MouseOverHandler(e:MouseEvent) {

?
Mouse.cursor=MouseCursor.HAND;

?
}

?
//开始拖动

?
function MouseDownHandler(e:MouseEvent):void {

?
(e.target as Sprite).startDrag(true,new Rectangle(20,20,stage.stageWidth-40,stage.stageHeight-40));

?
darggingBall=e.target as Ball;

?
removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);

?
}

?
//结束拖动

?
function MouseUpHandler(e:MouseEvent):void {


if (darggingBall!=null) {

?
darggingBall.stopDrag();

?
darggingBall=null;

?
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);


}

?
}


function EnterFrameHandler(e:Event):void {

?
for(var i:uint=0,j=arrBalls.length-1;i<j;i++){

?
SpringTo(arrBalls[i],arrBalls[i+1]);????????

?
}

?
SpringTo(arrBalls[arrBalls.length-1],arrBalls[0]);

?
DrawLine();?

?
for(i=0,j=arrBalls.length;i<j;i++){


CheckBoundary(arrBalls[i]);

?
}

?
}


//画连接线

?
function DrawLine():void {

?
graphics.clear();

?
graphics.lineStyle(0.5,0x666666);

?
//graphics.moveTo(ball_1.x,ball_1.y);

?
//graphics.lineTo(ball_2.x,ball_2.y);

?
for(var i:uint=0,j=arrBalls.length-1;i<j;i++){

?
graphics.moveTo(arrBalls[i].x,arrBalls[i].y);

?
graphics.lineTo(arrBalls[i+1].x,arrBalls[i+1].y);

?
}

?
graphics.lineTo(arrBalls[0].x,arrBalls[0].y);

?
}

?
//弹性运动处理??
function SpringTo(targetBall:Ball,moveBall:Ball):void{

?
var dy=targetBall.y-moveBall.y;

?
var dx=targetBall.x-moveBall.x;?

?
var angle1:Number=Math.atan2(dy,dx);

?
moveBall.vx += (targetBall.x - springLength * Math.cos(angle1) - moveBall.x) * spring;


moveBall.vy += (targetBall.y - springLength * Math.sin(angle1) - moveBall.y) * spring;

?
moveBall.vx *= friction;

?
moveBall.vy *= friction;

?
moveBall.x += moveBall.vx;

?
moveBall.y += moveBall.vy;

?
}

?
//检测边界

?
function CheckBoundary(b:Ball) {

?
if (b.x>stage.stageWidth-b.width/2||b.x<=b.width/2) {

?
b.x-=b.vx;

?
b.vx*=-1;

?
}

?
if (b.y>stage.stageHeight-b.height/2||b.y<=b.height/2) {


b.y-=b.vy;


b.vy*=-1;

?
}

}

思考一下:这样为啥不会造成死循环?

热点排行