且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

 ActionScript 3 日积月累之二

更新时间:2021-12-16 17:33:43

作者相关,转载请保留:http://as3blog.com/as3/as3tip-new-philosophy/

对于AS1、AS2的开发模式来说,灵活是最大的优势。然而,灵活却造成了不稳定、紊乱。这是开发复杂的、长久的项目所忌讳的。关于(AS1/2/1+ 2)灵活轻便与稳定持久(AS3)的权衡,我个人觉得可以理解为“鱼和熊掌不可兼得”,但我希望已经习惯了AS1、AS2的朋友们不要把这个结论想得太悲观。

AS3是纯粹面向对象的,相比过去的AS2,我认为是更加敏捷的。纵然有着更多的约束,但在package内直接建立多个辅助类(Helper Class),不失为一个非常好的消息。就凭这一点,我觉得至少与笨拙的AS2相比,AS3的开发效率就不会打多大折扣。我们需要的其实只是语法、习惯,尤其是观念的转变而已。当然,这需要时间。我作为一个AS1/2的长期发开人员,在转变到AS3的过程之中,也遇到了很多问题和疑惑。但我很乐于与大家分享、交流我所获得的收获及观念转变的心路历程。

ActionScript编程自它问世的那一天就是多姿多彩的。技术,尤其是Adobe产品线的技术体系,也绝然不是呆板的“学究式体系”。我希望我的“罗嗦”能让您获得一个更轻松的心态。

言归正传,先说说我在AS1/2(1+2)转变到AS3时所遭遇的最大困惑吧:

开局(How, and especially where, to get start) - 玩过星际争霸的朋友们一定知道,针对不同的地图,如Lost Temple 和WCG-groky park(原来WCG有一个岛关,我忘记了),都有各自的经典、流行的开局方式。从AS1/2转变到AS3,无非是从Lost Temple 转变到WCG-groky park 的过程,你也许要先采气矿造空军,才能顺利发展。

其实Flash从AS1到AS3,也有各自固定的、流行的开局方式。

对于习惯了用AS1编程的人来说,制作一个Flash的开局是非常灵活的:你一进入Flash就有一个长长时间轴以供使用。你往往需要一个 loading,你可以用1-5帧先做一个loading(还记得N年前流行的FlashMTV制作教程么?);你也可以取一帧,放一个loading的 MovieClip 然后在这个MovieClip 上写一个onEnterFrame 来监听swf 文件加载的进度(我热衷的做法)。接下来,你可以在第二帧或者第N帧部署程序界面。MovieClip 强大的帧API能让你灵活地完成许多有趣的逻辑(gotoAndPlay、gotoAndStop、 prevFrame等)。编程的时候也可以很随意地寻找自己要控制的资源,我现在还记得刚接触AS的时候,一个_root一个_global,曾经让我屡试不爽。每次遇到问题了就用这两个东西解决。

AS2的开局其实没有本质的变化,至少我是这么认为的。唯一的进步就是比AS1的OOP,模块封装的更加彻底。甚至还有些许退步,比如清一色基于 MovieClip + attachMovie 的模式,仍然容易造成运行时(Run-Time)效率低下,而且开发起来概念也模糊了。因为Library中设置了linkage,new的明明是自己的Class,attach的还是MovieClip。

于是很多人采用AS1+2的方式,这也是我所喜欢的。现在想起来,还是比较灵活快速的。然而在AS3中,你却仿佛陷入一片黑暗。FlexBuilder 没有时间轴。即便用“似曾相识”的FlashCS3的IDE开发,AS3 也不支持 MovieClip和Button上的代码。写在帧上也无法简单地使用“onRelease=function”了。上网搜教程,往往得到如下写法:

aw.addEventListener("click",fun);
function fun(e:Event){trace(1);}

实在让习惯了AS1、2的朋友们郁闷。一方面看到人家用AS3设计出来的精彩demo 羡慕不已,一方面又对程序入口摸不着边际。这种尴尬我想不是看一两篇教程就能解决的。

我们需要“洗心革面”,我们需要“忘记过去”(try to forget the past)。大胆地告诉自己,onRelease=function不仅已经被“杀死”,而且根本就不是好的写法,哪怕你仍然觉得它看起来那么顺眼。大胆地告诉自己,AS3中,所有的变量、函数都属于类(对象的属性和方法),而不再属于时间轴、帧,哪怕上面列举的两行代码也可以写在时间轴上生效。

我个人建议,传统AS1/2的程序员从Flash CS3 IDE入手AS3,比较合适。因为Flash CS3的入口(开局)非常明确:Document Class(文档类)。

运行FlashCS3,打开fla文件,在IDE下面属性面板中,找到“Document Class”,填入一个名字(由于是类名,***是首字母大写,比如MyMainClass)。然后在fla文件所在的文件夹下面建立同名的as文件。当然,也可以把fla 和类文件全部分离,这就需要设定类路径(File-Publish Settings-ActionScript version:Settings)。下面可以输入类路径。我个人建议输入相对路径。相对,意即相对当前的fla文件;路径,即我们电脑文件系统中的文件夹。不写死“x:\xxx”是为了让项目可以在不同的环境上运行,也可以更好的支持多人开发。相对路径的写法就是用“.”表示当前路径,用“..”表示上一级路径。比如可以写:
“./classes/”或者“../classes/”。

