Flash 的媒体组织方式 [作者:LeeFJ]
[ 2004-10-31 23:48:10 | 发布: N神 ]
一、资源管理
库(Library)是Flash文档的资源管理器,所有可被Flash利用的资源都可以放在库中,并接受库的管理。在使用Flash进行创作设计或软件开发之前,首先要将媒体内容添加至Flash文档,当然也可以在 Flash 中直接创建矢量图或文本。或者从外部导入矢量图、位图、视频和声音;可以创建元件,即可重用的媒体内容。在运行时,也可以使用脚本动态地将媒体内容添加至文档。
对于已经导入的媒体资源,Flash使用库(Library)对它们进行管理。从另外一个角度来说,库是用来存储已经导入的文件,并把它们作为可被重复利用的资源。从外部导入的文件和在Flash中直接绘制的图形是进行创作的基础。利用元件可以使用嵌套(nesting)的方式进一步组织这些媒体,使之成为独立但可重复利用的模块。元件包括:图形(Graphic)、按钮(Button)和电影剪辑(MovieClip)。库还可以包含添加到文档的组件(Component),组件作为编译好的剪辑显示在库中。不同的Flash文档间还可以进行库项目的交流,一个Flash文档可以打开另一个Flash文档的库,从中获取当前文档所需要的库项目,以实现资源的共享。库可以作为资源永久保存,Flash启动时被自动加载,Flash还提供了若干个范例库以供用户使用。
同时,库资源可以作为 SWF 文件导出到一个 URL,从而创建运行时共享库。这里需要涉及到两个概念:资源文档和目标文档。所谓目标文档是指当前正在编辑,需要利用共享库中的资源的文档,而资源文档是指已经被导出到某个URL的swf文件,用于存储库资源,供目标文档使用。这里的URL必须符合Flash Player 7安全沙箱的要求,简单地说,目标文档和资源文档在发布后必须位于同一个域名或指定域名下,然而这一点在本地调试时确实不受限制的。在本地运行的Swf或Exe文件也不受这个安全机制限制,可以直接使用运行时共享库中的资源。运行时共享库对于RIA开发非常有用,使库项目的开发和软件整体整合开发分离,并且共享资源库可以被多个目标文档所使用,提高了库项目资源的可复用性。
库还可以对库项目进行管理,创建文件夹对库项目进行分类,修改库项目的属性。被导入的资源可以在库中直接调用其它编辑程序进行编辑,编辑完成后Flash可以直接更新库中原来的项目。可以直接选中未使用的库项目,这样开发者便可以删除一些无用的库项目,精简库资源,使Flash文档更小。这里需要注意的是,一般情况下,未使用的库项目并不包含在发布后的Swf文档中,只有当库项目被导出为运行时共享库时,未使用的库项目才同时被导出到Swf文档中。
二、时间轴上对象的组织
对象在Flash中被称为实例(Instance),而库中的库项目通常被成为符号(Symbol),类似于通常面向对象编程中的类。所谓“时间轴上对象的组织”也即时间轴上实例的组织。
时间轴被分为很多的小格,连续的时间被离散化,每一小格对应了一个状态——Flash执行的状态,小格被称为:帧(Frame)。帧包括两种,关键帧(Key Frame)和普通帧(Frame)。在关键帧中可以放置内容,而普通帧则不允许放置内容,并且由Flash根据关键帧的内容自动生成。不同时间轴之间是相互独立的,它们的播放是互不影响的。这里需要指出的是,单帧的时间轴与多帧时间轴的区别,单帧的时间轴并不循环播放,而多帧的时间轴在没有脚本语句控制的情况下会连续循环地播放。
时间轴与时间轴之间的组织是一种树形结构,它们始终以一种嵌套(nesting)的方式进行组织。父时间轴包含了子时间轴,并可以相互引用和控制。主时间轴(_root)是这个树形结构的根节点。在任意节点下的子节点集合并非一直保持原有的状态,随着时间轴上播放头的推进,其子节点集合也在发生着变化,所以这棵树在时间上是一棵动态树。
正是由于这样一种组织方式,每一个对象都有一个路径指明对象在这棵树中的位置,以便脚本引用。路径包括绝对路径和相对路径。绝对路径从主时间轴开始;而相对路径由当前位置开始,例如MC._parent指MC的父时间轴。
对象的生存期和作用域在时间轴上被定义。首先,对象在关键帧中被创建,并在其后的普通帧中一直存在(电影剪辑、组件等对象还可以被脚本引用),直到遇到一个关键帧,对象被移除或被重新创建。如果前后两个关键帧中对象被赋的引用名不同,对象将被重新创建和初始化。多帧循环的时间轴在进行循环播放时,从最后一帧跳到第一帧时时间轴将被刷新,这与使用脚本语句进行播放控制的效果是一样的。时间轴被刷新后,时间轴上的所有对象将被清除,并重新创建。在后面将对时间轴刷新进行详细讨论。
事实上,Flash中对象的组织并不仅仅只是在时间轴的组织,深度(Depth)组织方式与时间轴组织一样重要。所以在单个的时间轴上,Flash的对象组织方式是二唯的,即时间轴方向和深度方向。
在大多数的可视化编程中,需要对屏幕上的对象进行组织。这种组织意味着各个可视对象在屏幕上的位置以及它们互相层叠的方式。在Flash中可视化屏幕对象可以是电影剪辑(MovieClip)、按钮(Button)、文本框(TextField)和组件(Component)。当使用Actionscript进行编程时可以使用一定的方式来控制他们的层叠方式,当然,在Flash的编辑状态下也可以使用菜单命令对屏幕对象的层叠方式进行调节。
在Flash 的编辑环境下,对象的组织方式是不严格的,使用Flash 脚本可以实现与编辑状态下一样的控制,它可以在程序中直接给出屏幕对象的组织方式。但是在脚本中,用户仅可以控制电影剪辑、按钮、非静态的文本对象以及组件,因为只有他们才是屏幕元素,可以被指定一个引用名,以便在Actionscrip中实现对他们的操作和控制,而其它的那些可视对象,例如静态文本、色块、线条始终位于编辑时的原始位置。值得指出的是,组件(Component)事实上是被编译后的电影剪辑,其行为特性与电影剪辑是类似的。
前面提到过,Flash的时间轴组织是一棵在时间轴方向上动态的树,并且主时间轴(_root)是这棵树个根节点。需要注意的是,这里所说的深度(Depth)并非树的深度。深度是对不同时间轴层次的描述,它表现在两个方面:对象在屏幕的显示层次(Z-Order)和对象的加载顺序(Load-Order)。另外时间轴在其父时间轴上有一定的生存期。因为时间轴往往包含在具体的对象中,所以其生存期的概念与对象生存期的概念是一致的。
三、深度(Depth)
深度(Depth)仅仅需要一个数字描述,Flash Player 使用这个数字来指定对象的层叠位置。所谓层叠是指一种显示时的的遮盖关系。深度值较大则显示较前,深度值较小则显示较后,较后的要被较前的遮盖。深度具有可比性但仅限于兄弟节点,所以同一父节点下的兄弟具有不同的深度,同时这个深度也描述了他们之间的层叠关系。属于不同父节点的子节点可以有相同的深度,但他们不具有可比性。
编辑环境下,Flash使用了图层(Layer) 来组织对象。这时, Flash 并没有给对象指定一个深度,只有当Flash 文档在运行时 Flash Player根据用户最初在编辑环境下的拖放情况来指定对象的深度。这里的图层可以认为是同一父时间轴节点下子时间轴节点的集合。图层和图层之间不存在交集,而且图层是一个动态的集合,随着程序的运行,集合中的元素也会发生变化。Flash 也可以在运行时动态地创建时间轴,例如使用 attachMovie()、duplicateMovieClip()等语句,但必需以参数的形式给出要被创建的时间轴的深度。
对象在编辑环境下的拖放顺序以及时间轴上图层的层叠关系,用来帮助Flash 确定对象的深度。图层在Actionscript中是不被引用的,所以在swf文件中也不会有图层这个概念。在编译时,图层被分解为多个对象(多个时间轴),并且每一个对象都会被指定一个深度。当Flash 播放时,时间轴会读取图层中的内容,并根据和其他对象的相对位置关系指定它的深度。如果对象所在的图层较高则获得一个比较高的深度,如果对象所在的图层较底则获取一个较低的深度。与此同时,Flash也会为对象指定一个名称,实现脚本对该对象的引用。深度概念也影响Flash 中对象的创建,在FileàPublish SettingàLoad Order 中可以设置对象被创建的顺序,指定是由低深度到高深度(Bottom up)地创建,还是由高深度到低深度(Top down)地创建,Flash中的默认为前者。
Actionscript 还提供了一些与深度相关的方法和管理对象:
深度方法和功能描述
这里需要加以说明的是,SwapDepth()方法可以把在不同深度的两个对象进行深度交换。如果要实现这种交换有两种方法:一是把两个对象进行调换,即把上面的拿到下面,把下面的拿到上面,这是对对象本身进行操作;二是直接更改对象的深度属性,即直接修改指定对象深度的数值。但是如果使用后者显然不是在交换深度而是在设置深度了。SwapDepth()方法是实现对象深度位置的交换而非设置深度。可以把深度理解为一个容器,比如说是房子,如果两个人要交换房子,那么必须是你搬过来我搬过去,而仅仅更换门牌是没有什么用处的。所以深度是只读的。另外,getDepth()方法可以很方便的获取MovieClip、Button和TextField对象的深度数据。
另外,深度管理器(DepthManager)是一个专门对深度进行管理的Flash V2组件,它封装了若干深度管理的方法:
DepthManager.createChildAtDepth():在指定深度处创建指定元件的子级。
DepthManager.createClassChildAtDepth():在该指定深度处创建指定类的对象。
DepthManager.createClassObjectAtDepth():在指定深度处创建指定类的实例。
DepthManager.createObjectAtDepth():在指定深度处创建一个对象。
DepthManager.setDepthAbove():移动实例到指定实例的深度之上。
DepthManager.setDepthBelow():移动实例到指定实例的深度之下。
DepthManager.setDepthTo():将实例移动到指深度。
四、深度区域:
在为对象指定深度时必须清楚地了解Flash在深度上的三个区域。在Flash 中,深度的范围在-16384到2130690045之间,任何Flash的可视对象都不会超出这个范围。在播放时,Flash把时间轴中的对象按照默认的设置进行加载。-16384到-1是深度的第一个范围,在这个深度区域对象不可以使用脚本创建和移除,用于放置用户在编辑环境下创建的对象,这里把它称为时间轴区(Timeline)。接下来是0到1048575的深度范围,在这个深度范围内,对象可以使用脚本创建和移除,所以称为动态区(Dynamic)。之后一个区域称为保留区(Reserve),深度范围在1048576和2130690045之间,可以放置MC但是不可以移除。
Flash的深度区域:
Flash 在动态区之前提供了时间轴区,用于放置编辑环境下时间轴中的对象。在编辑环境下,最底层的对象放置到区域的最深处——-16384。在通常情况下会从-16383这个深度开始,Flash依次向较高深度放置时间轴中的对象。
接下来是动态区,在这个区域可以放置那些可以动态创建和移除的对象。而且这个区域也符合一般人的使用习惯,因为它的深度是从0开始的,而开发者在创建对象时通常也会考虑这个范围。在这个范围可以获得比较大的自由权,开发者可以使用脚本动态地创建和移除对象。如果对象不在动态区,那么首先可以把对象交换到动态区,然后再进行移除。
保留区可以理解为动态区的一个扩展,只是在保留区中无法使用脚本移除对象,对象在那个区域可以动态地被创建。在这个区域对象也可以使用swapDepth()方法交换到其它的深度区域。但保留区还是一个比较特殊的区域,因为那里的对象不可以被移除,而且深度高的有点离谱。在保留区Flash为对象提供了一定的存储空间。
需要特别注意的是,Flash 在使用createEmptyMovieClip()方法创建的空MC时,深度的分配上几乎没有什么限制,深度可以指定在-999999999999以下或是999999999999以上。虽然这个深度已经超出了刚才讨论的那个范围。
五、时间轴刷新:
关于深度,可能会遇到一些另人混淆的问题,特别是动态区和时间轴区。当时间轴被刷新时,所有的对象将被重新创建。Flash 会扫描位于该时间轴的时间轴区域,并清除保存在这些深度上的对象。然后Flash 读取时间轴上的数据并重新创建这些对象,但是通过动态方法创建的对象将被忽略。其中一个例子就是使用gotoAndPlay()返回播放已经播放过的帧,例如从第10帧返回到底5帧播放,这时Flash为了重新展示第5帧的内容必须刷新时间轴并完全重构第5帧的内容。但是使用动态方法创建的对象如果在时间轴刷新时被移除,那么这时并不被自动创建,除非程序给出。
很明显,这样可能会引起一些问题。首先,这样会失去在时间轴区域或是使用动态方法已经创建并交换到时间轴区域的对象。也就是在这中情况,不可以把使用动态方法创建的对象交换到时间轴区域,否则在时间轴刷新时会丢失这些对象。在开发时为避免这种情况的发生,可以创建一个单帧停止的MC,这样的MC可以是安全的,可以不必为时间轴刷新而担忧。
另外一个问题是无法移除所需要移除的对象。其原因是由于使用深度交换方法把时间轴区的对象转移到了非时间轴区,这样在时间轴刷新时就无法清除该对象了,而且这次刷新还会创建一个新的该对象到时间轴区。这种情况也应该避免发生。
还有一个需要清楚的问题是场景(Scene)跳转的问题。场景间的跳转不会引起时间轴的刷新,也不会触发其他一些特殊的事件。作为场景本身而言,它们是主时间轴的片段,当Flash被发布以后,这些场景便会整合到一起,变成单个的主时间轴。所以用户在一个场景创建的对象,它仍旧可以在接下来的场景出现,当然也可以使用脚本使那些对象消失。
六、播放器执行顺序:
在深度问题上,还有一点比较容易被人们忽视。正如前面所提到的,深度也会影响到脚本的执行顺序。事实上深度本身并不影响脚本的执行顺序,但是深度却与对象的创建顺序有关。一般我们都会认为,在同一时间轴上,首先被创建的对象会首先执行它所包含的脚本。另人感到奇怪的是,在默认的发布设置下,那些最晚被创建的对象反而首先执行了EnterFrame事件中的脚本。在默认情况下对象从最底层开始被创建,这一点我们可以在Flash的发布选项中设置。帧脚本是按照它们被创建的顺序执行的。这样如果在bottom up 模式下,从技术角度而言,较低层的脚本反而较早执行,但是值得一提的是,EnterFrame事件中的脚本刚刚与之相反。
看来很有必要追究一下EnterFrame事件到底是怎样的一个事件。EnterFrame事件随着电影剪辑的帧速被持续地触发。可以认为EnterFrame事件是在播放头进入某一帧时触发的一个事件,但是在EnterFrame事件中的代码将先与帧脚本执行。但是,对象的创建和Flash的播放(对象状态的改变过程)到底是怎样一个关系呢?在Flash中第一帧的帧脚本和其它帧的帧脚本有着不同的行为。当运行一个Swf文件时,它的第一帧将首先被创建,然后开始载入该文档中的对象并拖入到舞台,这个过程可以认为是一个初始化的过程。所以在这个过程中随着对象的载入第一帧的容量将不断增大。这样做的原因也是显而易见的,只有当对象全部载入后,脚本才能执行,设想如果脚本所要操作的对象都不存在,那么脚本必然会发生错误。一旦所有的对象载入完毕,除第一帧外的其它帧都将被一次性创建,并开始播放。这样做的另外一个原因是,如果按照先创建,先播放的原则,那么必然导致不同电影剪辑播放时步调的不一致。因为创建对象是需要时间的,特别是在网络上,它还要有一个下载的过程。这里还要注意的是#initclip和#endinitclip中的代码块,它们通常定义在电影剪辑的第一帧,只要符号被定义且被编译(电影剪辑符号定义了,但不一定都被编译),那么就执行该代码段,它用于电影剪辑的初始化,所以优先于其它脚本执行,并且仅执行一次,它的运行效果将作用到该剪辑的所有实例。
这样,就可以得出,Flash的执行可以分成两个过程。首先是对象的下载、创建和初始化,接下来是一个播放的过程。播放是一个对象状态随着帧速改变的过程,其状态的两个极端是存在与不存在。这样在Flash的执行过程中,电影剪辑第一帧的脚本将首先被执行;然后是播放过程,其脚本执行的原则是EnterFrane事件脚本的执行先于帧脚本的执行。
七、图层(Layer)、层级(level)和深度(depth)
通常人们会把图层和层级混淆起来使用,但事实上它们是两个完全不同的概念。时间轴可以以两种方式独立于主时间轴:电影剪辑(Movie Clip)和层级(Level)。这里所谓的独立是指独立的播放与停止。图层(Layer),只在编辑环境下被看到,用于存放和组织在时间轴上的对象。它们仅仅只是在编辑环境下出现,当发布一个Flash文件时,这些图层将被压缩到同一个时间轴上。
层级(Level)位于一个独立的时间轴上,用于存储使用loadmovie方法加载的外部Swf文件。层级(Level)可以使用_level0, _level1, _level3, _leveln 对其进行引用。层级越高,就越接近观察者,也就越容易被看到,这一点与深度是一致的。使用该方法加载的电影将贯穿电影的主时间轴。由于这个原因从外部加载电影的目的常常是为了加载某些声音,因为声音不会影响到原来电影的播放。
电影剪辑(Movie Clip)同样是一个独立的时间轴,但是电影剪辑位于库(Library)中,并不是位于电影的外部。所以它与层级不同,如果需要的话,你可以在帧上创建一个电影剪辑的实例。 从库中拖动一个电影剪辑到舞台(Stage),那么就创建了该电影剪辑的一个实例,可以指定一个唯一的名称对其进行引用。电影剪辑可以包含其它的电影剪辑,这就是通常所说的嵌套(nesting)。
深度(Depth)通常会用于swapDepth()和attachMovie()这些方法,用于指定电影剪辑的层叠顺序。它可以被认为可视对象在时间轴上的层叠顺序(Z-Order)。
这里还要指出的是 _root 和 _level0 的区别。_root 和_level0引用的并非同一个对象,它们是有差别的。_root 指代电影的主时间轴,如果一个电影有多个层级那么_root指代当前脚本正在执行的那个层级。例如:在层级n中的某个脚本包含了 _root,这时_root返回 _leveln,_root和_leveln才是等同的。
库(Library)是Flash文档的资源管理器,所有可被Flash利用的资源都可以放在库中,并接受库的管理。在使用Flash进行创作设计或软件开发之前,首先要将媒体内容添加至Flash文档,当然也可以在 Flash 中直接创建矢量图或文本。或者从外部导入矢量图、位图、视频和声音;可以创建元件,即可重用的媒体内容。在运行时,也可以使用脚本动态地将媒体内容添加至文档。
对于已经导入的媒体资源,Flash使用库(Library)对它们进行管理。从另外一个角度来说,库是用来存储已经导入的文件,并把它们作为可被重复利用的资源。从外部导入的文件和在Flash中直接绘制的图形是进行创作的基础。利用元件可以使用嵌套(nesting)的方式进一步组织这些媒体,使之成为独立但可重复利用的模块。元件包括:图形(Graphic)、按钮(Button)和电影剪辑(MovieClip)。库还可以包含添加到文档的组件(Component),组件作为编译好的剪辑显示在库中。不同的Flash文档间还可以进行库项目的交流,一个Flash文档可以打开另一个Flash文档的库,从中获取当前文档所需要的库项目,以实现资源的共享。库可以作为资源永久保存,Flash启动时被自动加载,Flash还提供了若干个范例库以供用户使用。
同时,库资源可以作为 SWF 文件导出到一个 URL,从而创建运行时共享库。这里需要涉及到两个概念:资源文档和目标文档。所谓目标文档是指当前正在编辑,需要利用共享库中的资源的文档,而资源文档是指已经被导出到某个URL的swf文件,用于存储库资源,供目标文档使用。这里的URL必须符合Flash Player 7安全沙箱的要求,简单地说,目标文档和资源文档在发布后必须位于同一个域名或指定域名下,然而这一点在本地调试时确实不受限制的。在本地运行的Swf或Exe文件也不受这个安全机制限制,可以直接使用运行时共享库中的资源。运行时共享库对于RIA开发非常有用,使库项目的开发和软件整体整合开发分离,并且共享资源库可以被多个目标文档所使用,提高了库项目资源的可复用性。
库还可以对库项目进行管理,创建文件夹对库项目进行分类,修改库项目的属性。被导入的资源可以在库中直接调用其它编辑程序进行编辑,编辑完成后Flash可以直接更新库中原来的项目。可以直接选中未使用的库项目,这样开发者便可以删除一些无用的库项目,精简库资源,使Flash文档更小。这里需要注意的是,一般情况下,未使用的库项目并不包含在发布后的Swf文档中,只有当库项目被导出为运行时共享库时,未使用的库项目才同时被导出到Swf文档中。
二、时间轴上对象的组织
对象在Flash中被称为实例(Instance),而库中的库项目通常被成为符号(Symbol),类似于通常面向对象编程中的类。所谓“时间轴上对象的组织”也即时间轴上实例的组织。
时间轴被分为很多的小格,连续的时间被离散化,每一小格对应了一个状态——Flash执行的状态,小格被称为:帧(Frame)。帧包括两种,关键帧(Key Frame)和普通帧(Frame)。在关键帧中可以放置内容,而普通帧则不允许放置内容,并且由Flash根据关键帧的内容自动生成。不同时间轴之间是相互独立的,它们的播放是互不影响的。这里需要指出的是,单帧的时间轴与多帧时间轴的区别,单帧的时间轴并不循环播放,而多帧的时间轴在没有脚本语句控制的情况下会连续循环地播放。
时间轴与时间轴之间的组织是一种树形结构,它们始终以一种嵌套(nesting)的方式进行组织。父时间轴包含了子时间轴,并可以相互引用和控制。主时间轴(_root)是这个树形结构的根节点。在任意节点下的子节点集合并非一直保持原有的状态,随着时间轴上播放头的推进,其子节点集合也在发生着变化,所以这棵树在时间上是一棵动态树。
正是由于这样一种组织方式,每一个对象都有一个路径指明对象在这棵树中的位置,以便脚本引用。路径包括绝对路径和相对路径。绝对路径从主时间轴开始;而相对路径由当前位置开始,例如MC._parent指MC的父时间轴。
对象的生存期和作用域在时间轴上被定义。首先,对象在关键帧中被创建,并在其后的普通帧中一直存在(电影剪辑、组件等对象还可以被脚本引用),直到遇到一个关键帧,对象被移除或被重新创建。如果前后两个关键帧中对象被赋的引用名不同,对象将被重新创建和初始化。多帧循环的时间轴在进行循环播放时,从最后一帧跳到第一帧时时间轴将被刷新,这与使用脚本语句进行播放控制的效果是一样的。时间轴被刷新后,时间轴上的所有对象将被清除,并重新创建。在后面将对时间轴刷新进行详细讨论。
事实上,Flash中对象的组织并不仅仅只是在时间轴的组织,深度(Depth)组织方式与时间轴组织一样重要。所以在单个的时间轴上,Flash的对象组织方式是二唯的,即时间轴方向和深度方向。
在大多数的可视化编程中,需要对屏幕上的对象进行组织。这种组织意味着各个可视对象在屏幕上的位置以及它们互相层叠的方式。在Flash中可视化屏幕对象可以是电影剪辑(MovieClip)、按钮(Button)、文本框(TextField)和组件(Component)。当使用Actionscript进行编程时可以使用一定的方式来控制他们的层叠方式,当然,在Flash的编辑状态下也可以使用菜单命令对屏幕对象的层叠方式进行调节。
在Flash 的编辑环境下,对象的组织方式是不严格的,使用Flash 脚本可以实现与编辑状态下一样的控制,它可以在程序中直接给出屏幕对象的组织方式。但是在脚本中,用户仅可以控制电影剪辑、按钮、非静态的文本对象以及组件,因为只有他们才是屏幕元素,可以被指定一个引用名,以便在Actionscrip中实现对他们的操作和控制,而其它的那些可视对象,例如静态文本、色块、线条始终位于编辑时的原始位置。值得指出的是,组件(Component)事实上是被编译后的电影剪辑,其行为特性与电影剪辑是类似的。
前面提到过,Flash的时间轴组织是一棵在时间轴方向上动态的树,并且主时间轴(_root)是这棵树个根节点。需要注意的是,这里所说的深度(Depth)并非树的深度。深度是对不同时间轴层次的描述,它表现在两个方面:对象在屏幕的显示层次(Z-Order)和对象的加载顺序(Load-Order)。另外时间轴在其父时间轴上有一定的生存期。因为时间轴往往包含在具体的对象中,所以其生存期的概念与对象生存期的概念是一致的。
三、深度(Depth)
深度(Depth)仅仅需要一个数字描述,Flash Player 使用这个数字来指定对象的层叠位置。所谓层叠是指一种显示时的的遮盖关系。深度值较大则显示较前,深度值较小则显示较后,较后的要被较前的遮盖。深度具有可比性但仅限于兄弟节点,所以同一父节点下的兄弟具有不同的深度,同时这个深度也描述了他们之间的层叠关系。属于不同父节点的子节点可以有相同的深度,但他们不具有可比性。
编辑环境下,Flash使用了图层(Layer) 来组织对象。这时, Flash 并没有给对象指定一个深度,只有当Flash 文档在运行时 Flash Player根据用户最初在编辑环境下的拖放情况来指定对象的深度。这里的图层可以认为是同一父时间轴节点下子时间轴节点的集合。图层和图层之间不存在交集,而且图层是一个动态的集合,随着程序的运行,集合中的元素也会发生变化。Flash 也可以在运行时动态地创建时间轴,例如使用 attachMovie()、duplicateMovieClip()等语句,但必需以参数的形式给出要被创建的时间轴的深度。
对象在编辑环境下的拖放顺序以及时间轴上图层的层叠关系,用来帮助Flash 确定对象的深度。图层在Actionscript中是不被引用的,所以在swf文件中也不会有图层这个概念。在编译时,图层被分解为多个对象(多个时间轴),并且每一个对象都会被指定一个深度。当Flash 播放时,时间轴会读取图层中的内容,并根据和其他对象的相对位置关系指定它的深度。如果对象所在的图层较高则获得一个比较高的深度,如果对象所在的图层较底则获取一个较低的深度。与此同时,Flash也会为对象指定一个名称,实现脚本对该对象的引用。深度概念也影响Flash 中对象的创建,在FileàPublish SettingàLoad Order 中可以设置对象被创建的顺序,指定是由低深度到高深度(Bottom up)地创建,还是由高深度到低深度(Top down)地创建,Flash中的默认为前者。
Actionscript 还提供了一些与深度相关的方法和管理对象:
深度方法和功能描述
这里需要加以说明的是,SwapDepth()方法可以把在不同深度的两个对象进行深度交换。如果要实现这种交换有两种方法:一是把两个对象进行调换,即把上面的拿到下面,把下面的拿到上面,这是对对象本身进行操作;二是直接更改对象的深度属性,即直接修改指定对象深度的数值。但是如果使用后者显然不是在交换深度而是在设置深度了。SwapDepth()方法是实现对象深度位置的交换而非设置深度。可以把深度理解为一个容器,比如说是房子,如果两个人要交换房子,那么必须是你搬过来我搬过去,而仅仅更换门牌是没有什么用处的。所以深度是只读的。另外,getDepth()方法可以很方便的获取MovieClip、Button和TextField对象的深度数据。
另外,深度管理器(DepthManager)是一个专门对深度进行管理的Flash V2组件,它封装了若干深度管理的方法:
DepthManager.createChildAtDepth():在指定深度处创建指定元件的子级。
DepthManager.createClassChildAtDepth():在该指定深度处创建指定类的对象。
DepthManager.createClassObjectAtDepth():在指定深度处创建指定类的实例。
DepthManager.createObjectAtDepth():在指定深度处创建一个对象。
DepthManager.setDepthAbove():移动实例到指定实例的深度之上。
DepthManager.setDepthBelow():移动实例到指定实例的深度之下。
DepthManager.setDepthTo():将实例移动到指深度。
四、深度区域:
在为对象指定深度时必须清楚地了解Flash在深度上的三个区域。在Flash 中,深度的范围在-16384到2130690045之间,任何Flash的可视对象都不会超出这个范围。在播放时,Flash把时间轴中的对象按照默认的设置进行加载。-16384到-1是深度的第一个范围,在这个深度区域对象不可以使用脚本创建和移除,用于放置用户在编辑环境下创建的对象,这里把它称为时间轴区(Timeline)。接下来是0到1048575的深度范围,在这个深度范围内,对象可以使用脚本创建和移除,所以称为动态区(Dynamic)。之后一个区域称为保留区(Reserve),深度范围在1048576和2130690045之间,可以放置MC但是不可以移除。
Flash的深度区域:
Flash 在动态区之前提供了时间轴区,用于放置编辑环境下时间轴中的对象。在编辑环境下,最底层的对象放置到区域的最深处——-16384。在通常情况下会从-16383这个深度开始,Flash依次向较高深度放置时间轴中的对象。
接下来是动态区,在这个区域可以放置那些可以动态创建和移除的对象。而且这个区域也符合一般人的使用习惯,因为它的深度是从0开始的,而开发者在创建对象时通常也会考虑这个范围。在这个范围可以获得比较大的自由权,开发者可以使用脚本动态地创建和移除对象。如果对象不在动态区,那么首先可以把对象交换到动态区,然后再进行移除。
保留区可以理解为动态区的一个扩展,只是在保留区中无法使用脚本移除对象,对象在那个区域可以动态地被创建。在这个区域对象也可以使用swapDepth()方法交换到其它的深度区域。但保留区还是一个比较特殊的区域,因为那里的对象不可以被移除,而且深度高的有点离谱。在保留区Flash为对象提供了一定的存储空间。
需要特别注意的是,Flash 在使用createEmptyMovieClip()方法创建的空MC时,深度的分配上几乎没有什么限制,深度可以指定在-999999999999以下或是999999999999以上。虽然这个深度已经超出了刚才讨论的那个范围。
五、时间轴刷新:
关于深度,可能会遇到一些另人混淆的问题,特别是动态区和时间轴区。当时间轴被刷新时,所有的对象将被重新创建。Flash 会扫描位于该时间轴的时间轴区域,并清除保存在这些深度上的对象。然后Flash 读取时间轴上的数据并重新创建这些对象,但是通过动态方法创建的对象将被忽略。其中一个例子就是使用gotoAndPlay()返回播放已经播放过的帧,例如从第10帧返回到底5帧播放,这时Flash为了重新展示第5帧的内容必须刷新时间轴并完全重构第5帧的内容。但是使用动态方法创建的对象如果在时间轴刷新时被移除,那么这时并不被自动创建,除非程序给出。
很明显,这样可能会引起一些问题。首先,这样会失去在时间轴区域或是使用动态方法已经创建并交换到时间轴区域的对象。也就是在这中情况,不可以把使用动态方法创建的对象交换到时间轴区域,否则在时间轴刷新时会丢失这些对象。在开发时为避免这种情况的发生,可以创建一个单帧停止的MC,这样的MC可以是安全的,可以不必为时间轴刷新而担忧。
另外一个问题是无法移除所需要移除的对象。其原因是由于使用深度交换方法把时间轴区的对象转移到了非时间轴区,这样在时间轴刷新时就无法清除该对象了,而且这次刷新还会创建一个新的该对象到时间轴区。这种情况也应该避免发生。
还有一个需要清楚的问题是场景(Scene)跳转的问题。场景间的跳转不会引起时间轴的刷新,也不会触发其他一些特殊的事件。作为场景本身而言,它们是主时间轴的片段,当Flash被发布以后,这些场景便会整合到一起,变成单个的主时间轴。所以用户在一个场景创建的对象,它仍旧可以在接下来的场景出现,当然也可以使用脚本使那些对象消失。
六、播放器执行顺序:
在深度问题上,还有一点比较容易被人们忽视。正如前面所提到的,深度也会影响到脚本的执行顺序。事实上深度本身并不影响脚本的执行顺序,但是深度却与对象的创建顺序有关。一般我们都会认为,在同一时间轴上,首先被创建的对象会首先执行它所包含的脚本。另人感到奇怪的是,在默认的发布设置下,那些最晚被创建的对象反而首先执行了EnterFrame事件中的脚本。在默认情况下对象从最底层开始被创建,这一点我们可以在Flash的发布选项中设置。帧脚本是按照它们被创建的顺序执行的。这样如果在bottom up 模式下,从技术角度而言,较低层的脚本反而较早执行,但是值得一提的是,EnterFrame事件中的脚本刚刚与之相反。
看来很有必要追究一下EnterFrame事件到底是怎样的一个事件。EnterFrame事件随着电影剪辑的帧速被持续地触发。可以认为EnterFrame事件是在播放头进入某一帧时触发的一个事件,但是在EnterFrame事件中的代码将先与帧脚本执行。但是,对象的创建和Flash的播放(对象状态的改变过程)到底是怎样一个关系呢?在Flash中第一帧的帧脚本和其它帧的帧脚本有着不同的行为。当运行一个Swf文件时,它的第一帧将首先被创建,然后开始载入该文档中的对象并拖入到舞台,这个过程可以认为是一个初始化的过程。所以在这个过程中随着对象的载入第一帧的容量将不断增大。这样做的原因也是显而易见的,只有当对象全部载入后,脚本才能执行,设想如果脚本所要操作的对象都不存在,那么脚本必然会发生错误。一旦所有的对象载入完毕,除第一帧外的其它帧都将被一次性创建,并开始播放。这样做的另外一个原因是,如果按照先创建,先播放的原则,那么必然导致不同电影剪辑播放时步调的不一致。因为创建对象是需要时间的,特别是在网络上,它还要有一个下载的过程。这里还要注意的是#initclip和#endinitclip中的代码块,它们通常定义在电影剪辑的第一帧,只要符号被定义且被编译(电影剪辑符号定义了,但不一定都被编译),那么就执行该代码段,它用于电影剪辑的初始化,所以优先于其它脚本执行,并且仅执行一次,它的运行效果将作用到该剪辑的所有实例。
这样,就可以得出,Flash的执行可以分成两个过程。首先是对象的下载、创建和初始化,接下来是一个播放的过程。播放是一个对象状态随着帧速改变的过程,其状态的两个极端是存在与不存在。这样在Flash的执行过程中,电影剪辑第一帧的脚本将首先被执行;然后是播放过程,其脚本执行的原则是EnterFrane事件脚本的执行先于帧脚本的执行。
七、图层(Layer)、层级(level)和深度(depth)
通常人们会把图层和层级混淆起来使用,但事实上它们是两个完全不同的概念。时间轴可以以两种方式独立于主时间轴:电影剪辑(Movie Clip)和层级(Level)。这里所谓的独立是指独立的播放与停止。图层(Layer),只在编辑环境下被看到,用于存放和组织在时间轴上的对象。它们仅仅只是在编辑环境下出现,当发布一个Flash文件时,这些图层将被压缩到同一个时间轴上。
层级(Level)位于一个独立的时间轴上,用于存储使用loadmovie方法加载的外部Swf文件。层级(Level)可以使用_level0, _level1, _level3, _leveln 对其进行引用。层级越高,就越接近观察者,也就越容易被看到,这一点与深度是一致的。使用该方法加载的电影将贯穿电影的主时间轴。由于这个原因从外部加载电影的目的常常是为了加载某些声音,因为声音不会影响到原来电影的播放。
电影剪辑(Movie Clip)同样是一个独立的时间轴,但是电影剪辑位于库(Library)中,并不是位于电影的外部。所以它与层级不同,如果需要的话,你可以在帧上创建一个电影剪辑的实例。 从库中拖动一个电影剪辑到舞台(Stage),那么就创建了该电影剪辑的一个实例,可以指定一个唯一的名称对其进行引用。电影剪辑可以包含其它的电影剪辑,这就是通常所说的嵌套(nesting)。
深度(Depth)通常会用于swapDepth()和attachMovie()这些方法,用于指定电影剪辑的层叠顺序。它可以被认为可视对象在时间轴上的层叠顺序(Z-Order)。
这里还要指出的是 _root 和 _level0 的区别。_root 和_level0引用的并非同一个对象,它们是有差别的。_root 指代电影的主时间轴,如果一个电影有多个层级那么_root指代当前脚本正在执行的那个层级。例如:在层级n中的某个脚本包含了 _root,这时_root返回 _leveln,_root和_leveln才是等同的。
[最后编辑于 N神, at 2005-06-06 01:24:25]
此文还没有评论.
