转 第十一章 撞球物理(1)(as3.0)

我们都希望技术性的书籍,可以潜入深,由简单到复杂。本章内容的复杂度达到了顶点。
并不是说接下来的章节会越来越容易,但是希望大家在学习本章内容时不要偷工减料。我会
带大家一步步地学习本章的概念,如果到现在为止大家都能很好地跟上我的步伐,那就再好
不过了。
    本章我们要关注动量:两个物体发生碰撞后动量会发生什么样的变化,动量的守恒,以
及如何在 ActionScript 中应用动量。
    在本章的例子中使用的对象,都本这简单直接的原则,这个学科通常是指“撞球物理”。
我们很快会看到一些不同大小的桌球相互碰撞的例子。
    在给大家代码时,我都会从简单的一维运动开始举例,为的是容易理解。然后再过渡到
二维坐标上,比如上一章的坐标旋转。本质上讲,就是将二维场景旋转成一个平面。最后就
可以忽略一个轴,而只对一维场景进行操作。这些都让读者很期待接下来的内容。让我们从
质量与动量开始吧。

质量
    本书前面的章节讨论过几种运动的概念:速度,加速度,向量,摩擦力,反弹,缓动,
弹性以及重力。而我成功的避开了物体的质量问题。现在我们要重新讨论这个问题,严格来
讲,书中有几个地方都要在方程中加入质量。我通常只关心让物体正确地运动看起来,注重
于制作出正确的效果。最重要的是执行结果必需有很高的效率,不能让程序毁掉 Flash。
    不过,从现在起再也不能忽略质量问题了。物体的质量与动量紧密相关,所以我们不得
不直接面对它。
什么是质量呢?在地球上,我们通常认为质量就是物体的重量。它们之间确实关系密切,因
为重量与质量是成比例的。物体的质量越大,重量就越大。事实上,对于质量和重量我们使
用同样的测量单位:千克,磅等等。严格来说,质量是物体所承受速度大小的测量单位。
    因此,物体的质量越大,这个物体就越难移动,也不易改变其本身的运动(减慢,加速
或改变方向)。
质量也与加速度和力有关。物体质量越大,给它加速度的力就越大。我的 Chevy Cavalier [注:
一款轿车的名字] 引擎可产生足够的力给小轿车作为加速度。  但是,这样的力对于大卡车的
加速度来说是远远不够的。因为卡车的质量比较大,引擎需要更多的力。

动量
    现在来看动量。它是由物体的质量和速度构成的,是质量与速度的乘积。动量通常用字
母 p 表示,质量用 m 表示,速度用 v 表示。下面这个公式应该无需解释了:
    p=m*v
    也就是说,质量小,速度大的动量与质量大速度小的动量相似。前面所说大卡车以每小
时 20 迈的速度运动就足以至人于死地。此外,子弹的质量非常轻,但是速度非常快,同样
也是致命的。
    由于速度 v 是一个向量(方向与量值),所以动量也必然是一个向量。动量的向量与
速度的向量是相同的。为了完整地描述动量,我们可以说:
    5 公斤 * 20 米/秒 角度为 23 度的方向运动。
    很复杂吧?现在大家知道我为什么要等到这里才讲了吧。

动量守恒
     最后,我们来看本章的核心:动量守恒。什么意思?动量是守恒不变的?什么时候?哪
里?如何守恒?OK,慢慢来。动量守恒可在碰撞中使用。碰撞检测一章中的碰撞反应都是仿
造出来的。而动量守恒才是碰撞反应的实际原理。
     有了动量守恒,我们就可以这样说,“在碰撞之前,一个物体以 A 速度运动,另一个
物体以 B 速度运动。碰撞之后,该物体以 C 速度运动,另一个物体以 D 速度运动。”,
分解来看,我们知道速度 v 是由速度和方向构成的,如果在碰撞之前知道了两个物体的速
度和方向,就可以求出两物体碰撞后的速度和方向。非常实用的定理,大家也是这样认为的
吧。
     注意:我们需要知道每个物体的质量。实际应用中,如果在碰撞前,知道每个物体的质
量,速度和方向,就可以求出碰撞后物体的运动方向和速度了。
    OK,那么动量守恒到底能为我们做些什么呢?它又是什么样的呢?动量守恒定理告诉我