这里再补充说明一下,我的建议是把原文件放在一起,输出的swf放在别的目录(通常叫做“bin”)。输出目录在刚才面板中的“format”标签下,可以把原文件放到目录“src”中,然后把swf格式的file名设置为“../bin/somefile.swf”,建议只输出swf。HTML还是自己写的好。

别看我罗嗦了这么多篇幅讲这些设置,但它们真的对于规范你的开发习惯和开发观念有好处。让你潜移默化的接受AS3的Philosophy中的“分离”思想。

经典论坛讨论:
http://bbs.blueidea.com/thread-2744560-1-1.html

切入正题,我们逐步开局:

一、建立文档类(Document Class)

现在我们可以开始建立Document Class了。Flash CS3方便地提供了一个“编辑图标”,你可以方便地打开类文件。回忆一下,上一篇文章提到关于类的书写:每一个类都应该在一个package中。我个人的理解,觉得Document Class 应该在一个单独的、无具体名称的“generic”package中,即:

package
{
import flash.display.Sprite;
public class MyMainClass extends Sprite
{
public function MyMainClass()
{
init();
}
private function init()
{
// do sth
}
}
}
// We can even use some help classes
class MyMainClassHelper{}

这里,我们就成功“开局”了。
注意,这个文档类必须为public 的。而辅助类则不能定义为public、private 的,必须是internal 的。文档类必须继承自Sprite 或者MovieClip。因为这个文档类代表了这个swf,显然swf 是一个需要在屏幕上渲染显示(flash.display.DisplayObject)并提供资源承载能力(flash.display.InteractiveObject)的基础容器。

二、逻辑开局(Initialize the logic)

我们所有的逻辑入口都是从这个类的构造函数开始的。AS3的loading有一些麻烦,我们暂时跳过(稍后会介绍)。

构造函数一般要保持简洁,不妨用流行的init 方式开局,即在构造函数内调用一个init 函数。记住一点,AS3中,“_root”已死,这里就是传统意义上的“_root”了。你看到的这个类(文档类),第一反应应该是这个swf 文件(就如同你原来看到“_root”就应该反应到swf 文件一样)!在这里可以找到原来我们需要的许多资源,例如我们可以找到通过loaderInfo:LoaderInfo 属性(继承自DisplayObject),获取外部参数:xxx.swf ?somevar=1传进来的“somevar”,也可以通过stage:Stage属性(继承自DisplayObject),来进行原来的Stage类的各种操作。我也可以用contextMenu:ContextMenu 属性(继承自InteractiveObject),来控制flash右键菜单的内容。

这一切都在文档类的init以及其他所属方法中进行。所有的其它功能,可以封装成别的类、包进行“模块式”调用。

三、事件机制(The new Event System)

习惯新的事件机制所花的勇气,我认为和开局相当。

我曾经热衷于xxx_mc.onRelease = function(){}的写法,而且做过N多这样的项目。然而当我真正开始用addEventListener 的时候,才发现这是多么优雅的写法。

优雅在哪:
1. 统一:只有addEventListener,没有addListener、没有on(…),代码可以统一地放置。
2. 清晰:事件处理函数作为类的方法(Methods)列举分明,试想一个跟在onXXX后面的赋值函数放在代码当众多难找。
3. 信息翔实、准确:新的事件机制通过传递Event对象让事件的信息完整无漏地传达给接受方;函数(方法)与类绑死,Delegate终于可以光荣退休了。

四、总结

1. 接受新的OOP开发体系:类/对象(class/object)+构造函数(constructor)+成员属性(properties)+成员方法(methods),除了这些东西以外,ActionScript 没有别的存在形式!把时间轴和实例上的代码都忘记吧!

我们要“拥抱”类的概念!AS3中所有的一切围绕着类的概念进行。swf就是一个类,用Flex开发,叫做Application,用CS3,叫做 Document Class(往往继承自Sprite)。任何变量(属性)都属于一个类,MovieClip有成员属性currentScene,它是Scene 类的一个实例;Sprite有成员属性contextMenu和stage,它们继承自DispatchObject 类,分别是ContextMenu 类和 Stage 类的实例。

2. 没有_root,所有的_root 有关的操作,封装到文档类中的成员函数(方法)进行。_root不再是swf 的代表,取而代之的是Document Class(或者Flex中的Application Class)

3. 功能模块化、分离:
不要把所有的事情都塞到文档类中去做,哪怕你可以定义很多辅助类,毕竟独立出来的文件更加便于管理、集成、再使用。而且界面(图形、动画)和代码要分离(事实上AS3的Document Class 和addChild 的内容管理体系帮我们完成了这个操作)。无论你是一个人搞定代码+设计还是有一个团队协作分工编程与动画。分离的好处是让你的功能更加强大和易维护。

经典论坛讨论:
http://bbs.blueidea.com/thread-2744560-1-1.html