跳到主要內容

Progression3 tutorial part2

上一篇簡單分享過Progression全組件式的寫法
雖然方便, 但擴充性並不強, 要寫一個專案, 還是需要乖乖來寫程式
玩Progression要先搞懂三個要點:
1. 場景 ScendObject
他是Progression的整個核心架構
你可以想成html, 一個scene就是一頁html
該scene要有什麼元素, 都由這個SceneObject來管理
SceneObject有四個重要的事件:
_onLoad:當該場景被載入時。
_onInit:當該場景被初始化。
_onGoto:當該場景切換到別的場景時。
_onUnload:當該場景被移除時。
SceneObject的生命週期就是走這四個事件。
只有最上一層的主場景_onLoad只會發生一次
_onUnload永遠不會發生, 這個後面會再補充。

2. 可視物件 CastSprite, CastMovieClip
跟一般的Sprite, MovieClip使用起來差不多
但有二個重要的事件。
_onCastAdded:當透過new AddChild 或是 new AddChildAt 加入該物件時, 會發生的事件
_onCastRemoved:當透過new RemoveChild 移除該物件時, 會發生的事件。

3. Command
Progression提供了許多的 Command可以使用
Command Design pattern的好處就是可以依序的執行Command
跑完A, 再跑B , 再跑C,
所以可以很方便的製作單元切換的進退場效果。
像第二點的new AddChild就是 Command的其中一種

一個專案一般只會有一個Progression實體物件。
var prog:Progression= new Progression( 'index', stage, IndexScene );
'index':為該專案的Progression唯一的 Key 值, 只要key值不同, 彼此寫的Progression就不會打架
stage:把stage實體傳入
IndexScene:則是最上一層的 SceneObject, 其他的場景就由這裡開始加入

在這兒範例裡, 做了一個很簡單的架構, 好讓快速上手
首頁場景:
場景上有二個Button,
About:
About的內容可視物件
Contact:
Contact的內容可視物件

其中首頁的場景就是對映剛剛的IndexScene。

先建立Progression
Index.as
package milkmidi.progression {
import flash.display.*;  
import jp.nium.events.DocumentEvent;
import jp.progression.casts.*;
import jp.progression.commands.*;
import jp.progression.core.debug.Verbose;
import jp.progression.events.*;
import jp.progression.loader.*;
import jp.progression.*;
import jp.progression.scenes.*; 
import milkmidi.progression.scenes.IndexScene;
public class Index extends CastDocument {
public var prog:Progression;   
public function Index() {}  
protected override function _onInit():void {   
align = StageAlign.TOP_LEFT;
quality = StageQuality.HIGH;
scaleMode = StageScaleMode.NO_SCALE;    
//Verbose.enabled = true;
//是否啟用 debug 功能。   
//Verbose.filteringCommand();   
//debug 功能是否過濾 Command 資訊   
prog = new Progression( 'index', stage, IndexScene );    
prog.sync = true;      
//是否啟用swfAddress功能。   
prog.goto( prog.firstSceneId );
//播放第一個場景, 也就是 IndexScene
}
}
}
建立IndexScene, 主場景物件
同時在IndexScene裡有一個 IndexPage的主畫面。
package milkmidi.progression.scenes {
import jp.progression.casts.*;
import jp.progression.commands.*;
import jp.progression.events.*;
import jp.progression.loader.*;
import jp.progression.*;
import jp.progression.scenes.*;
import milkmidi.progression.btn.*;  
import milkmidi.progression.page.IndexPage;
public class IndexScene extends SceneObject {  
public var page:IndexPage = new IndexPage(); 
public function IndexScene() {   
title = "IndexSceneTitle"; 
//網址的 Title      
addScene( new AboutScene('about') );           
//加入子場景 
}    
protected override function _onLoad():void { 
//當場景被載入時
//如果是IndexScene(主場景), 就只會被載入一次, 
//所以可以把要常駐的物件在這兒加入。
//在這個範例是加入二個按鈕。    
var indexButton:IndexButton = new IndexButton();
indexButton.x = 0;
indexButton.y = 400;
progression.container.addChild( indexButton );

var _aboutBtn:AboutButton = new AboutButton();
_aboutBtn.x = 100;
_aboutBtn.y = 400;
progression.container.addChild(_aboutBtn); 

addCommand( 
new Trace(this + "._onLoad()")    
);
}
protected override function _onInit():void {   
//當場景被初始化時
//該函式會接在_onLoad後發生
//除非是直接呼叫該場景的子場景
//ex:  #/about/aboutchild/
//那_onInit就不會發生。   
addCommand(
new Trace(this + "._onInit()"),
new AddChild( progression.container, page ) 
);
}  
protected override function _onGoto():void {    
//當場景離開時
addCommand(
new Trace(this + "._onGoto()"),
new RemoveChild( progression.container, page )
);
}
protected override function _onUnload():void {  
//當場景移除時
addCommand(
new Trace(this + "._onUnload()")
);
}
override public function toString():String {
return "[" + name + "Scene]";   
}
}
}