们:在系统中,碰撞前的动量总合与碰撞后的动量总合相等。那么定理中所谓的系统是指什
么呢?它是指一个拥有动量的物体的集合。多数情况下,是指一个封闭系统,也就是不受其
它外力影响的系统。换句话讲,也就是可以忽略除实际碰撞以外的一切。对于我们而言,只
关注两个物体之的反作用力, 系统总是以物体 A 和物体 B 这样的形式出现。  系统的总动量
就是由系统中所有物体的动量结合而成。 按照这个例子来讲,就是把物体 A 和物体 B 的动
量相加到在一起。 因此,碰撞前将动量之和,与碰撞后动量之和相同的。大家也许会问,  “那
太好了,但是定理没有告诉我们怎么求得的动力啊。”。不要急,马上来说这个问题,说好
了,要一步步来。下面几段,要慢慢来看,因为会有公式!
     在学数学前,给大家几条建议。先不要想怎么把公式转换成代码,马上会讲到。现在大
家要集中看好下面几个公式的概念。 “一个数加上另一个数等于另一个数加上这个数。  当然,
这是有意义的。”。
     OK,如果碰撞前的动量之和等于碰撞后的动量之和,并且动量等于速度乘以质量,那么
对于两个物体——物体 0 和 物体 1——我们会得出 [ momentum :动量 ]:
     momentum0 + momentum1 = momentum0Final + momentum1Final
或者:
     (m0 * v0) + (m1 * v1) = (m0 * v0Final) + (m1 * v1Final)

    现在我们要知道的就是 物体 0 和 物体 1 的最终速度,也就是 v0Final 和 v1Final。
解一个有两个未知数的方程需要找出另一个有两个相同未知数的方程。      物理学中恰好有这样
一个方程,这就是动能公式。我们不需要关心动能是什么,只需要借这个公式来解决我们的
问题,用完后再还回去。动能公式如下:
                      2
    KE = 0.5 * m * v
    虽然这里用 v 表示速度,但是严格来讲,动能不是向量,它只是速度向量中的量值的
大小,并不涉及方向。
    碰撞前的动能刚好与碰撞后相同。因此可以这样表示:
    KE0 + KE1 = KE0Final + KE1Final
或者:
                                                                            2
    (0.5 * m0 * v0 ) + (0.5 * m1 * v1 ) = (0.5 * m0 * v0Final ) + (0.5 * m1 * v1Final )
    两边同时消去因数 0.5 后:
                                                         2
    (m0 * v0 ) + (m1 * v1 ) = (m0 * v0Final ) + (m1 * v1Final )

 

(2是平方- -||)
    这样就得到了两个方式,带有两个相同的未知变量:v0final 和 v1Final。然后就可以
为每个未知数求出一个等式。接下来就是代数问题了,为了让你我都不感到头痛,直接给出
最终的公式。如果您喜欢求代数式,或者想在学校拿到更高的学分的话,我建议您坐下来拿
几张纸几支笔自己算一算。那么计算出的结果应该是这样的:
                (m0 – m1) * v0 + 2 * m1 * v1
v0Final = ----------------------------------------------
                          m0 + m1
                (m1 – m0) * v1 + 2 * m0 * v0
v1Final = ---------------------------------------------
                          m0 + m1
现在大家知道为什么我一开始说这章非常之复杂了吧。
下面先在单轴上进行应用,随后制作两个轴上的运动时会加入坐标旋转。继续!
单轴上的动量守恒
      现在公式已经有了,可以开始应用了。第一个例子,我们继续使用 Ball 类,但这次要
加入质量(mass)这个属性。新的代码如下(Ball.as):
package {
  import flash.display.Sprite;
  public class Ball extends Sprite {
   private var radius:Number;
   private var color:uint;
   public var vx:Number = 0;
   public var vy:Number = 0;
    public var mass:Number = 1;
   public function Ball(radius:Number=40, color:uint=0xff0000) {
     this.radius = radius;
     this.color = color;
     init();
   }
   public function init():void {
     graphics.beginFill(color);
     graphics.drawCircle(0, 0, radius);
     graphics.endFill();
   }
  }
}
      我们要创建两个 Ball 类的实例,使用不同的大小,位置和质量。开始先忽略 y 轴的
运动。因此影片开始时基本的设置如图 11-1 所示。
转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)


图 11-1 单轴动量守恒运动的舞台设置
      类的开始是创建两个小球放入舞台上,然后进行单轴上的基本运动代码,并使用简单的
