用Flash编写微型教学软件──《光速的测量》制作要点
 
紫琅中学    吴建国
 
 

《光速的测量》帮助文件开始部分,对软件的功能做了一个说明:
在美国物理学家迈克耳逊1926年所做的这个著名的实验中,八面镜与远处凹面镜之间的距离为22英里(35.4千米)。这个距离超过八面镜尺寸的50000倍,在动画中无法按比例来表现。八面镜以读者指定的转速旋转;不过这里显示的是“慢镜头”:这里1秒钟大约表示真实时间(1/22000)秒。这里显示的光的运动当然也是“慢镜头”,而且是更慢的“慢镜头”。八面镜静止不转时,从望远镜能看到回来的光;读者可以亲手“试验”,看看把八面镜的转速增加到多大时,从望远镜能间断地看到回来的光。
下面介绍《光速的测量》制作过程,特别是ActionScript的编写。
一.制作符号
新建一个图片(graphic),命名为“mirror”,其中画边长为20像素的八面镜的截面图。
新建一个图片,命名为“concaveAndPlane”,其中画左右彼此相对的凹面镜和平面镜,两者相距55像素。凹面镜高38像素,平面镜高34像素。
新建一个图片,命名为“telescope”,其中画一只竖直的望远镜。
新建一个图片,命名为“photon”,在原点附近画一条长度为8像素的水平短线,表示光粒子(或者一份光波)。
新建一个电影剪辑(movie clip),命名为“lampHouse”,其中作一个简单动画(比如半径变化着的圆),表示一个正在发光的光源。
新建一个电影剪辑,命名为“mirrorRotation”。首帧为关键帧,引入一个“mirror”,放在(0,0)位置,其实例名也定为“mirror”。第2帧为普通帧。在“mirror”上捆绑一段代码,指定八面镜的角度(_rotation)按读者指定的转动频率而变化。
新建一个电影剪辑,命名为“lightEarly”。1-5帧,表现光粒子从光源竖直向下运动到八面镜。6-40帧,表现光粒子从八面镜向左边(水平或倾斜)运动。第6帧为关键帧,引入一个“photon”,放在(0,0)位置,其实例名也定为“photon”。7-40帧为普通帧。在“photon”上捆绑一段代码,指定光粒子根据反射时八面镜的角度,沿适当方向运动。
新建一个电影剪辑,命名为“lightLater”,1-6帧,表现光粒子从平面镜上端水平向左运动到凹面镜,从凹面镜运动到平面镜,从平面镜运动到凹面镜。7-35帧,表现光粒子从凹面镜水平向右运动到八面镜。36-42帧,表现光粒子从凹面镜向下方(竖直或倾斜)运动。第36帧为关键帧,引入一个“photon”,放在(0,0)位置,其实例名也定为“photon”。37-42帧为普通帧。在“photon”上捆绑一段代码,指定光粒子根据反射时八面镜的角度,沿适当方向运动。
新建一个电影剪辑,命名为“light”,三层。第一层首帧为关键帧,引入一个“lightEarly”;2-40帧为普通帧。第二层第34帧为关键帧,引入“lightLater”;35-75帧为普通帧。在第三层第34帧放置一段代码,设置“如光粒子第一次反射后几乎水平向左运动,则从此帧开始“lightEarly”不可见;否则,从此帧开始 “lightLater”不可见。
新建一个电影剪辑,命名为“lights”。首帧为关键帧,第2帧为普通帧。在首帧放置一段代码:指定复制一个“light”。运行时每次执行该帧,将新复制一个“light”。如此表现光源不断发光。
新建一个电影剪辑,命名为“main”,三层,内容暂为空白。
二.组装
打开场景1,引入电影剪辑“main”(待以后调整位置)。实例名为“main”。放置一个输入文本框(input textbox),其变量名为w。这个文本框用以让用户输入一个数值,作为八面镜的转动频率。
打开电影剪辑“mian”,从符号库引入若干符号。第一层右上方放置“lampHouse”。其下方放置“mirrorRotation”,实例名为“mirrorRotation”。“mirrorRotation”下方放置望远镜“telescope”。“mirrorRotation”上的A点应位于“lampHouse”正下方100像素处。望远镜上端应位于A点正下方144像素处。左边放置“concaveAndPlane”,其凹面镜上端位于A点左边605像素处。第二层右上方放置 “light”,其实例名也定为“light”。 “light”的中心点跟“lampHouse”的中心点重合。第三层放置“lights”,位置任意。
三.编写ActionScript代码
双斜杠后面的文字是注释。
1.捆绑在电影剪辑实例_root.main.mirrorRotation.mirror上的代码。
onClipEvent (load) {q1 = 0;}
//装载(load)的时候,本地变量q1取0.以后可以看出,q1是八面镜相对初始位置旋转的角度。
//每次进入(enter)新的一帧(frame),都执行下面的代码。
onClipEvent (enterFrame) {
    w = _root.w;
    if (isNaN(w) == true) {w = 0;}
//本地变量w获取场景1文本框内的内容(转动频率)。如果w不是数值,w取0。
    q1 = q1-1/12*w*360/22225;
//w为正值时,八面镜逆时针旋转,八面镜的角度减小(跟解析几何中的规定不同),q1减小。其中(1/12)是推进一帧所用的时间。22225这个除数是额外加上去的,从而读者看到的是慢镜头。
    this._rotation = q1;
//八面镜的角度取q1。
    q = q1-45*Math.round(q1/45);}
