2010年6月18日 星期五

Progression 4 歡樂開發Flash網站 ( 2 ) — 基本原理與主要構成

新增了一個專案,一下子產生出好幾個檔案。在動手寫程式之前,我們先試著分析一下Progression運作的基本原理與主要構成。前面提過,Progression主要是用來解決網站架構,以及各場景畫面間的切換。網站架構的部分使用Scene場景來組成一個Scene tree,對應傳統的網站架構,然後在進入每個Scene的時候將這個場景應該上場的Cast演員放到舞台上。各個場景間的切換則是一套定義完整的事件機制,我們只要下切換場景的命令,事件就會依序發生,那麼在每個相對應的事件發生時去處理進退場,以及Cast的上下場,那麼整個網站就自然的運作起來。另外,為了方便讓每件事情依序進行,Progression裡面有一套Command命令,把每件要做的事情用Command的方式來指派,然後依照想要執行的順序加到適合的CommandList,然後一次執行,就可以解決很多錯綜複雜的狀況。而這背後,則是由一個manager(Progression)在掌控。以下就針對每個部分來加以說明。

網站架構
通常在企劃網站,會畫出一個網站架構圖,舉一個簡單的例子:

當我們使用Progression來建構Flash網站,可以直接把這些HTML頁面對應成一個Scene Tree,如下圖:

非常簡單直覺。其中,最上層的IndexScene也就是Root Scene,其實就是我們新增專案裡面的IndexScene.as。接下來的Child Scene,我們可以視情況在IndexScene裡使用addScene等方法來加入。而我們也可以看到,IndexScene其實是繼承自SceneObject類別,這是一個Scene最基礎的類別。
這種Scene Tree架構還有一個很棒的地方,就是它可以跟SWFAddress同步,而path的組成則是用SceneObject.name屬性。舉例來說,假設ProductScene.name是product,P1Scene.name是p1,那麼:
IndexScene的網址就會是:http://www.myweb.com.tw/
ProductScene的網址就會是:http://www.myweb.com.tw/#/product
P1Scene的網址就會是:http://www.myweb.com.tw/#/product/p1
其中Root Scene的name不會出現在網址上,因為它代表的就是網站一開始進入的點。
Scene的工作除了架構出Child Scene以外,還有一件工作就是把各個Cast演員加入到場景上。這邊要特別提醒:雖然看起來一個Scene對應到一個HTML頁面,但SceneObject不是一個可視物件,SceneObject.container才是。之後的章節會介紹,我們是把各種Cast加到SceneObject.container(或其他可視物件)底下,才會加到DisplayList底下,也才能夠被看到。

場景切換的事件機制
架構完後,來看看場景切換時會有哪些事件發生。跟場景切換有關的事件總共有六種,其中四種較常用,也就是template會自動幫我們產生出來的Load、Init、Goto、Unload四個,另外還有兩個,Ascendm與Descend。而要設定一個SceneObject的這六種事件有三種方法:1.用AddEventListener偵聽SceneObject發送出來的SceneEvent,也就是AS 3.0常見的方式。2、使用SceneObject的onSceneXxxx屬性來設定它的事件處理常式,例如:aboutScene.onSceneInit = function() {...};,也就是類似AS 2.0事件的處理方式。3、在繼承自SceneObject的Class裡面,例如IndexScene.as裡,複寫atSceneXxxx事件處理常式,可以從IndexScene.as裡面看到那四個override的function就是。有一點亂,整理一張表如下:
事件 說明
SceneEvent.SCENE_LOAD
onSceneLoad
atSceneLoad
目的地Scene是這個Scene或Child Scene時,在進入這個Scene的時候會先觸發這個事件。本身與Child Scene要加入舞台的Cast可以在這裡處理。
SceneEvent.SCENE_INIT
onSceneInit
atSceneInit
目的地Scene是這個Scene時,在進入這個Scene時會觸發,時間在SCENE_LOAD之後。這個Scene才有的Cast可以在這裡加入舞台。
SceneEvent.SCENE_GOTO
onSceneGoto
atSceneGoto
這個Scene是Current Scene,在要前往其它Scene時會觸發。只是經過的話不會觸發。通常SCENE_INIT加入的東西在這裡移除。
SceneEvent.SCENE_UNLOAD
onSceneUnload
atSceneUnload
目的地Scene是這個Scene的Parent Scene時,在階層真正切換的瞬間會發生。通常SCENE_LOAD加入的東西在這裡移除。
SceneEvent.SCENE_DESCEND
onSceneDescend
atSceneDescend
目的地Scene是這個Scene的Child Scene時,在經過這個Scene的時候會先觸發SCENE_LOAD,再觸發SCENE_DESCEND。
SceneEvent.SCENE_ASCEND
onSceneAscend
atSceneAscend
目的地Scene是這個Scene的Parent Scene時,在經過這個Scene的時候會先觸發SCENE_ASCEND,再觸發SCENE_UNLOAD。
舉兩個例子說明一下這些事件發生的順序。
例一:從IndexScene出發到P2Scene

首先IndexScene要開始出發的時候會觸發SCENE_GOTO,接著經過ProductScene時會觸發SCENE_LOAD,因為要往下走,所以跟著觸發SCENE_DESCEND,最後到P1Scene時先觸發SCENE_LOAD,再觸發SCENE_INIT。
例二:再從P1Scene到AboutScene