package milkmidi.progression.page {
import flash.text.TextField;
import flash.text.TextFormat;
import jp.progression.casts.*;
import jp.progression.commands.*;
import jp.progression.events.*;
import jp.progression.loader.*;
import jp.progression.*;
import jp.progression.scenes.*;
public class IndexPage extends CastSprite { 
public var txt:TextField; 
public function IndexPage( initObject:Object = null ) {
super( initObject ); 
//這兒只是做一個文字。
txt = new TextField();
txt.width = 400;
txt.text = "IndexPage";      
txt.setTextFormat( new TextFormat("Arial", 60));
txt.mouseEnabled = false;
addChild( txt );     
}
protected override function _onCastAdded():void {   
//當透過new AddChild 或是 new AddChildAt 加入該物件時, 會發生的事件。
//直接使用addChild的話是不會發生該事件的喔。
txt.x = -400;
//透過 Command, 可以在這兒加入進場的效果。
addCommand(    
new Trace(this + "_onCastAdded()"),
new DoTweener( txt, {
x:0,
time:1
} ) 
);
}  
protected override function _onCastRemoved():void {   
//當透過new RemoveChild 移除該物件時, 會發生的事件。
//直接使用DisplayObjectContent的removeChild的話是不會發生該事件的喔。
//在這兒就可以加入退場的效果。
addCommand(
new Trace(this + "_onCastRemoved()"),    
new DoTweener( txt, {
x:-400,
time:1
} )  
);
}
override public function toString():String {
return "IndexPage";
}
}
}

到這兒先來分析一下
Progression實體被建立, 並goto到第一個場景也就是 IndexScene
當來到 IndexScene 後
就依序發生了_onLoad , _onInit事件
然後我們在_onInit時, 透過new AddChild加入 IndexPage時
接著就會發生 IndexPage裡的 _onCastAdded 事件,
在這兒我們做一個Tweener的進場

當按下about的按鈕時, 要切換到 about場景
就會發生 IndexScene的 _onGogo事件
接著new RemoveChild把 IndexPage移掉
就會發生 IndexPage裡的 _onCastRemoved事件,
在這兒我們也是做一個Tweener的退場

退完場後, 才會進到 AboutScene裡的
_onLoad, _onInit事件。

Progression都是走這樣的模式。
因為是Command模式, 所以一定是一個Command跑完才跑下一個, 不會同時發生
要同時執行多個Command的話也是有這樣的類別。


有任何錯誤的地方, 歡迎請教討論。
SourceCodeDownload