//Math.round()根据四舍五入法则取整数。q的取值范围是[-22.5,22.5].八面镜当时接受入射光的那个面相对当初接受入射光的那个面当初的位置转过的角度等于这个数值。后面会用到这个数值。
2.捆绑在电影剪辑实例_root.main.light.lightEarly上的代码。
onClipEvent (load) {
q = _root.main.mirrorRotate.mirror.q;
//本地变量q等于前一段代码中的q。
x1 = 20*Math.cos((180+2*q)*Math.PI/180);
y1 = 20*Math.sin((180+2*q)*Math.PI/180);
//Math.PI是圆周率常数。(180+2*q)是反射后光粒子前进的方向。设每推进一帧光粒子前进20像素。x1和y1是每推进一帧光粒子横坐标和纵坐标的变化量。
this._rotation = 180+2*q;}
onClipEvent (enterFrame) {
this._x = this._x+x1;
this._y = this._y+y1;}
3.捆绑在电影剪辑实例_root.main.light.lightLater上的代码。
onClipEvent(load){
q=_root.main.mirrorRotate.mirror.q
x1 = 20*Math.cos((90+2*q)*Math.PI/180);
y1 = 20*Math.sin((90+2*q)*Math.PI/180);
this._rotation=90+2*q}
onClipEvent (enterFrame) {
this._x = this._x+x1
this._y = this._y+y1}
4.电影剪辑light第三层第34帧代码.
w = _root.w;
if (isNaN(w) == true) {w = 0;}
d = Math.abs(w)/1800+0.15;
//光粒子反射时的q取0附近区域(-d,d)内的数值时,光能够到达凹面镜。初步确定d的值。由于动画设计上的局限,需要有点不合逻辑的这样一个式子。
d = Math.min(d, 0.5);
//进一步确定d的数值,d不至于超过0.5.
q = this.lightEarly.photon.q;
//q取光粒子向下运动射到八面镜时八面镜的q。
if (Math.abs(q)>=d) {
this.lightLater._visible = false;}
//q取值超出(-d,d)时,不显示lightLater。
if (Math.abs(q+0.89)<0.89+d) {
this.lightEarly._visible = false;}
//从左边过来的光粒子射到平面镜后,不再显示。
5.电影剪辑lights第1帧代码。
n = n+1;
duplicateMovieClip ("_root.main.light", "l"+n, n);
//第一次运行这一帧时,把_root.main.light复制一份,命名为l1;第二次运行这一帧时,把_root.main.light复制一份,命名为l2;等等。
if (n>38) { n = 0;}
//如此,第39,40,41…个复制品,将覆盖第1,2,3…个复制品,以免陈旧的复制品无益地占用内存。
把八面镜的转速调到约529转/秒的时候,射向望远镜的光实际上是一闪一闪的,但闪烁得太快了,人眼看起来,光是稳定的。在软件中八面镜的转速调到约1058转/秒的时候,同样可以从望远镜看到光;但当时的实验中是不会发生这样的事情的,530转/秒可能已经接近当时技术上的极限了。

 
关闭