Flash面向对象程序设计的演变
类别: Flash教程
注:以下引用出自<<Flash ActionScript 2.0-RIA应用程式开发 >>,引用已得到本书作者:Luar的允许.如涉及版权问题请与我联系,马上擦除.转贴请注明出处.
本节会以一个粒子运动系统(粒子运动系统其实是大量Movie Clip在一个范围内随机移动,当碰到边界便会反弹)作范例,讲解Movie Clip面向对象程序设计上的改变.
1.全域函数
开发步骤:
先准备好一个Movie Clip ball代表粒子,大量地将它拖到舞台上,输入这些Movie Clip ball实体名称,例如由ball0到ball14.
以美工角度加上时间轴的思考模式,Movie Clip ball会直接在主影片的时间轴上受控制,意思是程序会放在主影片的时间轴时,路径跟所有Movie Clip ball实体是一致的,而这种在主影片的时间轴里程序,是全域程序,因为由_root可以直接访问到.
由于粒子要不停移动,为了使负责移动的程序不停执行,时间轴必须循环播放,不停经过有程序的帧,让粒子移动.
对ActionScript认识较多的美工,会将初始化和移动的程序写成函数,否则可能只是直接地在第1和2帧加入程序.这些函数,路径是_root,视为全域函数;直到现在,大部分Flash开发人员,仍然是以全域函数方法开发应用程序或程序设计互动效果.
良好的程序设计习惯上, 函数是放在第1帧,在图层script加入程序代码, initBall()是初始化函数,计算每个粒子开始时的移动角度,然后分成x 速度和y速度:
继续加入程序代码,程序设计移动程序的函数:
在第一帧加入变量ballno,代表粒子总数;最后,调用initBall()函数进行初始化,继续加入程序代码.
在第二帧加入程序代码,调用moveBall()函数移动粒子:
在第三帧加入程序代码,跳到第二帧循环播放,让moveBall()函数不停地被调用:
这个以全域函数编写的粒子运动系统完成,可以测试影片.
特点分析:
全域函数是最容易学习的程序设计技巧,但它有以下的三个问题:
1.面向对象成份很低
在程序设计中,涉及的面向对象概念很少,在图形使用上则达到重用要求(所有粒子实体都是来自同一个Movie Clip元件).
2.缺乏封装性
全域函数将程序代码和图形分离,当需要在别的专案中重用时,必须小心抽出所需的程序代码和图形,封装性完全缺乏.
3.留意Movie Clip路径
全域函数直接控制Movie Clip,假设Movie Clip和全域函数都是在同一个时间轴中(例如:主影片),没有路径问题;但是当受控制Movie Clip是在另一个Movie Clip里,全域函数就要修改受控制Movie Clip的路径,或者将全域函数搬到那Movie Clip的时间轴里去.
2.对像区域函数
区域函数意思就是将原来放在主影片时间轴的全域函数搬到对象里,即放在Movie Clip ball的时间轴里.
开发步骤:
选择主影片图层script第一至第三帧,按右键选”Cut Frames”,如图所示.
编辑元件库里Movie Clip ball,插入帧至3个,增加图层,选择头3个帧,按右键选”Paste Frames”,如图所示.
编辑第1帧的代码,改为以下程序代码:
程序修改主要是删去for循环,以及将路径删去(自己不用路径).修改后可以测试影片.
特点分析:
区域函数和全域函数的不同之外是:
1.程序和图形放在一起,封装性改善了,容易拷贝到另一个地方使用.
2.没有路径考虑,在别的Movie Clip里都可以使用.
不过,区域函数有一个致命问题:虽然区域函数是写在Movie Clip元件里,但是每个Movie Clip实体都会有一套区域函数在自己时间轴里.他们的区域函数其实是完全相同,这么多份区域函数会严重浪费内存.
3.原型(Prototype)扩展
由于所有舞台上的Movie Clip都是MovieClip类的具体表现(唯一可视化的实体),所以在MovieClip类直接加入关于随机移动的方法,所有粒子实体就会有随机移动的方法供调用,避免浪费内存.
原型是ActionScript 1.0中用来建立继承或将自定属性和方法增加到对象中之用.利用关键字”prototype”,为MovieClip类增加两个方法,分别是initBall()和moveBall().
开发步骤:
基于上面的源程序的修改.主影片时间轴只保留第一帧,新增回图层script,加入扩充MovieClip类方法的程序代码(可以从Movie Clip ball第一帧复制):
程序代码要修改的地方不多,只是加上关键字”this”,代表指向自己的属性.
编辑元件库里Movie Clip ball,只保留第一帧,将程序代码改成:
onEnterFrame是Movie Clip其中一个事件,它会根据影片帧速率(Frame Rate)不停执行程序.修改后可以测试影片.
特点分析:
原型扩展虽然避免了重复区域函数浪费内存,但是由于它直接在MovieClip类加入关于随机移动等方法,污染了MovieClip类,因为所有舞台上Movie Clip实体,就算不是粒子,都会有这两个方法.
4.封装成组件
针对原型扩展缺点,正确方法是建立一个新对象(例如:粒子类),并继承MovieClip类.这个做法,在Flash MX时,就是所谓以ActionScript 1.0来进行面向对象程序设计的做法.其实这做法跟开发Flash MX组件是没有分别,换句话说,开发Flash MX组件就是ActionScript 1.0面向对象程序设计的常见情况.
开发步骤:
基于上面的源程序修改.拷贝主影片时间轴图层script第一帧的程序代码,然后删除图层script.编辑元件库里Movie Clip ball图层script的第一帧,将旧有两行程序代码删除,粘贴刚才主影片的程序代码,然后如以下程序代码作修改:
在元件库里Movie Clip ball旁按右键选”连结”,如图所示
勾选”Exprot for ActionScript”,取消勾选”Export in first fame”,识别名称输入ball.这样BallClass类便可以跟此元件相关联,所有此元件在舞台的Movie Clip实体,也就是BallClass实体.修改后可以测试影片.
特点分析:
在Flash MX时,这是普遍面向对像程序设计的做法,写成的粒子组件,在重用性,封装性等上都已经达到Flash面向对象程序设计的要求.唯一缺点是Prototype Based的面向对象程序设计不是业界习惯,所以到Flash MX 2004就有了ActionScript 2.0.
5.ActionScript 2.0类
粒子运动系统以ActionScript 2.0重写,面向对象概念跟ActionScript 1.0没有分别,只是方法上不同.
开发步骤:
基于上面的源程序的修改.将Movie Clip ball图层script删除.在元件库里Movie Clip ball旁按右键选”连结”,输入AS 2.0类为BallClass,这步骤已经等于Object.registerClass(“ball”,BallClass);
建立一个名为BallClass.as的文件,加入程序代码:
完成后可以测试影片(记得以Flash 6/7 ActionScript 2.0发布).
特点分析:
ActionScript 1.0的类,如果没有名称领域,都是在_root建立 ,ActionScript 2.0的类,则在_global建立,而且自行处理好名称领域问题.
从以上各例子一步步的演变,可以看到无论面向对象程序设计语法是如何改变,最核心控制粒子随机移动的程序都是大同小异的,而且面向对象程序设计概念是不变的.因此Flash MX面向对象程序设计新手要从全域函数到程序设计ActionScript 2.0是没有障碍的,学了面向对象程序设计概念,学了ActionScript 2.0方法,就应该踏出尝试第一步.
本节会以一个粒子运动系统(粒子运动系统其实是大量Movie Clip在一个范围内随机移动,当碰到边界便会反弹)作范例,讲解Movie Clip面向对象程序设计上的改变.
1.全域函数
开发步骤:
先准备好一个Movie Clip ball代表粒子,大量地将它拖到舞台上,输入这些Movie Clip ball实体名称,例如由ball0到ball14.
以美工角度加上时间轴的思考模式,Movie Clip ball会直接在主影片的时间轴上受控制,意思是程序会放在主影片的时间轴时,路径跟所有Movie Clip ball实体是一致的,而这种在主影片的时间轴里程序,是全域程序,因为由_root可以直接访问到.
由于粒子要不停移动,为了使负责移动的程序不停执行,时间轴必须循环播放,不停经过有程序的帧,让粒子移动.
对ActionScript认识较多的美工,会将初始化和移动的程序写成函数,否则可能只是直接地在第1和2帧加入程序.这些函数,路径是_root,视为全域函数;直到现在,大部分Flash开发人员,仍然是以全域函数方法开发应用程序或程序设计互动效果.
良好的程序设计习惯上, 函数是放在第1帧,在图层script加入程序代码, initBall()是初始化函数,计算每个粒子开始时的移动角度,然后分成x 速度和y速度:
程序代码: |
function initBall() { var speed = 10; for (var i = 0; i<ballno; i++) { var dir = random(360)*Math.PI/180; this["ball"+i].xdir = Math.cos(dir)*speed; this["ball"+i].ydir = Math.sin(dir)*speed; } } |
继续加入程序代码,程序设计移动程序的函数:
程序代码: |
function moveBall() { for (var i = 0; i<ballno; i++) { //利用共用子表达式删除增加执行速度 var ball = this["ball"+i]; var x = ball._x; var y = ball._y; x += ball.xdir; y += ball.ydir; if ((x<0 and ball.xdir<0) or (x>292 and ball.xdir>0)) { //碰到边界便能会反弹 ball.xdir *= -1; //粒子不可穿过边界,所以极限的位置是边界大小 x = (x<0) ? 0 : 292; } else if ((y<0 and ball.ydir<0) or (y>292 and ball.ydir>0)) { //碰到边界便能会反弹 ball.ydir *= -1; //粒子不可穿过边界,所以极限的位置是边界大小 y = (y<0) ? 0 : 292; } ball._x = x; ball._y = y; } } |
在第一帧加入变量ballno,代表粒子总数;最后,调用initBall()函数进行初始化,继续加入程序代码.
程序代码: |
ballno =15; initBall(); |
在第二帧加入程序代码,调用moveBall()函数移动粒子:
程序代码: |
moveBall(); |
在第三帧加入程序代码,跳到第二帧循环播放,让moveBall()函数不停地被调用:
程序代码: |
gotoAndPlay(2); |
这个以全域函数编写的粒子运动系统完成,可以测试影片.
特点分析:
全域函数是最容易学习的程序设计技巧,但它有以下的三个问题:
1.面向对象成份很低
在程序设计中,涉及的面向对象概念很少,在图形使用上则达到重用要求(所有粒子实体都是来自同一个Movie Clip元件).
2.缺乏封装性
全域函数将程序代码和图形分离,当需要在别的专案中重用时,必须小心抽出所需的程序代码和图形,封装性完全缺乏.
3.留意Movie Clip路径
全域函数直接控制Movie Clip,假设Movie Clip和全域函数都是在同一个时间轴中(例如:主影片),没有路径问题;但是当受控制Movie Clip是在另一个Movie Clip里,全域函数就要修改受控制Movie Clip的路径,或者将全域函数搬到那Movie Clip的时间轴里去.
2.对像区域函数
区域函数意思就是将原来放在主影片时间轴的全域函数搬到对象里,即放在Movie Clip ball的时间轴里.
开发步骤:
选择主影片图层script第一至第三帧,按右键选”Cut Frames”,如图所示.
编辑元件库里Movie Clip ball,插入帧至3个,增加图层,选择头3个帧,按右键选”Paste Frames”,如图所示.
编辑第1帧的代码,改为以下程序代码:
程序代码: |
function initBall() { var speed = 10; var dir = random(360)*Math.PI/180; xdir = Math.cos(dir)*speed; ydir = Math.sin(dir)*speed; } function moveBall() { var x = _x; var y = _y; x += xdir; y += ydir; if ((x<0 and xdir<0) or (x>292 and xdir>0)) { xdir *= -1; x = (x<0) ? 0 : 292; } else if ((y<0 and ydir<0) or (y>292 and ydir>0)) { ydir *= -1; y = (y<0) ? 0 : 292; } _x = x; _y = y; } initBall(); |
程序修改主要是删去for循环,以及将路径删去(自己不用路径).修改后可以测试影片.
特点分析:
区域函数和全域函数的不同之外是:
1.程序和图形放在一起,封装性改善了,容易拷贝到另一个地方使用.
2.没有路径考虑,在别的Movie Clip里都可以使用.
不过,区域函数有一个致命问题:虽然区域函数是写在Movie Clip元件里,但是每个Movie Clip实体都会有一套区域函数在自己时间轴里.他们的区域函数其实是完全相同,这么多份区域函数会严重浪费内存.
3.原型(Prototype)扩展
由于所有舞台上的Movie Clip都是MovieClip类的具体表现(唯一可视化的实体),所以在MovieClip类直接加入关于随机移动的方法,所有粒子实体就会有随机移动的方法供调用,避免浪费内存.
原型是ActionScript 1.0中用来建立继承或将自定属性和方法增加到对象中之用.利用关键字”prototype”,为MovieClip类增加两个方法,分别是initBall()和moveBall().
开发步骤:
基于上面的源程序的修改.主影片时间轴只保留第一帧,新增回图层script,加入扩充MovieClip类方法的程序代码(可以从Movie Clip ball第一帧复制):
程序代码: |
MovieClip.prototype.initBall = function() { var speed = 10; var dir = random(360)*Math.PI/180; this.xdir = Math.cos(dir)*speed; this.ydir = Math.sin(dir)*speed; }; MovieClip.prototype.moveBall=function() { var x = this._x; var y = this._y; x +=this. xdir; y += this.ydir; if ((x<0 and this.xdir<0) or (x>292 and this.xdir>0)) { this.xdir *= -1; x = (x<0) ? 0 : 292; } else if ((y<0 and this.ydir<0) or (y>292 and this.ydir>0)) { this.ydir *= -1; y = (y<0) ? 0 : 292; } this._x = x; this._y = y; } |
程序代码要修改的地方不多,只是加上关键字”this”,代表指向自己的属性.
编辑元件库里Movie Clip ball,只保留第一帧,将程序代码改成:
程序代码: |
initBall(); this.onEnterFrame=moveBall; |
onEnterFrame是Movie Clip其中一个事件,它会根据影片帧速率(Frame Rate)不停执行程序.修改后可以测试影片.
特点分析:
原型扩展虽然避免了重复区域函数浪费内存,但是由于它直接在MovieClip类加入关于随机移动等方法,污染了MovieClip类,因为所有舞台上Movie Clip实体,就算不是粒子,都会有这两个方法.
4.封装成组件
针对原型扩展缺点,正确方法是建立一个新对象(例如:粒子类),并继承MovieClip类.这个做法,在Flash MX时,就是所谓以ActionScript 1.0来进行面向对象程序设计的做法.其实这做法跟开发Flash MX组件是没有分别,换句话说,开发Flash MX组件就是ActionScript 1.0面向对象程序设计的常见情况.
开发步骤:
基于上面的源程序修改.拷贝主影片时间轴图层script第一帧的程序代码,然后删除图层script.编辑元件库里Movie Clip ball图层script的第一帧,将旧有两行程序代码删除,粘贴刚才主影片的程序代码,然后如以下程序代码作修改:
程序代码: |
#initclip //建构函式 BallClass = function () { this.initBall(); }; //继承MovieClip类 MovieClip.prototype = new MovieClip(); //定义方法 BallClass.prototype.initBall = function() { var speed = 10; var dir = random(360)*Math.PI/180; this.xdir = Math.cos(dir)*speed; this.ydir = Math.sin(dir)*speed; this.onEnterFrame=this.moveBall; }; BallClass.prototype.moveBall = function() { var x = this._x; var y = this._y; x += this.xdir; y += this.ydir; if ((x<0 and this.xdir<0) or (x>292 and this.xdir>0)) { this.xdir *= -1; x = (x<0) ? 0 : 292; } else if ((y<0 and this.ydir<0) or (y>292 and this.ydir>0)) { this.ydir *= -1; y = (y<0) ? 0 : 292; } this._x = x; this._y = y; }; //将BallClass类与Movie Clip元件相关联 Object.registerClass("ball",BallClass); #endinitclip |
在元件库里Movie Clip ball旁按右键选”连结”,如图所示
勾选”Exprot for ActionScript”,取消勾选”Export in first fame”,识别名称输入ball.这样BallClass类便可以跟此元件相关联,所有此元件在舞台的Movie Clip实体,也就是BallClass实体.修改后可以测试影片.
特点分析:
在Flash MX时,这是普遍面向对像程序设计的做法,写成的粒子组件,在重用性,封装性等上都已经达到Flash面向对象程序设计的要求.唯一缺点是Prototype Based的面向对象程序设计不是业界习惯,所以到Flash MX 2004就有了ActionScript 2.0.
5.ActionScript 2.0类
粒子运动系统以ActionScript 2.0重写,面向对象概念跟ActionScript 1.0没有分别,只是方法上不同.
开发步骤:
基于上面的源程序的修改.将Movie Clip ball图层script删除.在元件库里Movie Clip ball旁按右键选”连结”,输入AS 2.0类为BallClass,这步骤已经等于Object.registerClass(“ball”,BallClass);
建立一个名为BallClass.as的文件,加入程序代码:
程序代码: |
//继承MovieClip类 class BallClass extends MovieClip { //属性 private var xdir:Number; private var ydir:Number; //建构函式 function BallClass() { initBall(); } //方法 private function initBall():Void { var speed = 10; var dir = random(360)*Math.PI/180; xdir = Math.cos(dir)*speed; ydir = Math.sin(dir)*speed; onEnterFrame = this.moveBall; } private function moveBall():Void { var x = _x; var y = _y; x += xdir; y += ydir; if ((x<0 and xdir<0) or (x>292 and xdir>0)) { xdir *= -1; x = (x<0) ? 0 : 292; } else if ((y<0 and ydir<0) or (y>292 and ydir>0)) { ydir *= -1; y = (y<0) ? 0 : 292; } _x = x; _y = y; } } |
完成后可以测试影片(记得以Flash 6/7 ActionScript 2.0发布).
特点分析:
ActionScript 1.0的类,如果没有名称领域,都是在_root建立 ,ActionScript 2.0的类,则在_global建立,而且自行处理好名称领域问题.
从以上各例子一步步的演变,可以看到无论面向对象程序设计语法是如何改变,最核心控制粒子随机移动的程序都是大同小异的,而且面向对象程序设计概念是不变的.因此Flash MX面向对象程序设计新手要从全域函数到程序设计ActionScript 2.0是没有障碍的,学了面向对象程序设计概念,学了ActionScript 2.0方法,就应该踏出尝试第一步.
- 上一篇: FLASH实用技巧之太阳系制造
- 下一篇: Flash制作的一个3D类效果
-= 资 源 教 程 =-
文 章 搜 索