補充:Progression內建的Tween類別是使用Tweener, 我將TweenMax包裝成Command類別,方便在Progression裡使用
請注意TweenMax的類別包喔,
舊版是:gs的package
新版是:com.greensock
package milkmidi.progression.commands.display {
import jp.progression.core.commands.Command;
import gs.TweenMax;
import gs.easing.*;
import gs.events.TweenEvent;
public class DoTweenMax extends Command {
private var _target  :Object;
private var _parameters :Object;   
private var _tweenMax :TweenMax;
private var _duration :Number;
public function DoTweenMax( pTarget:Object, pDuration:Number, pParameters:Object, pInitObject:Object = null ) {      
_target = pTarget;
_duration = pDuration;
_parameters = pParameters;     
super( _execute, _interrupt, pInitObject );
}
private function _execute():void { 
timeOut = Math.max( timeOut, _duration + 5000 );   
_tweenMax = new TweenMax( _target, _duration, _parameters);
_tweenMax.addEventListener(TweenEvent.COMPLETE , _complete, false, int.MAX_VALUE, true);         
if ( _tweenMax ) { return; }
executeComplete();
}   
private function _complete( e:TweenEvent ):void {     
_tweenMax.removeEventListener(TweenEvent.COMPLETE , _complete, false); 
executeComplete();
}
override public function executeComplete():void {
super.executeComplete();
_tweenMax = null;
}  
private function _interrupt():void { 
//trace("_interrupt");
_tweenMax.clear();      
interruptComplete();
}
public override function clone():Command {
return new DoTweenMax( _target, _duration , _parameters );   
}
}
}

留言

列夫 LINLI寫道…
感激老師,

這種的是好東西阿
烤焦餅乾寫道…
把cs4裡面的flash.swc copy到專案裡後,還能夠不透過fla直接使用progression裡用再命令模式中的Dotween.
不過命令模式是Progression最大的特色,
不知道奶綠老師能不能夠多分享這方面的心得?
milkmidi寫道…
hi,
請問什麼是CS4裡的flash.swc copy到專案呢?
你是想要在CS4使用Progression嗎
你可以安裝他的類別檔
或是安裝他的swc檔
http://progression.jp/download/3.1.62/Progression3-swc.zip
這兒可以下載Progression3的swc檔
烤焦餅乾寫道…
作者已經移除這則留言。
烤焦餅乾寫道…
因為我沒使用swc,直接使用類別目錄檔,
所以沒發現到他有把fl.transitions:Tween包裝在裡面了,

為了要用dotween,又只想使用sdk發布,
還特地把flashCS4中的flash.swc copy到專案...

用progression.swc就不用多此一舉了~
milkmidi寫道…
是的, 如果用他的.as檔
並沒有fl.裡的Class,
但用Progression.swc他就有包裝在裡面
我也都是用Flex SDK再發怖專案
Flash只是用來做元件
寫道…
老師你好,請問一下,如果我在一個Progression專案中載入一個swf,這個swf也是一個Progression專案的fla,載入後,原本場景上的物件出現感應區被擋住的問題,似乎是兩個Progression class互相干擾的問題,請問有甚麼解決辦法嗎?
milkmidi寫道…
prog = new Progression( 'index', stage, IndexScene );
把'index'換一個名稱
這樣就不會衝突了
匿名表示…
真的好好用!超感謝老師在課堂上實際帶我們操作!
milkmidi寫道…
不客氣,加油
Midi表示…
請問奶老大~
小弟習慣使用 TweenLite 來寫~
為什麼一直出錯???

是不是要先把 tweener 刪掉還是.....
我用 progression3.swc 會出錯耶~

我把檔案放在
src\libs\com\greensock
tween 效果都有出來~可以正常使用~
但就是會有錯誤訊息...

請問奶大有這類情況嗎?

感謝感謝~~~
milkmidi寫道…
Tweener和TweenLite可以共用
你出現的錯誤訊息是什麼呢?
HARDMOUSE寫道…
I can't find anywhere has actionscript. Only found a "/src/libs/Progression3.swc"? How do I edit *.as in progression?
milkmidi寫道…
我的demo是用FlashDevelop+swc發怖
你上線我再傳完整的as檔類別給你
Midi表示…
奶老大~我只要使用 TweenLite 就回出現以下錯誤?~ 感謝奶大幫忙解惑....

Error: Error #9028: Specified the object does not correspond.
Midi表示…
解決問題!會發生以下現象...
Error: Error #9028: Specified the object does not correspond.

