延續上一個範例。要做到這一點,必須使用SceneLoader這個類別,搭配LoadScene這個Command來達成。基本的原理是這樣:先把各個大單元分開來,那麼每個單元就可以看成獨立的Progression專案,也就是我們會有index專案,about專案,Product專案,以及contact專案。其中只有index專案擁有preloader。每個專案當然就會分別對應一個CastDocument,所以會新增出about.as,product.as,以及contact.as三個繼承CastDocument的類別。然後中間我們使用一個SceneLoader,將上(index)下(about,product,contact)接起來。SceneLoader對上層而言就是扮演SceneObject的角色,事實上SceneLoader就是直接繼承自SceneObject,所以在上層Scene(IndexScene)使用addScene增加Child Scene時,改成addScene(SceneLoader)。對下層則是Loader,再增加讀取進度的設定,就可以把所有專案串起來。
調整.fla檔案
首先,我們要先把各場景要用到的物件都先分割開來。複製index.fla,另存成about.fla,product.fla,以及contact.fla。接著進到每個檔案的library,將不屬於這個單元的元件刪掉。index.fla要留下IndexPage以及Navi跟Bg,about.fla只需要AboutPage,product.fla需要ProductPage以及P1Page跟P2Page。contact.fla只需要ContactPage。元件對應的package也跟著調整,這樣在大一點的專案檔案比較好找。index.fla的元件還是維持在myproject.index,about.fla的改到myproject.about,當然也要將AboutPage.as搬到myproject/about資料夾裡。其他依此類推。然後我們直接將Index.as複製成About.as,Product.as,Contact.as,也設定一下相對應.fla的Class。這些檔案裡面,就把看到的"index"等路徑、檔名、名稱都改成"about"等等。
製作Loading元件
在index.fla裡面製作Loading元件,用來顯示下層讀取的進度。這裡直接複製preloader裡的元件來改。然後在IndexScene的atSceneLoad裡面將它加入foreground底下:
//將這個Scene以及Child Scenes會用到的Cast加到舞台上 if (_document.isPreloaded) { _navi.x = stage.stageWidth - 400; _navi.y = 20; _bg.width = stage.stageWidth; _bg.height = stage.stageHeight; _loading.x = (stage.stageWidth - _loading.width) / 2; _loading.y = (stage.stageHeight - _loading.height) / 2; _loading.alpha = 0; _loading.visible = false; addCommand( new AddChild(_document.foreground, _navi), new AddChild(_document.background, _bg), new AddChild(_document.foreground, _loading) ); }其中_loading是個MovieClip,以new Loading()建構出來。
撰寫MySceneLoader
我們寫一個MySceneLoader,繼承SceneLoader,並且可以接收檔案名稱以及Loading的參照,方便我們動態去讀取各單元的swf。這部分沒有template可以使用,因此先將這個類別的程式碼貼出來再來講:
package myproject.scenes { import flash.display.MovieClip; import flash.net.URLRequest; import jp.progression.commands.net.LoadScene; import jp.progression.commands.tweens.DoTweener; import jp.progression.scenes.SceneLoader; /** * ... * @author Gray Liao */ public class MySceneLoader extends SceneLoader { private var _filename:String; private var _loading:MovieClip; public function MySceneLoader(filename:String, loadingMC:MovieClip = null, name:String = null, initObject:Object = null) { super(name, initObject); _filename = filename; _loading = loadingMC; } //シーンが読み込まれる際の処理 protected override function atScenePreLoad():void { addCommand( new LoadScene(new URLRequest(_filename), this, null, { //こんな感じにしておくと、ローディング状況が表示できた onStart:function() { _loading.visible = true; //若使用addCommand,執行時間會在全部下載完之後,所以這邊直接單獨使用一個Command去執行 var comm:DoTweener = new DoTweener( _loading, { alpha:1, time:0.2 } ); comm.execute(); }, onProgress:function() { var percent:Number; percent = this.bytesLoaded / this.bytesTotal; _loading.bar_mc.scaleX = percent; _loading.percent_txt.text = Math.floor(percent * 100).toString(); }, onComplete:function() { //這邊用addCommand可以讓_loading完全消失後再開始Scene進場 addCommand( new DoTweener( _loading, { alpha:0, time:0.5 }, { onComplete:function() { _loading.visible = false; }} ) ) } }) ); } //シーンが破棄された場合の処理 protected override function atScenePostUnload():void { // 読み込んだシーンを破棄する unload(); } } }基本上它也屬於Scene,因此我們將它放在scenes這個package底下。在建構式裡,多加filename來接收.swf的檔名,loadingMC接收Loading的參照。接到之後先存下來,後面會用到。
接著只要複寫兩個function就完成了。atScenePreLoad是要開始讀取.swf的時候的動作,而atScenePostUnload是如果這個Scene要被移除的話,就會執行。
atScenePreLoad裡面就是addCommand(new LoadScene())而已。而LoadScene有四個參數要設定:第一個是URLRequest,這不用多說,第二個參數是SceneLoader,也就是給它this就好。第三個loaderContainer似乎是設定讀進來後的SceneObject.container,這裡給它null,就會都找到IndexScene的container。第四的是initObject,用來設定下載進度的動作。基本上看function名稱就知道該做啥了,應該不用多講。要注意的是,onStart裡面不要用addCommand,那會等到東西都下載完才會執行。所以要單獨使用DoTweener,然後execute。而onComplete則使用addCommand,這樣可以等Command執行完(這邊是讓Loading fade out),才會做下一個Scene進場。
atScenePostUnload裡面只要unload就行了。
再次修改IndexScene
接著修改IndexScene裡面addScene的部分:
//增加Child Scenes addScene(new MySceneLoader("about.swf", _loading, "about")); addScene(new MySceneLoader("product.swf", _loading, "product")); addScene(new MySceneLoader("contact.swf", _loading, "contact"));改成新增MySceneLoader類別的實體,再給檔案名稱,Loading參照,名稱這三個參數就可以了。
修改完後重新發布就可以了。基本上一般的網站製作一開始就會把元件檔案規劃好,所以不會需要前面的修改。所以只要會寫SceneLoader,然後上層在addScene的地方改一下,很快就串好了。而這樣分割出來的.fla主時間軸不會自動加到DisplayList,因此在整個範例中我們在主時間軸上都不加任何元件。
測試與下載
最後來看看結果:請按此。
下載範例:請按此。
上一篇文章:Progression 4 歡樂開發Flash網站 ( 3 ) — 簡單範例
下一篇文章:Progression 4 歡樂開發Flash網站 ( 5 ) — 增加導覽列功能
Gray你好, 我想請問一下,場景分隔後,是不是就抓不到個別的CastDocument!? 因為所有SceneObject.container都指到Index去了!?
回覆刪除在我使用的範例裡面,每個Scene都有一個_page,我設定成private,你可以把它設定成public,或者開一個getter讓外部的類別可以取得,這可能才是你需要的,因為這才是被加到Display List底下的東西,抓個別的CastDocument好像沒甚麼需要?
回覆刪除謝謝你的回覆,不過我的主swf跟分割後的子swf是放不同的目錄,我希望藉由CastDocument的loaderInfo來抓個別的子目錄位置
回覆刪除試試看SceneLoader.contentSceneInfo或SceneObject.sceneInfo,兩個都是一個SceneInfo,而SceneInfo.loaderURL或許就是你要抓的~
回覆刪除感謝Gray超詳細的分享,我想請問我可以在Aboutpage.as底下抓到index的container嗎,我想從aboutpage的程式下把元件加到index的container底下,不知可否做到?謝謝
回覆刪除To erika:
回覆刪除可以參考這篇介紹的幾種抓取instance的方法
http://grayliao.blogspot.com/2010/11/progression-4.html
或者自己設計一個Singleton來存一些重要的參照
或者AboutScene在add AboutPage的時候把container傳進去
謝謝Gray的回覆,用getSceneById可以解決了,
回覆刪除感謝了!!目前還在努力學習中。