模型取取怎么安装:动量守恒与能量守恒

来源:百度文库 编辑:偶看新闻 时间:2024/05/10 02:54:14

动能公式:

 

动量公式:

 

动量守恒:

 

能量守恒: 

 

根据这些规律可以得到下列方程组:

 

 

解该方程组,得到下面的公式:

 

 

把这二个公式相减,可以得到:

即:

我们也经常利用这个公式简化运算

 

基本的动量守恒演示:

先给ball类添加一个质量"属性"

package {import flash.display.Sprite;//小球 类public class Ball extends Sprite {public var radius:uint;//半径public var color:uint;//颜色public var vx:Number=0;//x轴速度public var vy:Number=0;//y轴速度public var count:uint=0;//辅助计数变量public var isDragged=false;//是否正在被拖动public var vr:Number=0;//旋转速度public var mass:Number = 1;//质量public function Ball(r:Number=50,c:uint=0xff0000) {this.radius=r;this.color=c;init();}private function init():void {graphics.beginFill(color);graphics.drawCircle(0,0,radius);graphics.endFill();}}}

一维单轴刚体碰撞测试:

package {import flash.display.Sprite;import flash.events.Event;public class Billiard1 extends Sprite {private var ball0:Ball;private var ball1:Ball;private var bounce:Number = -0.6;public function Billiard1() {init();}private function init():void {ball0=new Ball(40);addChild(ball0);ball1=new Ball(20,0x0000ff);addChild(ball1);ReStart();}private function ReStart():void{ball0.mass=2;ball0.x=50;ball0.y=stage.stageHeight/2;ball0.vx=5;ball1.mass=1;ball1.x=300;ball1.y=stage.stageHeight/2;ball1.vx=-5;addEventListener(Event.ENTER_FRAME,EnterFrameHandler);}private function EnterFrameHandler(event:Event):void {ball0.x+=ball0.vx;ball1.x+=ball1.vx;var dist:Number=ball1.x-ball0.x;//如果撞到了if (Math.abs(dist)=stage.stageWidth-ball0.radius || ball0.x<=ball0.radius){ball0.x -= ball0.vx;ball0.vx *= bounce;}if (ball1.x >=stage.stageWidth-ball1.radius || ball1.x<=ball1.radius){ball1.x -= ball1.vx;ball1.vx *= bounce;}trace(ball1.vx,ball0.vx);//如果二球都停了if (Math.abs(ball1.vx)<=0.05 && Math.abs(ball0.vx)<=0.05){removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);ReStart();}}}}

二维坐标上的刚体碰撞:

先来看这张图,红球a以Va速度运动,蓝球b以Vb速度运动,二球的连线正好与x轴平行(即:水平对心碰撞),碰撞的过程可以理解为二球水平速度分量Vax,Vbx应用运量守恒与能力守恒的结果(y轴方向的速度不受影响!)

但很多情况下,二球的连线并非总是与坐标轴平行,比如下面这样:

思路:仍然利用坐标旋转,先将二个球反向旋转到连线水平位置,然后按常规方式处理,完事后再旋转回来。

var ballA:Ball=new Ball(80,Math.random()*0xffffff);var ballB:Ball=new Ball(50,Math.random()*0xffffff);var bounce:Number=-1;ballA.x=ballA.radius+100;ballB.x=ballA.radius+200;ballA.y=120;ballB.y=300;ballA.mass=2;ballB.mass=1;ballA.vx = 5*(Math.random()*2-1);ballB.vx = 5*(Math.random()*2-1);ballA.vy = 5*(Math.random()*2-1);ballB.vy = 5*(Math.random()*2-1);addChild(ballA);addChild(ballB);addEventListener(Event.ENTER_FRAME,EnterFrameHandler);function EnterFrameHandler(e:Event):void {ballA.x+=ballA.vx;ballA.y+=ballA.vy;ballB.x+=ballB.vx;ballB.y+=ballB.vy;//运量守恒处理开始var dx:Number=ballB.x-ballA.x;var dy:Number=ballB.y-ballA.y;var dist:Number=Math.sqrt(dx*dx+dy*dy);if (dist<(ballA.radius + ballB.radius)) {var angle:Number=Math.atan2(dy,dx);var cos:Number=Math.cos(angle);var sin:Number=Math.sin(angle);//以ballA中心为旋转中心反向旋转var xA:Number=0;//ballA自身为旋转中心,所以自身旋转后的相对坐标都是0var yA:Number=0;var xB:Number=dx*cos+dy*sin;var yB:Number=dy*cos-dx*sin;//先(反向)旋转二球相对(ballA的)速度var vxA=ballA.vx*cos+ballA.vy*sin;var vyA=ballA.vy*cos-ballA.vx*sin;var vxB=ballB.vx*cos+ballB.vy*sin;var vyB=ballB.vy*cos-ballB.vx*sin;//旋转后的vx速度处理运量守恒var vdx=vxA-vxB;var vxAFinal = ((ballA.mass - ballB.mass)*vxA + 2*ballB.mass*vxB)/(ballA.mass + ballB.mass);var vxBFinal=vxAFinal+vdx;//相对位置处理xA+=vxAFinal;xB+=vxBFinal;//处理完了,再旋转回去//先处理坐标位置var xAFinal:Number=xA*cos-yA*sin;var yAFinal:Number=yA*cos+xA*sin;var xBFinal:Number=xB*cos-yB*sin;var yBFinal:Number=yB*cos+xB*sin;//处理最终的位置变化ballB.x=ballA.x+xBFinal;ballB.y=ballA.y+yBFinal;ballA.x+=xAFinal;ballA.y+=yAFinal;//再处理速度ballA.vx=vxAFinal*cos-vyA*sin;ballA.vy=vyA*cos+vxAFinal*sin;ballB.vx=vxBFinal*cos-vyB*sin;ballB.vy=vyB*cos+vxBFinal*sin;}//<--- 运量守恒处理结束CheckBounds(ballA);CheckBounds(ballB);}//舞台边界检测function CheckBounds(b:Ball) {if (b.xstage.stageWidth-b.radius) {b.x=stage.stageWidth-b.radius;b.vx*=bounce;}if (b.ystage.stageHeight-b.radius) {b.y=stage.stageHeight-b.radius;b.vy*=bounce;}}

粘连问题:

反复运行上面这段动画,偶尔可能会发现二个球最终粘在一起,无法分开了,造成这种原因的情况很多,下面的示意图分析了可能的形成原因之一

解决思路:找出重叠部分,然后把二个小球同时反向移动适当距离,让二个球分开即可

先来一段测试代码:验证一下是否有效

var ballA:Ball=new Ball(80,0xff0000);ballA.x=stage.stageWidth/2;ballA.y=stage.stageHeight/2;addChild(ballA);var ballB:Ball=new Ball(60,0x00ff00);ballB.x=stage.stageWidth/2-70;ballB.y=stage.stageHeight/2;addChild(ballB);btn1.x=stage.stageWidth/2;btn1.y=stage.stageHeight-btn1.height;btn1.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);function MouseDownHandler(e:MouseEvent):void {var overlap:Number=ballA.radius+ballB.radius-Math.abs(ballA.x-ballB.x);//计算重叠部分trace(overlap);//计算每个球所占重叠部分中的比例var aRadio:Number = ballA.radius/(ballA.radius + ballB.radius);var bRadio:Number = ballB.radius/(ballA.radius + ballB.radius);//分离判断if (overlap>0){if (ballA.x>ballB.x){ballA.x += overlap*aRadio;ballB.x -= overlap*bRadio;}else{ballA.x -= overlap*aRadio;ballB.x += overlap*bRadio;}}}ballA.addEventListener(MouseEvent.MOUSE_DOWN,startDragHandler);ballB.addEventListener(MouseEvent.MOUSE_DOWN,startDragHandler);ballA.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);ballA.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);ballB.addEventListener(MouseEvent.MOUSE_OVER,MouseOverHandler);ballB.addEventListener(MouseEvent.MOUSE_OUT,MouseOutHandler);stage.addEventListener(MouseEvent.MOUSE_UP,stopDragHandler);var obj:Ball;var rect:Rectangle = new Rectangle(0,stage.stageHeight/2,stage.stageWidth,0);function startDragHandler(e:MouseEvent):void {Mouse.cursor = MouseCursor.HAND;obj=e.currentTarget as Ball;obj.startDrag();}function stopDragHandler(e:MouseEvent):void {if (obj!=null) {obj.stopDrag(true,rect);obj=null;Mouse.cursor = MouseCursor.AUTO;}}function MouseOverHandler(e:MouseEvent):void{Mouse.cursor = MouseCursor.HAND;}function MouseOutHandler(e:MouseEvent):void{Mouse.cursor = MouseCursor.AUTO;}

水平拖动小球故意让它们重叠,然后点击“分开”按钮测试一下,ok,管用了!

再回过头来解决运量守恒中的粘连问题:

只要把EnterFrameHandler中的

 //相对位置处理   xA+=vxAFinal;   xB+=vxBFinal;  

换成:

//相对位置处理(同时要防止粘连)//xA+=vxAFinal;//xB+=vxBFinal;var sumRadius = ballA.radius + ballB.radius;var overlap:Number=sumRadius-Math.abs(xA-xB);//计算重叠部分//trace(overlap);//计算每个球所占重叠部分中的比例var aRadio:Number = ballA.radius/sumRadius;var bRadio:Number = ballB.radius/sumRadius;//分离判断if (overlap>0){if (xA>xB){xA += overlap*aRadio;xB -= overlap*bRadio;}else{xA -= overlap*aRadio;xB += overlap*bRadio;}}

最后老规矩:来一个群魔乱舞,把一堆球放在一块儿乱撞

package {import flash.display.Sprite;import flash.events.Event;import flash.geom.Point;public class MultiBilliard extends Sprite {private var balls:Array;private var numBalls:uint=8;private var bounce:Number=-1.0;public function MultiBilliard() {init();}private function init():void {balls = new Array();for (var i:uint = 0; i < numBalls; i++) {var radius:Number=Math.random()*40+10;var ball:Ball=new Ball(radius,Math.random()*0xffffff);ball.mass=radius;ball.x=i*100;ball.y=i*50;ball.vx=Math.random()*10-5;ball.vy=Math.random()*10-5;addChild(ball);balls.push(ball);}addEventListener(Event.ENTER_FRAME, onEnterFrame);}private function onEnterFrame(event:Event):void {for (var i:uint = 0; i < numBalls; i++) {var ball:Ball=balls[i];ball.x+=ball.vx;ball.y+=ball.vy;checkWalls(ball);}for (i = 0; i < numBalls - 1; i++) {var ballA:Ball=balls[i];for (var j:Number = i + 1; j < numBalls; j++) {var ballB:Ball=balls[j];checkCollision(ballA, ballB);}}}//舞台边界检测function checkWalls(b:Ball) {if (b.xstage.stageWidth-b.radius) {b.x=stage.stageWidth-b.radius;b.vx*=bounce;}if (b.ystage.stageHeight-b.radius) {b.y=stage.stageHeight-b.radius;b.vy*=bounce;}}private function rotate(x:Number, y:Number, sin:Number, cos:Number, reverse:Boolean):Point {var result:Point = new Point();if (reverse) {result.x=x*cos+y*sin;result.y=y*cos-x*sin;} else {result.x=x*cos-y*sin;result.y=y*cos+x*sin;}return result;}private function checkCollision(ball0:Ball, ball1:Ball):void {var dx:Number=ball1.x-ball0.x;var dy:Number=ball1.y-ball0.y;var dist:Number=Math.sqrt(dx*dx+dy*dy);if (dist

注:这段代码做了优化,把一些公用的部分提取出来封装成function了,同时对于粘连问题的解决,采用了更一种算法

后记:弄懂了本文中的这些玩意儿有啥用呢?让我想想,或许...公司需要开发一款桌面台球游戏时,这东西就能派上用场吧.