我在創見專案的時候不要用 swc 輸出~
就一切正常了...

Progression 真的太好用了!!!
靈活、方便、快速!~~真是一大福音!!!

感謝奶大~這麼多篇教學~~小弟沒齒難忘~以身相許~~~....誰受的了?

再次感謝奶綠~
Midi表示…
請問一下奶綠大~

在 addCommand 裡不能用 TweenLite 耶...

真是又讓我陷入一陣錯愕......

不好意思~一直麻煩您~~~
milkmidi寫道…
我有將TweenMax寫成Progression Command
,我貼在上方,請享用
Midi表示…
首先瘋狂感激 奶綠大 分享 TweenMax Command !!!大鼓掌~~~

但您的程式碼運行似乎有兩個問題~請奶大幫幫忙~

1.在您的程式碼中我看已經有加入 import com.greensock.easing.*; 但沒有發揮作用~我必須在各頁面.as 還是要在 import 一次才有作用^^....

2._tweenMax.clear(); 這句也會造成錯誤!

以上是小地使用測試心得~感謝奶綠大~感謝~~
milkmidi寫道…
不好意思,因為我是使用舊版本的gs.TweenMax來製作,沒注意到新版的TweenMax會有這樣問題,謝謝你提供的資訊。
而每一個as都要import該類別是正常的
import是針該對隻as而不是針對整個flash應用程式喔
Midi表示…
沒錯~每個頁面可以依照要使用 easing 獨立崁入~對檔案大小也有幫助!!!

感謝奶綠大的教學!~~~感恩!~~
Midi表示…
請問奶綠老師~入門問題~(我很菜~)
全 class 寫動態定位 onResize
將語法寫在 index.as 只能定位 index入場的物件,請問我要怎麼動態定位 IndexPage 其他頁面的物件???

我換了好多種寫法...
都無法動態定位...

感謝奶綠老師解答!.... 一鞠躬!
milkmidi寫道…
每個可視物件,自已去偵聽stage的resize事件就可以了
Gray Liao寫道…
Dear 奶綠,請問一下,一般我們使用swfobject.embedSWF嵌入flash,只要設定一個attributes.id給他,js就可以呼叫到flash裡的function(透過ExternalInterface.addCallback),但透過progression.embedSWF,我好像怎麼設定都沒用,照理講它應該只是把這些參數再丟給swfobject.embedSWF才對呀?不知道你有沒有遇過這樣的問題?
milkmidi寫道…
我想一下,應該是正常才對,我之前也有用Progression+FBConnect,也是js as互call,你是用幾版的Progression呢,3還是4呢,我來查一下
Gray Liao寫道…
我是用3.1版的
馬克提供了這個http://blog.cuegraphix.com/?p=68
但我現在手邊沒檔案,明天再來繼續試了
感謝
milkmidi寫道…
我試了一下是可以的呀,不然你上線Q我,我把我試的檔案給你參看一下

這個網誌中的熱門文章

webpack2 入門實戰 1

大家好,我是奶綠茶
前端戰場不再只是寫寫 js / css , 各種框架、前處理工具百花齊放
身為前端工程師,不只要把程式寫完,還要寫好
老師說:選對好工具,事情就完成一半
如果你還在一隻 JS 打完全部程式,一隻 css 寫所有的 style
每次存檔還在手動 reload 網頁, 圖片壓 K 壓到不要不要的
透過奶綠伯的系列教學,讓你了解 webpack2 帶來的優勢
學會 webpack 可能不會加薪,但至少可以準時下班(誤)
1. 安裝 nodejs
請參考 gulp 安裝編

