本篇通过一个实例,围绕着attachMovie这个复制语句,详细讲解了如何给批量复制的MC赋给不同的动作……
本篇要讲的是关于给批量复制的MC赋给不同的动作的教程。
效果预览:
可以看到这是一个简单的打字作品,为了突出我讲的重点,这里对作品本身就没有加修饰了.按钮是共享库中的现成,改成了MC.场景里只有一具动态文本框. 本来文本框也可以用AS建,但是我担心那样就把本篇的主题掩盖了.
在结合源文件讲解前,我的对于本篇的中心作一下说明.
由于现在用FLASH进行动画创作的人是越来越多,作品的规模也是越来越大,因此很多时候会用到复制影片剪辑的语句.通常是用attachMovie来复制库中的语句,使得场景本身不显得太乱.而我们要说的“给批量复制的MC加不同的动作”其实也是围绕着attachMovie这个复制语句来讲的.
有些时候,我们的确需要给很多MC加上动作,于是在大的工作量下面就产生了这样一个问题,能不能用AS编写出一种能够简化工作量的代码,使得给很多MC加上动作时不必那么费事(的确,如果MC有几十个,每一个都加上不同的动作,不累死也烦死的).
关于问题的答案是不确定的.关键在于你要加的动作和MC之间有没有某种规律性地联系.如果你要给完全不同的MC(也就是说不是用attachMovie复制出来的MC,而是你自己一个一个做出来的形态各异的MC)加上完全不同的代码,那么我只能说:“无能为力“.我们之所以有理由去让AS完成给不同的MC加上不同的动作,是因为这些MC和这些动作之间有某些相同或相似之处,我们自己处理不同的地方,而把相同的部分留给了代码.
那么,“相似“二字如何理解呢?或者说,什么样的MC和什么样的AS才叫做相似呢?
这里我要举的例子就是循环语句.利用循环语句我们知道可能批量地完成某一工作,比如说给一个数组的每个元素赋予不同的值. 我们自然而然地想到循环. 那么进一步问:为什么要用循环? 原因有两个:
1、数组元素的变量有相似性,可以用下标来逐个表示。
2、赋予的值有规律性,比如是一个以i值变化的数列等等。
这样我们才能够把代码简化,而这种简化前提就是数组元素和赋值的“相似“.
说了这么多,无非就是一个意思:如果MC(我们类比的数组元素)之间有规律性,相应的动作代码也有规律性(我们类比赋予的值),那么我们就可能简化我们的工作量.
幸运的是,大多数要用到attachMovie复制MC的时候,我们需要的“不同的代码“之间也是相似的.
等等,为什么我们一再强调用attachMovie呢?
因为我们要批量出现的MC就是靠它来完成. 那么如果我的MC相差很大,而代码相似,怎么办?
呆会儿你会看到,其实MC的相似与否不是MC本身决定的,而是由它的标识符,也就是MC的名称决定的,因为我们是用MC的名称来完成对MC的引用的,所以关于这一点您不用担心,而且我也相信在看完本篇后你会有办法举一反三的. 现在回到attachMovie中来.我们之所以考虑这个语句,是因为我们经常用如下语句来批量复制MC:
for(i=1;i<=50;i++{ attachMovie("mcName",mcName"+i,i); }
当然,这里我省略了对坐标的定义,出来的MC全部是在左上角的(0,0),看上去50个就像是一个.
看出来了吧,复制出的50个MC的唯一差别只在于i的值,这就是规律,这就是相似. 如果我们的动作代码本身也有着对i的函数关系的话,毫无疑问,我们可以定义不同的代码了.
明白了吗?一切的一切关键就在于i的有规律的取值,使得复制出来的MC的标识符(名称)与代码之间都有着对i的函数关系,那么我们就可以用AS来简化我们的工作了!就算MC不同,只要它们之间的名称与i有函数关系,代码也与i有函数关系,那就没问题.
那么如何得到这个序列号(i值)呢?下面还是结合我给的例子来详细说明一下我们的做法.
例子中当你敲击键盘时,场景中的相应的按键就按下,动态框里出来相应的字母.而实际上我只用了一个MC,不多的代码就完成了.唯一美中不足的是键盘没有像现实中那样排列.因为我实在找不出排列与i值的关系.
好了,可以看到,代码一共分为三部分,第一部分是对一个MovieClip类的子类的定义.
function keyMc(){ } keyMc.prototype = new MovieClip(); keyMc.prototype.onLoad = function(){ this.label = String.fromCharCode(96+parseInt(String(this).substr(10))); };
千万别头晕,如果您懂得一点儿对象的概念,我想是不难理解的.
首先我们定义了一个类:
function keyMc(){}
您不必奇怪为什么会这样写,只要知道这种写法是对的就行了.就相当于java中的class keyMc{}一样.一个定义而已.然后把这个类定义为 MovieClip类的一个子类:
keyMc.prototype = new MovieClip();
这里需要说明一下,我们建立的所有的MC都是MovieClip类的一个子类. 这是AS里面的语法,prototype是原型的意思,这样就表示MovieClip是keyMC的原型(父类),当然我们的目的是让keyMc类继承MovieClip中的方法:
keyMc.prototype.onLoad = function(){ this.label = String.fromCharCode(96+parseInt(String(this).substr(10))); }
先别管{}里面的内容.我们看到了熟悉的onLoad方法.还有一个不太熟悉的prototype.
上面已经说过,prototype表示“原型“,而keyMc类又是继承了MovieClip类,所以自然有onLoad方法.因此该句意思是把onLoad方法加入到期keyMc的原型中,简单地说就是所有的从keyMc类实例化的对象都有了这个onLoad方法.
而我们可以看到,这个方法里面的代码:
this.label = String.fromCharCode(96+parseInt(String(this).substr(10)));
什么意思呢?看起来是对对象里的label属性赋值.赋的什么值呢?括号是有点多,不过我们发现最外边的是String.fromCharCode(),它的意思是把里面的数字转为对应的ASCII字符.那么是什么样的数字呢?
我们可以看到数字是96加上某一个数,这个数是这样表示的arseInt(String(this).substr(10)).外括号是一个parseInt()函数,它的作品是把()里面的字符串转为数字.这个字符串是tring(this).substr(10),this指代的是对象本身,String(this)表示把对象本身的名称转为字符串. 那后面的substr(10)是什么意思呢? substr是String对象的一个方法,表示取从字符串的第10个字符开始,取出到字符串结束的子字符串.
好了,看起来我们基本理解了代码的意思:把对象名称的第10个字符及以后的字符取出(很可能是数字,因为我们用到了parseInt来转换),并加上96,再把与此数字对应的ASCII字符赋给该对象里的label属性.
等等,说了半天,好像与要讲的不太相干呀?您别急.
现在我们到源文件第一帧的代码里找到了这样的一条语句:
Object.registerClass("mc", keyMc);
并注意到在库里面我已经把按键的MC的链接名称写成了mc,keyMc是我们刚刚定义的类. 好象有些眉目了. 事实上这句代码是把mc与keyMc关联起来了,您不用知道为什么是Object.registerClass(),您只需要知道这样做就能把自定义的类与一个在库中的MC关联起来就行了,会照搬就行了.
那么,关联的什么东西呢?是不是onLoad方法?
答对了!就是onLoad方法!
联想到我们说过用attachMovie来批量复制,以及onLoad方法中的String(this).substr(10),好像有点儿联系了!
的确如此,再下面我们会看到这样的代码:
for(i=1;i<=26;i++) { attachMovie("mc", "mc"+i, i) with(evel("mc"+i)) { _x = ((i-1)%9)*50+100; _y = Math.floor((i-1)/9)*60+300; } }
至于with语句,您可以看到只是对坐标的赋值,这里我们不管.我们要注意的是attachMovie("mc", "mc"+i, i), 显示,复制出来的MC的名称就是"mc"+i. 再联想到substr(10)是从对象名称的第十个字符起取出,是不是正好取到了i的值呢? 但是为什么是10,而不是三阶段呢?i的值明明是第三位呀!
您的猜想完全正确! 而之所以我们取10的原因是String(this)返回的是当前对象的完整名称,在这里也就是:_level0.mc1项(我们用mc13来代表复制出来的MC),您看,到1正好是十个字符,因此String(this).substr(10)取出的值是13!也就是i的值!
我们已经说过,通过Object.registerClass("mc", keyMc);语句使得所有从mc复制出来的MC都有了keyMc定义的onLoad方法.而现在我们通过对对象本身的名称的筛选找到了不同!
明白了这一点,剩下的就好解释了.我们注意到97对应的ASCII字符是小写的"a",而i值是从1开始循环的,那么代码的意思就是:找到复制的MC的序列号(也就是i值),并从a开始,把"mc"中的label赋给对应的字母!而label您可以在"mc"里面看到,是一个动态的文本框.因此我们才可能看到复制出来的按键上的字母是从a~z的! 而用onLoad方法是让代码在初始时就被执行.
我们终于找到了关键点所在了,就是通过命名的有序性,找到这个序列号(i值),利用它来使代码互异而有序.
接下来代码就更容易理解了,我们已经把关键问题解决了.
可以看到剩下的一段代码是对按键监听器的定义:
keyLis = new Object(); keyLis.onKeyDown = function() { eval("mc"+(Key.getAscii()-96)).gotoAndStop(3); labelText+=eval("mc"+(Key.getAscii()-96)).label; }; keyLis.onKeyUp = function() { eval("mc"+(Key.getAscii()-96)).gotoAndStop(1); }; Key.addListener(keyLis); Object.registerClass("mc", keyMc); for (i=1; i<=26; i++) { attachMovie("mc", "mc"+i, i); with (eval("mc"+i)) { _x = ((i-1)%9)*50+100; _y = Math.floor((i-1)/9)*60+300; } }
这里我们声明了一个新的Object对象keyLis,并对它定义了onKeyDown和onKeyUp方法.也就是监听器.eval("mc"+(Key.getAscii()-96))表示对所按键对应的MC的引用.Key.getAscii()表示所按键对应的ASCII值,减去96,正好是对应的i值的一个序列号,用eval计算得到的就是对应的MC.我们让该MC跳到第三帧,也就是按下的状态. 并在某些方面labelText里面留下对应的字符.labelText是主场景里的一个动态框.onKeyUp是让该MC跳回到第一帧,也就是普通状态.
Key.addListener(keyLis)是把这个对象注册给Key对象,使得它可以监听对键盘的响应.
回顾一下全部的代码,我们无非是做了这样几件事:
1 自定义一个对象,并自定义onLoad方法(您也可以添加同样的方法,如onEnterFrame),把这个对象与库里的MC链接,使得所有从中复制的MC都拥有该方法.
2 方法中有对MC序列的提取,并依靠这个序列号给MC定义相似的方法.
3 注册一个键盘监听器,使之接受键盘事件,并对相应的MC做出反应.
4 复制名称相似的MC.
我们一再强调,完全不同的方法定义是不可能的(除非您真的不怕麻烦,而宁愿用一堆if...else...语句来判断MC的名称),我们的关键就是找到复制出来的MC对应的序列号:String(this).substr(10).
注意,这里我们用10而不是其它,是因为我们把MC命名为诸如mc13之类,如果是abc13,您可得改成11.
也许您对自定义对象并把它注册给一个库中的对象有些不解,或者是对监听器有些疑问,请查看FLASH帮助文档并结合源文件.