首先P1Scene要出發時先觸發SCENE_GOTO,接著經過ProductScene因為要往上走,先觸發SCENE_ASCEND,再觸發SCENE_UNLOAD,最後進入AboutScene時先觸發SCENE_LOAD,再觸發SCENE_INIT。
通常SCENE_DESCEND與SCENE_ASCEND不太會用到,大都只要在SCENE_LOAD與SCENE_UNLOAD去處理路過的事情就夠了。

可視物件,各種Cast
前面提到,Scene只是用來架構網站,以及頁面的切換,並不是可視物件。真正的可視物件,在Progression裡稱為Cast演員。場景搭好後,當然是要指定每一場該有的演員到場上表演啦。可以稍微翻閱一下線上文件的jp.progression.casts這個package,大部分都是繼承自flash.display來加一些擴充功能。Cast在被使用AddChild類Command加入,RemovedChild類Command移除時,分別會觸發CastEvent.CAST_ADDED以及CastEvent.CAST_REMOVED兩個事件,可以在這裡撰寫進場與退場動作。而要設定Cast的這些事件也跟Scene一樣有三種方法,就不多作解釋,直接列表如下:
事件 說明
CastEvent.CAST_ADDED
onCastAdded
atCastAdded
Cast被加到舞台後,可以做進場的控制。
CastEvent.CAST_REMOVED
onCastRemoved
atCastRemoved
Cast從舞台移除前,可以做退場控制。
其中有三個特殊的Cast要稍微介紹一下:
CastPreloader:顧名思義就是當Preloader用的。新增專案裡面就有一個preloader.fla、Preloader.as。裡面有針對Loading所使用的事件就先不細講,比較特別的是,它其實是最底層的Display Object,CastPreloader.background以及CastPreloader.foreground是它特有的兩個Sprite,而load進來的swf會放在這兩層中間,所以foreground可以放Logo、Navigation、Header、Footer等會一直在網站上層的元件,而background則是拿來放背景圖等會在最下層的元件。不過這些動作最好在index被load進來以後再做,因為Preloader的用意就是檔案要盡量小,一開始就加一堆東西會讓Preloader失去意義。
CastDocument:第一個被Preloader讀近來swf,它的類別必須是繼承自CastDocument,而後面章節會介紹到,用SceneLoader讀進來的swf也必須是繼承自CastDocument。新增專案中的index.fla及Index.as就是。index.swf的主時間軸會被讀到CastPreloader的foreground與background中間,而其他用SceneLoader讀入的swf主時間軸則不會自動加入到DisplayList中,這是因為所有的SceneObject的container屬性都會指到最底部的CastDocument,也就是Index。所以使用Progression最好養成時間軸上不要直接放元件的習慣,請使用AddChild等指令加到舞台上,而這同時也可以確保CAST_ADDED事件會被觸發。CastDocument也有foreground與background兩個屬性,只有在使用Preloader時才會有值,因為它們分別指到CastPreloader的foreground與background。CastDocument主要的工作在設定manager(Progression),以及跟(Root )Scene連結。所以加入其它元件的動作,我個人建議挪到IndexScene裡面去做,包含想加東西到foreground以及background,因為這樣可以讓分工清楚一點。
CastButton:場景的切換,除了使用GoTo以及JumpTo等命令外,通常是使用CastButton來實現Button讓user控制要瀏覽的內容。只要指定CastButton.sceneId就可以完成場景切換的設定。若要外連到其他網址可以設定CastButton.href屬性就行了。若同時設定sceneId與href,則只有href會有作用。
其它的Cast大都如前面講的,就是DisplayObject的延伸,加入事件的發送與偵聽,還有一些有趣的功能,例如CastImageLoader加入了讀取圖片完後縮放、對齊圖片等等常用的功能,都很值得拿來試試。而一般的可視物件,就繼承CastMovieClip或CastSprite來用吧。
而整個Progression的視覺元件大致的架構可以用一張圖來解示:


Command命令執行
前面一直提到Command,這是Progression很大的一個特色。所謂Command,就是用來執行某些事情,必須使用Command.execute()來開始執行,而執行完後會送出EXECUTE_COMPLETE事件,也可以被中斷。Command也可以透過delay屬性來設定一段時間之後再開始執行,甚至有Wait()專門停止一段時間的Command。在template裡面也有MyCommand可以拿來修改,只要實作幾個function,我們也可以製作自己的Command。而CommandList基本上繼承自Command,所以本身也是Command的一種,主要是用來執行一連串的Command。要依序執行就用SerialList,要同時執行就使用ParallelList,甚至可以混用,其它還有還有可重複執行的LoopList,還有可往返執行的ShuttleList等等。

manager(Progression),幕後的黑手
前面提到manager會在CastDocument的地方做設定,它主要用來控制Scene的移動與停止,監控Scene Process,設定Root Scene,與外部的SWFAddress同步等。

上一篇文章:Progression 4 歡樂開發Flash網站 ( 1 ) — 新增專案
下一篇文章:Progression 4 歡樂開發Flash網站 ( 3 ) — 簡單範例

沒有留言:

張貼留言