2. 安裝 global webpack , 筆者使用的是 2.2.1 版本
npm i webpack@2.2.1 -g
3. 在專案的根目錄放一隻 webpack.config.js
entry:你的主 js 進入點
output.filename:webpack 打包後的檔名
output.path:webpack 打包後的路徑
var path = require('path'); module.exports = { entry: './src/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
4. require , module.exports
現在前端都 module 化
可以每個獨立的功能都寫成單一的 js module
除了好管理,也方便讓團隊使用
寫一隻 module_exports_util.js
每隻經過 webpack 打包的 js , 都會是獨立的檔案
所以變數都是私有的, 外部成員都無法得到
在這個 module 裡,我們想開放二個函式
add , getName
所以在最後的 module.exports 指定
筆記加入 jsdoc , 為了方便在開發時,能夠有型別的提示

var name = "milkmidi"; /** * @param {number} num1 * @param {number} num2 * @return {number} */ function ad…

webpack2 入門實戰 3 scss,html,file-loader

大家好,我是奶綠茶
上一篇介紹了 webpack 的核心功能 loader
這篇再來補強各種常用的 loader
css-loader:解悉 css 檔
extract-loader:這個有點難翻,下面會介紹
file-loader:存成實體的檔案, 如圖片
html-loader:解悉 html 檔
sass-loader:解悉 scss 檔
url-loader:解悉圖片路徑
webpack.config.js
module.exports = { resolveLoader: { // 所有用到的 loader, -loader 可以不用打 moduleExtensions: [ "-loader" ], }, resolve: { // 在 require 檔案, 如果不想寫完整的路徑 // 可以加入這些目錄, 讓 webpack 自動尋找對的檔案 // 請注意我們加入了 src/img 路徑,後面會再介紹到 modules: [ path.resolve( 'src/html' ), path.resolve( 'src/img' ), path.resolve( 'src/css' ), path.resolve( 'src/js' ), path.resolve( "node_modules"), ], // 在 require 時可以不用打副檔名 extensions: [ ".js", ".scss" ] }, } 再來就是 loader 的介紹
scss
在這要做多組合的應用
先將 .scss 透過 scss-loader 轉換, 並產生 sourceMap 檔
再過 css-loader
最後再過 style-loader
{ test: /\.scss$/, // 多個 loader 組合, 可寫成一行,或…

Android完全入門篇-01 安裝SDK與裝置USBDriver

大家好,我是奶綠茶
筆者以 Windows 系統來介紹安裝
1. 下載 Android SDK
http://developer.android.com/sdk/index.html
有分 32 位元和 64 位元的版本
為了教學方便,筆者將檔案放置在 D:\ 下
壓開後會有
eclipse資料夾:Eclipse程式碼編譯器
sdk:Android 開發用的 SDK
SDK Manager.exe:sdk管理用的軟體


2. 開啟手機的"開發人員選項"
部份手機該選項被隱藏起來了
要開啟的話,點選"關於手機"
接著連點"版本號碼"七次,就會重新開啟該功能
接著再開啟"USB偵錯"功能
接上你的 USB 線後
這樣你的電腦才能透過 USB 線來偵錯手機的資訊
3. 為裝置安裝 adb usb driver
因為各家廠牌的 Driver 都不同也不通用,所以需要自行 Google 找 Driver
可以用"XXX廠牌 型號 adb usb driver"關鍵字來找
例:HTC Newone adb usb driver
接著找到 我的電腦 / 內容


裝置管理員

會看到一個金嘆號未知的裝置, 按右鍵更新驅動程式軟體

選擇"瀏覽電腦上的驅動程式軟體"

完成後就會看到裝置啟動,並出現 XXX Android ADB Interface

4.測試是否連接成功
進入到第一步下載的 sdk 資料夾裡
D:\adt-bundle-windows-x86_64-20131030\sdk
然後在 platform-tools 資料夾上按住 Shift 鍵,然後再按滑鼠右鍵
選擇"在此處開啟命令視窗"
(此功能只有 Win7 之後的版本才支援, XP使用者就要自行輸入 dos 指令進入到資料夾)
輸入 adb devices
如果看到一串數字,並顯示 device 就表示連線成功
5.新增環境變數(選擇性設定)
為了方便的使用 adb 指令
可以為 windows 設定變數
開啟我的電腦 / 內容 / 左邊的"進階系統設定"
點選下方 環境變數

下方系統變數,找到 Path的選項,按下編輯

在變數值欄位的最後方加入
;D:\adt-b…