【转】Flash/Actionscript3 载入资源文件方法考

2012-07-14更新:修改了部分不流利的翻译;修改了部分表述方式;加入了iOS的一些限制;重新排版。

这篇文章描述了Flash/flex中载入图片等资源文件的几种方法,目前Flash最新的版本是Flash Pro CS4,CS5快要发行beta版。那么,我们来具体的看一看如何输出SWC文件,并通过[Embed]元标签来获得资源的方法。

1. 背景

如果,你正在创建一个应用程序,一个游戏,或者一个网站。在设置你的Flash项目时,有两种选择。1你可以创建一个FLA文件,指定一个文档类进行编码。或者2,你也可以选择Flash/Flex Builder,FDT,Flash Develop等,创建一个Flex或者AS3项目,然后使用Flex SDK编译它。几乎每一次,我都选择后者,因为后者增强了程序的可靠性,而且编译速度更快。

即使你选择了使用Flash Pro创建并编译FLA文件,你也可能会在Flash Builder或者其他IDE中修改代码。但问题是,之前你使用的是Flash Pro编译,接着要使用Flex SDK进行编译。写这篇东西的目的是,当我们使用Flex SDK编译Flex或者AS3项目时,我们如何通过FLA载入资源的。

我尽可能的将我所知道的写出来,但一定会有些技巧和窍门,甚至是方法,是我所不知道的。如果你发现任何错漏的地方,请一定让我知道,我会尽快修正。

为什么非要是FLA文件?

你可能已经知道,可以将PNG图像,SVG和其他文件类型嵌入到你的类中,并且永远也不需要通过FLA文件获取图形。当涉及到动画,你可以使用TweenLite或者GTween。但是涉及到帧动画,角色动画,或者干脆是按钮和手绘的元件时,你可能需要使用Flash Pro上强大的时间轴,图形和动画工具去创建元件,并使它们动起来,这时就需要FLA了。

这时候你该问问自己,如果我的项目不使用Flash Pro编译,那么如何从FLA中获取资源导入到项目中去?

2. 工作流程

这里有五种将FLA中的资源嵌入到Flex或者纯AS3项目中的方法。为了照顾通用性,我已经排除了那些只适用于MXML的方法。

2.1 通过FLA发布SWC

这个方法涉及到库元素链接类,你必须在元素链接中写明类的路径,例如“com.package.MyClass”。接着你必须选择在“Flash发布设置面板中”勾选“导出SWC”,然后打开“AS3设置面板”勾选“自动申明舞台实例”选项以避免错误。最后,添加所有必须的类路径以避免在编译的时候出错。

当你发布SWF文件时,SWC文件也会被发布到同个文件夹中。你将这个SWC文件加入到你的AS3项目中,就可以通过编码使用里面的类/元件了。

优点:

这个方法保持了时间轴上的as代码,适合复杂的,嵌套或者多个状态的动画。

缺点:

  • 当你改变元件链接的类时,你必须重新编译整个FLA文件。这意味着又要打开Flash,导出SWC文件,再导回Flash Builder,刷新项目才能够重新引用新的SWC文件,最后再重新编译整个项目。
  • 你还必须确保,元件链接的类不在项目的源目录(或项目映射的源代码目录)。如果你不这样做,你可能看不到你的图形/动画,因为Flex链接器会因为编译顺序而寻找类别定义,从而忽略SWC。
  • 你必须添加所有必要的类路径进FLA。
  • Flash builder将不会报错,而且你也不能通过Ctrl/Cmd+左键点击跳到源文件中。
  • 你不能立即在舞台上使用它们,解决办法是相当痛苦的(见 这里)。

总结:

虽然这是保持时间轴代码的唯一方法,但缺点使它变得不直观,同时令人沮丧。如果谁能提供一个改善的方法,我会请你喝啤酒。

2.2 在申明类之前使用 [Embed] 标签

1package my.package {
2    [Embed(source="assets/some.swf", symbol="SymbolName")]
3    public class MyClass {
4    // code
5    }
6}

在这里我们仅仅使用一个FLA生成一个SWF来存储我们的元件。FLA中的元件没有做任何类绑定。库中只是充满了MovieClip。在我们的类文件中,我们添加[Embed]标签,接着绑定SWF文件中的元件。所以,当我们创建这个类的实例时,我们就能得到元件库中的图形。

