幀迴圈
幀迴圈的理念,存在於 Flash 最早的版本中,那時 ActionScript 還不像今天那麼強
大。把代碼寫入主要畫面格,並在下一幀中寫入像 gotoAndPlay 這樣的語句,使播放頭(playhead)
回到前一幀。這樣兩幀之間就形成了一個無限迴圈,每當播放頭到了代碼幀上時,就會執行
那些代碼。例如,在舞台上有一個執行個體名為 ball 的影片剪輯。
第一幀的代碼就像這樣:
ball.x ++;
第二幀的代碼如下:
gotoAndPlay(1);
實際上第二幀不需要做任何事,只是讓時間軸自動回到第一幀而以。另一個版本是建立
三個幀,第一幀進行初始化,寫入只執行一次的代碼,不進行迴圈。第二幀才是主要的執行
代碼,第三幀唯寫 gotoAndPlay(2); 這個方法在早期 Flash 版本中常被使用,雖然有點過
時,但是同樣可以出色地完成任務。馬上我們還要學到更靈活更強大的設定方法,但今後你
會發現其實原理上是一樣的。
影片事件
影片事件在 AS 3 中徹底的消失了,這真是件好事。但還要捎帶提一下,回顧 Flash 5
的時代,只有幀迴圈和影片剪輯事件兩種選擇。影片事件指代碼直接寫在影片剪輯上,而不
是幀上。如何?影片事件,首先選擇舞台上的影片剪輯,然後開啟動作面板並將代碼寫在
上面,這些代碼只對該影片剪輯有效。所有代碼必需寫在事件塊中,比如:
onClipEvent(eventName){
// code goes here
}
對於 onClipEvent(eventName),作用於 eventName(某種事件)。對於"on"類型事件則
必需指定滑鼠或鍵盤事件,如按下(press)和釋放(release)。
事件名稱(eventName)是指許多 Flash 影片事件之一,所謂事件就是在影片中發生的
事。事件分為兩種:系統事件和使用者事件。系統事件指發生在如電腦,Flash,或影片上
的事件,比如調取資料,調取資訊,或播放幀等。使用者事件是指使用者所做的一些事,基本上
就是滑鼠和鍵盤兩種。 影片事件使用得最多的就是 load 和 enterFrame 這兩個。 Load 事
件會在影片第一次出現在舞台上時才執行, 且只執行一次。 所以說非常適合在這裡面寫入初
始化代碼。只要把代碼寫在大括弧間即可:
onClipEvent(load){
// initialization code
}
我們可以把帶有如下代碼的影片剪輯放入時間軸上(注意:此處為 AS 1 寫法):
onClipEvent (load) {
this._x = 100;
this._y = 100;
}
onClipEvent (enterFrame) {
this._x += 5;
}
本書樣本中的代碼不使用這種寫法(因為它已經不是一種語言了),但不論使用何種方
法, 初始化(initialization),重複動作(repeating actions)和螢幕重新整理(screen refresh)
都是非常重要的。
事件及事件處理
Flash MX 的 ActionScrpt 發生了重要的改變,這些轉變與革新為 Flash 成為真正的
富用戶端程式(RIA)奠定了基礎。其中一個就是全新的事件結構,在編寫非常複雜的行為時
比之前的版本好用很多。 Flash MX 之前的版本,只能把代碼放在影片和按鈕的
onClipEvent(eventName) 或 on(eventName) 這兩種事件處理方法中。這就意味著,在設計
的時候就要把影片剪輯放到舞台上,並把代碼寫入影片剪輯中。MX 的事件結構並不完美,
但與之前版本來說已經有了長足的進步,並允許我們在任何時候訪問任何事件,或是停止處
理任何事件,或是動態改變某個事件的行為,可以想象這有多麼的強大和靈活。
要想瞭解事件,就要明白下面幾條概念:接聽程式(lintener)與處理函數(handler),這
兩個名字很貼切,接聽程式就是偵聽事件的對象,處理函數是一個用於處理所要發生的事件的
函數。偵聽與處理在 ActionScript 的發展過程中進行過很多次演變,在 AS 2 中就有很多
不同的實現方法。為了避免混亂,我很推崇 AS 3,因為它簡化了這個過程,使事件處理變
得更方便更一致。
事件接聽程式與處理函數
前面說過,接聽程式是一個用於偵聽事件的對象。我們可以設計一個類,通過調用
addEventListener 函數為某事件指定一個接聽程式。輸入要偵聽的事件名稱以及要執行處理
的函數名稱。看一個例子:
addEventListener("enterFrame", onEnterFrame);
在加入事件接聽程式時,可使用選擇性參數,本書中不會用到;對於大多數的應用程式來說,
會使用以上這種寫法就夠用了。請注意事件名"enterFrame"為字串型,戲稱它為“魔力字
符串”(Magic String)。為什麼這麼叫?如果你誤輸入成了"entorFrame",儘管沒有這個事
件名稱,編譯器也會編譯執行它,會發現事件處理函數沒有執行。但 AS 3 仍會對其進行處
理,除了使用“魔力字串”以外,還可以使用事件類別(Event Class)的屬性。例如:
addEventListener(Event.ENTER_FRAME, onEnterFrame);
實際上 Event.ENTER_FRAME 的值就是”enterFrame”這個字串。那麼這個屬性也可
能輸錯就像 Event.ENTOR_FRAME ,但這種方法好在,如果輸入錯誤了,程式會拒絕編譯,
並提示你在事件類別中不存在該屬性。編譯器會提示發生錯誤的行及確切的字元。所以,最好
使用這種方法,除非編譯器會幫我們修正錯誤或編寫代碼。
除此之外,還有其它的事件類型如:MouseEvent.MOUSE_DOWN,KeyboardEvent.KEY_DOWN,
TimerEvent.TIMER 等。這些都由 "mouseDown" , "keyDown" , "timer" 這樣的簡單字串
來表示,如果你記不住這些字串,那麼最好就去使用事件類別的屬性。
另一個重點是,使用 addEventListener 函數直接調用類中的函數。有時,需要偵聽另
一個對象產生的事件,例如,有一個名為 mySpriteButton 的 Sprite 影片(Sprite):影片
或按鈕,能完成按鈕的動作。當使用者點擊它的時候就會產生 mouseDown(滑鼠按下)事件。偵
聽該 Sprite 影片的 mouseDown 事件, 就要調用該對象的 addEventListener 方法,如下:
mySpriteButton.addEventListener(MouseEvent.MOUSE_DOWN, onSpritePress);
最後一點,必需要有事件處理函數如 onEnterFrame,在 AS 3 中,可以任意地為事件
處理函數命名,這點與以前的 ActionScript 不同。在 enterFrame 樣本中,使用
onEnterFrame 做事件處理函數, 是因為我們習慣使用這個名稱。 AS 3 中,
在 onEnterFrame
已不再是關鍵字,當然也可以為這個處理函數命名為 move,run,或是 doSomethingCool。
然而,我們已經習慣使用”on”表示事件開始,後面跟一些描述詞如 onStartButtonClick,
onConfigXMLLoad 或 onRoketCrash。有些朋友喜歡在事件名後面加上 "Handler" 作為後
綴,如: enterFrameHandler,這隻是個人偏好問題。
接聽程式用於偵聽事件,但對於一個接聽程式來說,也許會同時偵聽很多事件。在系統內部,
一個事件對象擁有一個包括了所有對象及自身的接聽程式的列表。 如果一個對象能夠產生多種
不同類型的事件,如 mouseDown,mouseUp,mouseMove 等,那麼它就擁有一個接聽程式列表,
其中包括它所涉及的所有類型的事件。無論觸發何種事件,都會檢索一遍列表,然後使列表
中的每個對象都知道所發生的事件。
另一種對事件的描述是, 將其看作一個加入到事件行列的接聽程式成員。產生事件的對象將它
所產生的事件公布給所有成員, 當你不再需要這個對象進行偵聽時,可以令其停止偵聽或使
用 removeEventListener 方法解除該成員;就是告訴對象從接聽程式列表中刪除該接聽程式,
這樣一來,他就不會再接收資訊了。
讓我們看看這段代碼,下面是一段在舞台中建立 Sprite 影片,並進行繪圖,然後再為
其添加接聽程式的代碼:
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
public class EventDemo extends Sprite {
private var eventSprite:Sprite;
public function EventDemo() {
init();
}
private function init():void {
eventSprite = new Sprite();
addChild(eventSprite);
eventSprite.graphics.beginFill(0xff0000);
eventSprite.graphics.drawCircle(0, 0, 100);
eventSprite.graphics.endFill();
eventSprite.x = stage.stageWidth / 2;
eventSprite.y = stage.stageHeight / 2;
eventSprite.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
eventSprite.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
}
private function onMouseDown(event:MouseEvent):void {
trace("mouse down");
}
private function onMouseUp(event:MouseEvent):void {
trace("mouse up");
}
}
}
在初始化函數(init)中建立一個 Sprite 影片,並在裡面畫圓,置於舞台中心,最後兩
句是為它添加兩個接聽程式,偵聽滑鼠按下(MOUSE_DOWN)和滑鼠彈起(MOUSE_UP)這兩個事件。
它們是 MouseEvent 類的兩個屬性,而這個類必需要匯入。最後定義兩個處理函數
onMouseDown 和 onMouseUp。
由事件對象呼叫事件處理函數,通常還會包括一些事件資訊。在處理滑鼠事件時,就包
括觸發該事件時滑鼠位置的資訊如:滑鼠點擊在按鈕上。對於鍵盤事件,就要包括按下鍵時
的資訊如 Ctrl,Alt,Shift 等。把上述樣本儲存為 EventDemo.as 檔案,並選擇一種前面
講過的編譯方式。當運行 SWF 時,就會看到每次點擊或圖形時,都會輸出 pressed 或
released。
動畫事件
我們希望能夠使用代碼讓物體動起來,並允許螢幕反覆地重新整理。前面看過一個使用
enterFrame 影片事件的樣本。現在把這種方法運用到 AS 3 中,只需要增加一個
enterFrame 事件的接聽程式即可:
addEventListener(Event.ENTER_FRAME, onEnterFrame);
別忘了匯入 Event 類,並建立一個名為 onEnterFrame 的方法。人們常常迷惑,只有
一幀怎麼能執行 enterFrame(進入幀) 事件呢?事實上,播放頭並非真正地在進入下一幀,
它只停留在第一幀上, 並不是把播放頭移動到下一幀才形成了 enterFrame 事件,而是用另
一種方法:Flash 告訴播放頭何時進行移動,可以把 enterFrame 看成一個定時器,只是有
些不精確。
下面我們看看第一個 AS 3 動畫:
package {
import flash.display.Sprite;
import flash.events.Event;
public class FirstAnimation extends Sprite {
private var ball:Sprite;
public function FirstAnimation() {
init();
}
private function init():void {
ball = new Sprite();
addChild(ball);
ball.graphics.beginFill(0xff0000);
ball.graphics.drawCircle(0, 0, 40);