距离碰撞检测:
package {
  import flash.display.Sprite;
  import flash.events.Event;
  public class Billiard1 extends Sprite {
   private var ball0:Ball;
   private var ball1:Ball;
   public function Billiard1() {
     init();
   }
   private function init():void {
     ball0 = new Ball(40);
     ball0.mass = 2;
     ball0.x = 50;
     ball0.y = stage.stageHeight / 2;
     ball0.vx = 1;
     addChild(ball0);
     ball1 = new Ball(25);
     ball1.mass = 1;
     ball1.x = 300;
     ball1.y = stage.stageHeight / 2;
     ball1.vx = -1;
     addChild(ball1);
     addEventListener(Event.ENTER_FRAME, onEnterFrame);
   }
 private function onEnterFrame(event:Event):void {
   ball0.x += ball0.vx;
   ball1.x += ball1.vx;
   var dist:Number = ball1.x - ball0.x;
   if (Math.abs(dist) < ball0.radius + ball1.radius) {
    // 在此执行反作用力
   }
 }
}
}
    目前,唯一的问题是如何执行反作用力。先来看 ball0。将 ball0 看作物体 0,ball1
就是物体 1,运用下面这个公式:
                (m0 – m1) * v0 + 2 * m1 * v1
v0Final = ----------------------------------------------
                          m0 + m1
在 ActionScript 中就变成了下面这段代码:
var vx0Final:Number = ((ball0.mass - ball1.mass) * ball0.vx +
2 * ball1.mass * ball1.vx) /
(ball0.mass + ball1.mass);
不难理解吧。那么 ball1 也是如此:
                (m1 – m0) * v1 + 2 * m0 * v0
v1Final = ---------------------------------------------
                          m0 + m1
代码如下:

var vx1Final:Number = ((ball1.mass - ball0.mass) * ball1.vx +
2 * ball0.mass * ball0.vx) /
(ball0.mass + ball1.mass);
      最后 onEnterFrame 中的代码如下:
private function onEnterFrame(event:Event):void {
  ball0.x += ball0.vx;
  ball1.x += ball1.vx;
  var dist:Number = ball1.x - ball0.x;
  if (Math.abs(dist) < ball0.radius + ball1.radius) {
    var vx0Final:Number = ((ball0.mass - ball1.mass) * ball0.vx +
    2 * ball1.mass * ball1.vx) /
    (ball0.mass + ball1.mass);
    var vx1Final:Number = ((ball1.mass - ball0.mass) * ball1.vx +
    2 * ball0.mass * ball0.vx) /
    (ball0.mass + ball1.mass);
    ball0.vx = vx0Final;
    ball1.vx = vx1Final;
    ball0.x += ball0.vx;
    ball1.x += ball1.vx;
  }
}
      注意,在计算 vx0Final 时用到了 ball1.vx,反之亦然。因此,不得不把结果作为临
时变量保存起来,而不是直接将它们赋值给 ball0.vx 和 ball1.vx。


设置物体位置
    前面例子中动作脚本的最后两行应该解释一下。在求出了每个小球的新的速度后,再把
它们加到小球的位置上。这是个新内容,为什么要这么做?回忆一下,在前面的反弹例子中,
需要重置影片的位置,为的是不让它进入到墙体内。当物体与墙面接触时就对它进行移动。

这里也是如此,但是这次有两样东西需要移动,因为不想让它们彼此相互吸引。这样一看就
是错的,而且通常都会使两个物体永远地粘在一起。
    我们要将其中一个小球移动到另一个小球的边上。但是要移动哪一个呢?无论移动哪个
都会使物体像跳到新位置上一样不自然,尤其是在运动速度很慢的情况下。
    有很多的方法可用来确定小球移动的位置,这些方法从简单到复杂,从精确到模拟的都
有。在第一个例子中用的是简单的解决方法只要加上新速度,就可以让两个物体分开。我认
为这是最真实也是最简单的方法——只要两句代码就能完成。随后,在“解决潜在问题”一
节中,我会给大家介绍一个更加健全的解决方法。
    试编译运行文档类 Billiard1.as,改变每个小球的质量与速度,也可以改变小球的大
小。注意,ball 的大小不会对反作用力有什么影响。多数情况下,物体体积越大,则质量
就越大,可以根据两个小球的相对大小给出真实的质量。通常,我在给出质量时都是在试数,
看上去合适就可以。严格来说应该是“小球的体积扩大两倍,则质量也要扩大两倍”。

代码优化
     这段代码最不好的地方就是中间大段的等式。  事实上,最坏的部分就是两个几乎完全相
同的等式出现了两次,如果可以减少一个就好了。OK,没有问题。
     用两个物体速度相减求出总的速度,看起来有些奇怪,但是要从系统的角度来思考。假