优点:

  • 你不必重新编译FLA文件,除非你改变FLA中的图形。
  • 你可以在编码环境上花更多的时间,而不是在不停的来回捣腾。
  • 你可以实时的获得编译错误,因为代码不是来自一个SWC文件。

缺点:

  • 它会取消元件中时间轴上的所有AS代码。换句话说,你在SWF中写的所有的AS代码都无效了。如果你的元件是一个MovieClip,而且有几帧中有stop命令。那么你的动画就会不停循环。可以使用addFrameScript(5, stop)来解决这个问题,但addFrameScript是一个未公开的方法,你不知道什么时候它会被取消。
  • 还可以使用大量的帧标签作为“元标签”进行代码替换(依然是利用addFrameSCript),这又自成一篇http://code.google.com/p/as3-asset-modifier/

2.3 [Embed] 标签在类属性前声明

1[Embed(source="assets/some.swf", symbol="MySymbol")]
2private var MySymbol:Class;
3// later on in a function...
4var myInstance:Sprite = new MySymbol();

和第2种用法类似,这种方法也会删除帧上的代码。

采用这种方法,你要么实例化一个SpriteAsset(扩展自Sprite),要么是一个MovieClipAsset(扩展自MovieClip)。注意,如果在Flash中的MovieClip只有一帧,那么其实它是一个SpriteAssets。

2.4 用 [Embed] 标签载入整个SWF

这里还有另外一个可用的属性可以提供给Embed元标签,就是mimeType。如果你删除元件属性,并让mimeType=application/octet-stream” 。将会嵌入整个SWF,并且保持库中的类关联。

当你使用这种方法从一个SWF中嵌入一个元件,你可以使用Loader去获得类,像这样:

 1[Embed(source="assets/some.swf", mimeType="application/octet-stream")]
 2private var MySWF:Class;
 3// within a method
 4var bytes:ByteArray = (new MySWF() as ByteArray);
 5var loader:Loader = new Loader();
 6loader.loadBytes(bytes, new LoaderContext(false, ApplicationDomain.currentDomain));
 7// wait for loader to dispatch Event.COMPLETE and...
 8var myClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition("com.package.MyClass");
 9var myInstance:DisplayObject = new myClass();
10// myInstance is now an instance of the class linked to it

优点:

这是一个很棒的方法去获得资源而不必重新编译FLA

缺点:

  • 如果你有很多元件,或者很多嵌套了很多其他东西的元件,这种方法就不是一个理想的选择。即使库能提供很大的帮助。但是……它没有严格定义类型。
  • 在生成iOS应用的时候,不能使用这种方法。因为iOS应用不允许你载入一个“可以执行的swf”。

2.5 运行时载入一个SWF

这也许是最古老的一个方法。在运行时加载SWF可以使用applicationDomain.getDefinition()获得元件/类,和方法3有点类似。如果你已经熟悉了getDefinition()方法,那问题就简单得多了。但你针对的只是一个特定的SWF中的类。

zrong: 这里也有一篇关于这种方法的介绍

优点:

适用于很少改变的内容,比如字体

缺点:

  • 神奇的字符串:定义一个字符串常量不会有别的什么作用,如果你改变FLA中的字符串,你的常量就变得毫无意义。并且你只有在那片代码执行的时候才能才会发现。
  • 你必须从FLA中导出你的SWF,或使用其他技术。这意味着你会遇到其他的一些问题。
  • 在生成iOS应用的时候,不能使用这种方法。因为iOS应用不允许你载入一个“可以执行的swf”。

总的来说,我觉得每一种方法都有缺陷,所以要慎重做出选择。目前我还没有找到一个完美的方案。能够使用Flash Pro加快处理游戏资源,在舞台上放置资源,在时间轴上做动画……但这样做弊大于利,把读取资源的工作搞复杂了。我希望在未来能加强工具间的联系,或许能通过一个新的文件格式来实现(XFL:http://www.moock.org/blog/archives/000269.html)。

或者看这里:http://www.riaidea.com/article.asp?id=36

3. 延伸阅读