Flash/Flex学习笔记(40):弹性运动续--弹簧
上一篇里演示的弹性运动加上摩擦力因素后,物体最终基本上都会比较准确的停在目标位置。但是我们回想一下现实世界中的弹簧,如果把弹簧的一头固定起来(即相当于目标点),而另一端栓一个球,把球拉开或压缩一定距离然后松手,事实上小球永远也不可能到达弹簧固定的那一端(因为弹簧即使压缩到最紧,也总有一定的长度)
所以如果要在Flash里模拟现实中的弹簧,真正的目标点绝不是弹簧的端点,而是目标点再偏移一段距离(即弹簧自然伸展时的长度)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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}); |
如果考虑到二维坐标的弹簧运动,要稍微复杂一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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}); |
上面的例子中,移动的方向(即夹角)与目标点都是固定的,如果改成动态的(比如鼠标当前所在位置),效果可能更逼真
1 2 3 4 5 6 7 8 9 10 11 12 | 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模拟出一个极逼真的弹簧模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 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 ; } } |
如果玩得再疯狂一点,多放一些小球,让第二个以第一个为目标,第三个以第二个为目标...最后一个再以第一个为目标,这样构成一个环,大概就是下面这个样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 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 ; } } |
思考一下:这样为啥不会造成死循环?
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步