从时间轴到外部的独立.as文件-按照软件工程的规范构建Flash程序

这个文章的立意是在于写一些“纲要”,这个纲要是用于指导那些——已经习惯于将AS代码放在Movieclip的帧上面,同时想要转向用更符合软件工程规范的写法来写Flash程序——即是将代码都放在外部的as文件内——的Flash程序员。本文只从表象上入手,介绍一些经验性的东西,暂时不探讨FlashPlayer的执行原理。


当然,乍一看,会觉得后一种的书写方式带来一些不自在,因为代码与元件的关系显得不是那么紧密与直观,可是它带来非常多工程学上的好处,比如利于扩展,易于维护等等。而且这个做法让Actionscript摆脱了脚本语言的苦命,.fla文件里将只保存视觉素材,与逻辑完全分开,这与在VC里建立C++程序的感觉差不多,嗯,至少看起来也高级一些。。。。


程序代码的整体结构:


如何组织一个程序的代码,这个问题最关健,对于初学者也最扑朔迷离。一般来说Flash程序的入口点都是根MovieClip,视觉上讲,它是所有可视元件的容器,逻辑上讲,它包含着最上一层的逻辑,就是说程序的初始化等等重要逻辑都会放在根Mc上面。传统的做法就是将程序最高一层的控制代码都放在根Mc的某一层上的某些帧上,一般来说我们会在时间轴上单独建立一个action层来放置这些代码。


新的做法,则是:先创建一个Actionscript类文档,扩展名为.as。然后将Fla文件里的文档类属性设定为这个新建的类的类名。至于这个文档类,它必须至少是继承自flash.display.Sprite类,或者如果你需要基于时间轴的动画的话,你就需要继承flash.display.MovieClip。比如:


package yourRootPackageName.subPackageName 
{
	import flash.display.Sprite;
	public class YourClassName extends Sprite
	{
		// properties & methods declarations
		public function YourClassName()
		{
			//constructor
		}
	}
}

我也见过另外一种做法,就是在library里建立一个MovieClip,然后给这个Movieclip建立一个独立的类文件,将最高层的逻辑都放在其中,之后拖拽一个该MC的实例到舞台(stage)上,也就是根MC上。这样做的好处是,你可以直接把这个MC移到另一个项目里。当然,由于Flash里面MC可以无限相互包容,所以你可以在任何一层的MC上放置你的程序入口点,只要你确保把这个MC放进了播放列表(displaylist)就行。


程序的初始化:


传统的做法当然是放在第一帧,因为它会被最先执行,而事实上这是因为在这种做法里我们对于一个MC的生命周期的控制有限。与旧的写法不同,在新的写法里,对于如何放置程序初始化逻辑,你将有更多的选择:


根MC的构造函数:


一个MC既然是一个实例,那么它被创建时当然是构造函数先被创建,所以根MC的构造函数是你可以放置初始化代码的第一个选择。


根MC的ADD_TO_STAGE事件侦听器:


但是也有一伙人更钟意把初始化代码放在根MC被加进stage之后,任何MC在被通过addChild()函数放进播放列表(displaylist)之后,都会释放一个ADD_TO_STAGE事件,你可以给这个事件加一个侦听器,在事件发生后处理一些事情,因为根MC是会被FlashPlayer自动加进stage的,所以有些人喜欢在根MC上注册一个ADD_TO_STAGE事件的侦听器,然后把初始化的逻辑放在那里。


仍然放在第一帧上面:


当然,在新的做法里,你仍然可以把初始化代码放在时间轴的第一帧上面,可是因为直接这样做违反了咱们的初衷,所以Flash里有一个Adobe未公开的方法,叫做:addFrameScript()


addFrameScript(0, frame1);
function frame1(){}

这个函数接收的第一个参数是指frame的索引,但是注意它是从0开始;第二个参数则是一个函数引用。当然Sprite类没法使用这个函数,它没有这个方法。


访问域:


访问子MC:


假设这样的情况:你有一个MC在库里面,这个MC有若干个子MC,它们的实例名字是instanceName1、instanceName2;现在你创建了一个类文档给它,并且在.fla文件里已经关联了两者;在这个类文档内,如果你需要访问子MC的话,你可以这样做:


this.removeChild(this["instanceName2"]);


或者:


this.removeChild(instanceName1);

即是说直接通过子MC的实例名,而其实这写法等于简化版的:


this.removeChild(this.instanceName1);


由此类推,假如instanceName1又有子MC叫做instanceNameDec,你可以这样访问它:

this.removeChild(this.instanceName1.instanceNameDec);


访问stage:


在Actionscript里,虽然我们常打交道的东西都是可见的,即是flash.display.DisplayObject的子类,可是也并非你在程序里构建的所有的类都一定得是可视的类,DisplayObject拥有一个属性:stage,实际上它是对于舞台对象的引用,当一个DisplayObject实例被放进displaylist之后,这个属性就会指向当前舞台,当被移走之后,这个属性会被设置为null,这些动作是由FlashPlayer来完成的。


讨论这个问题的意义在于,有些时候你可能会创建一些辅助类,它们或许是继承自Object,或者完全是独立的类,总之是非DisplayObject,所以它们不会有stage属性,因此,你或许需要明确传递stage的引用给这些类的方法来完成你想做的事,比如说侦听一些全局的鼠标或者键盘事件。


引用资源:


当你需要的只是能够在你的as类里使用一个静态的位图元素时,你可以创建一个MC作为这个图片的“壳”,然后为这个MC创建一个as类,但是类的实体是空的就可以了,因为实际上你只需要一个名称就可以了。


实际上,对于不需要时间轴动画的视觉系类,你直接继承Sprite就足够了(比如像上面那段刚刚讲的情况);不需要使用MovieClip,因为后者继承自前者,它拥有更多的属性和方法,这需要分配多余的内存来放置你根本不会用到的数据。


package yourRootPackageName.subPackageName 
{
	import flash.display.Sprite;
	public class YourGraphicName extends Sprite
	{
		// nothing is needed here
	}
}

当然,有些人喜欢明确地再写一个直接返回的构造函数,实际上就算你不写,编译器也会自动帮你填上的:


package yourRootPackageName.subPackageName 
{
	import flash.display.Sprite;
	public class YourGraphicName extends Sprite
	{
		public function YourGraphicName()
		{
			return;
		}
	}
}

动态类:


Actionscript的一个思维就叫做“later binding”,大致意思是说对象的属性和方法都可以在运行时动态决定,如果你希望你创建的自定义类的实例也有这种特性,那么你就在类的声明前面再加上个“dynamic”关键字。不过要注意一点,动态类的动态特性是不会通过继承关系传递给下一代的,假如你有个A类是dynamic,你用B继承自A,可以你没给B声明成dynamic,那么B就不会是dynamic的。。。。。(有点绕啊)


大致写法是:


package yourRootPackageName.subPackageName 
{
	import flash.display.Sprite;
	dynamic public class YourGraphicName extends Sprite
	{
		// nothing is needed here
	}
}

有一些需要注意,就是动态类的set和get方法只可以用来访问public属性。换句话说,如果已经是动态类了,你就别给它用什么set和get方法了,根本没用。




References:


http://flexblog.faratasystems.com/2006/10/02/actionscript-3-dynamic-classes


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值