设系统中有两辆车在高速路上。其中一辆车的速度是 50 mph 另一辆车的速度是 60 mph。
坐在随便一辆车中,可以看到另一辆车是以 10 mph 或 -10 mph 的速度前进。换句话讲,
另一辆车不是在你前,就是在你后面。
     因此,在碰撞之前,要求出总的速度(以 ball1 的角度) 用 ball0.vx 减去 ball1.vx:
                                                       
var vxTotal:Number = ball0.vx - ball1.vx;
     最后,在计算出 vx0Final 之后,再将它与 vxTotal 相加,就得出了 vx1Final。也许
有些违反直觉,没关系试验一下:
     vx1Final = vxTotal + vx0Final;
     OK!这样比每次输入两遍公式要好很多。现在,ball1.vx 这个式子不会对 ball0.vx 造
成任何影响。 所以,又可以把两个临时变量去掉了。以下是修正后的 onEnterFrame 方法(见
文档类 Billiard2.as):
private function onEnterFrame(event:Event):void {
  ball0.x += ball0.vx;
  ball1.x += ball1.vx;
  var dist:Number = ball1.x - ball0.x;
  if (Math.abs(dist) < ball0.radius + ball1.radius) {
   var vxTotal:Number = ball0.vx - ball1.vx;
   ball0.vx = ((ball0.mass - ball1.mass) * ball0.vx +
   2 * ball1.mass * ball1.vx) /
   (ball0.mass + ball1.mass);
   ball1.vx = vxTotal + ball0.vx;
   ball0.x += ball0.vx;
   ball1.x += ball1.vx;
  }
}
    现在,已经去掉了很多数学运算,并且运行结果相同——不错。
      这些公式并要求大家都能记住,除非您是学物理的。除非经常使用,否则很难记忆。
就我个人而言,在我要使用这个公式时,都会翻到第一个版本的例子中,直接复制!

两个轴上的动量守恒
      OK,深呼吸,进入下一级。现在,我们已经用过了这个冗长的公式,而它几乎是即插即
用型的。只需要把两个物体的质量和速度插入公式中,就可以得到结果。
  下面,进入更为复杂的一级——二维空间。本章开始时说过,其策略是使用坐标旋转。让
我们来看看原因。

理解原理及策略
  图 11-2 表示刚才看到那个例子:一维的碰撞。


转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-2 一维碰撞
    可以看到,两个物体有着不同的大小,不同的质量以及不同的速度。速度用箭头表示,
就是向量。回忆一下,速度向量指针表示运动的方向,长度表示速度的大小。
    一维的例子非常简单,因为两个速度向量都在 x 轴上。所以,可以直接加上或减去它
们的量值(长度)。现在,请看图 11-3,小球在二维空间中的碰撞。


转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-3 二维碰撞
    速度向量完全不同了,不能单纯地将速度代入到动量守恒公式中,因为,这会导致完全
错误的结果。那么应该如何解决呢?
    通过旋转第二张图,可以得到与第一张非常相似的图。首先,要知道两个小球之间形成
的角度并且旋转整个场景——坐标和速度——逆时针旋转。例如,如果角度是 30 度,就将
所有的物体旋转 -30 度,这与第十章的斜面反弹是一样的。结果如图 11-4 所示。

转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-4 旋转后的二维碰撞
    两个小球之间的角度非常重要,这个角度称为碰撞角度。重要的原因在于,它是小球速
度的一部分——速度的一部分要依赖于角度。
    下面请看图 11-5。这里,在每个向量上面加入了 vx 和 vy。注意,两个小球的 vx 都
严格地依照碰撞的角度来定。

图 11-5 加入 x,y 速度
  我们说过,只关心碰撞的角度。那么现在它就是 vx,可以忘掉 vy。如图 11-6 所示。

转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-6 只关心 x 速度
    看眼熟吗?这就是第一张图!现在可以使用即插即用的动量公式来解决这个问题了。 请
                                                                           
注意解题的步骤!)
    在应用这个公式时,会得出两个新的 vx 值。记住 vy 的值永远不变。vx 的变化如图
11-7 所示。

转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-7 新的 x 速度,y 速度不变,得出新的速度
  猜到下面该怎么办了吗?只需要把一切旋转回去,如图 11-8 所示。

转 <wbr>第十一章 <wbr>撞球物理(1)(as3.0)
图 11-8 将一切旋转回来
  下面把这个过程转换为代码。对我来说最难的地方就是要一再地说服大家“这很容易”。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值