有點概念了吧? 接下來我們繼續探討 Flash 可以認識的事件, 在六十幾類事件(Event 的子類別有六十幾個!)中, 最常見的就是滑鼠事件(MouseEvent)這類事件囉。 滑鼠事件(MouseEvent) 有哪些 ? 通常使用者會用滑鼠與我們的Flash影片或動畫互動, 所以Flash程式中最常用的就是滑鼠事件了, 如果是手機(要安裝Adobe AIR)則是手指觸控事件。 滑鼠事件(MouseEvent)是一個類別, 其完整名稱是: flash.events.MouseEvent.class 目前這個類別內共定義了十七種滑鼠事件(也就是說 MouseEvent 這 class(類別)內定義了17種滑鼠事件!), 以下列出常用的八種滑鼠事件: flash.events.MouseEvent.OVER 滑鼠滑入 flash.events.MouseEvent.MOUSE_DOWN 滑鼠按下 flash.events.MouseEvent.MOUSE_UP 滑鼠放開 flash.events.MouseEvent.CLICK 滑鼠按一下 flash.events.MouseEvent.RIGHT_CLICK 滑鼠右鍵按一下 flash.events.MouseEvent.OUT 滑鼠滑出 flash.events.MouseEvent.MOUSE_MOVE 滑鼠移動 flash.events.MouseEvent.MOUSE_WHEEL 滑鼠滾輪事件 滑鼠事件之外還有啥事件(Event)? 應該說到底可能發生甚麼事? 你想浪費時間去追根究底了解所有的Flash事件? 也就是整個 flash.events 套件(package)內有哪些類別? 各類別內又有幾種不同事件 ? 蔡神要告訴你"賣憨啦!" (台語, == 別傻了啦 == Don't be silly !) 因為這是不需要且很浪費時間的一件傻事! 重要的是概念! 知道大概的概念就可以啦! 當然, 如果你很好奇則可以隨便看看相關API手冊, 也不必仔細看啦 :-) 請注意, 上面我們只是把"滑鼠事件"(MouseEvent)這類別的常用事件列出, 其實光是滑鼠事件這類(class)就有十七種事件, 而滑鼠事件(MouseEvent)只是六十幾個事件類別(從 Event 衍生出六十幾種類別)中的一類, 所有這六十幾個類別(class)被放在同一個目錄 flash\events 內, 在ActionScript3.0這個 程式語言稱作 flash.events 套件(package), 所以我們常說 package 套件必須反應目錄架構; 意思是如果套件 package 是 ggg.yyy; 則必須放在目錄 ggg 之下的子目錄 yyy 內! 你可以點看以下官方網址查看所有這六十幾種事件類別(Event class): http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/events/package-detail.html 如果你只想看看有哪些滑鼠事件(MouseEvent), 請點看以下網址: http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/events/MouseEvent.html#constantSummary 滑鼠事件是由使用者引起的, 有一個最常發生但不是使用者引起的事件, 其全名如下: flash.events.Event.ENTER_FRAME 如果你去查手冊, 你會發現它是一個字串常數 "enterFrame", 這個事件目前的Flash版本每秒會自動發出 24 次(早期版本每秒12次), 原因是Flash播放影片的速率是每秒24個影格, 剛好符合肉眼視覺暫留的效果。 請注意, 即使畫面看起來沒在動, Flash 仍會以每秒24個畫面的速度進行播放, 所以, 這個 ENTER_FRAME 的事件是每二十四分之一秒會發生一次。如果你希望每 當一個畫面要播放或者說每24分之一秒要做一件事, 就可以利用註冊監聽這個事件。 如果你需要更精準的時間, 例如每秒要做一次, 或每秒要做十次甚至一百次, 那你必須利用計時器類別 flash.utils.Timer 所發出的 TimerEvent (flash.events.TimerEvent), 也就是像你在真實世界去買個可以設定時間的計時器, 時間到就發出時間事件: Timer timer = new Timer(多久發一次事件, 總共要發出幾次); Timer myTr = new Timer(100, 58); // 每千分之100秒一次, 總共要 58 次 上面第二列會創建一個計時器 myTr (等於去買來一個計時器), 設定為每十分之一秒"叫一次", 總共會叫58次; 也就是說, 該計時器每次時間到就會發出 TimerEvent.TIMER 事件, 達到總共要發出幾次的次數則會發出 TimerEvent.TIMER_COMPLETE 的事件; 因此, 你可以充分利用註冊監聽該兩個計時器事件做一些不斷需要做的事, 例如: myTr.addEventListener(TimerEvent.TIMER, him); // 根據前面計時器是每秒十次 myTr.addEventListener(TimerEvent.TIMER_COMPLETE, you); // 計時結束 注意, 註冊完之後, 別忘了要啟動計時器: myTr.start( ); 不然你等於買了計時器卻沒裝上電池 :-) 上述兩句註冊監聽搭配前面 new Timer(100, 58) 的意思是說每十分之一秒會叫用函數 him( ) 一次, 總共會叫用 58 次, 第58次數完之後, 會叫用函數 you( ) 一次; 當然, 如果還沒達到發出 TimerEvent.TIMER 58次之前你撤銷了監聽註冊: myTr.removeEventListener(TimerEvent.TIMER, him); // 撤銷監聽 那就不會繼續叫用 him( ) 這函數; 不過, 要注意 myTr 這 Timer 仍會繼續數, 直到數完58次還是會發出TimerEvent.TIMER_COMPLETE事件 你有兩個方法可以撤銷這個監聽命令, 第一個方法跟剛剛一樣: myTr.removeEventListener(TimerEvent.TIMER_COMPLETE, you); 第二個方法就是直接把計時器 myTr 停掉: myTr.stop( ); 因為, 既然計時器都停了, 那些監聽註冊自然失效 :-) 事件也可以是自己定義的事件, 名稱是自己定義的任意字串, 甚至還可以取中文喔 :-) 自己定義的事件註冊捕捉事件時只要使用字串表示, 但發出事件則要使用如下句子: dispatchEvent(new Event("你的事件名稱")); 這裡 new Event( ) 是製造出一個事件(也是一個物件), 然後由 dispatchEvent( 事件物件 ); 這個方法(Method, 又稱函數function)把事件丟出去(發出去)。 所以稱作"丟出去"是因為 C++ 和 Java 都是使用 throw 把事件發出去!! dispatchEvent( 事件物件 ) 這個函數(方法)是寫在 IEventDispatcher 這個介面(Interface)裡面, 關於該函數詳細的說明請看以下網址: http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/events/EventDispatcher.html#dispatchEvent() 因為幾乎所有的類別都直接或間接實作(implement)了該介面, 所以幾乎所有物件都可使用該函數發出事件。 簡單的說, 你想發出事件就寫該句子, 如果 Flash 編譯器說有問題再來研究 :-)Top回來繼續探討怎麼寫 Flash 的簡單程式! 既然說如果發生"某事件"就要請 處理函數 做事, 那我們就必須把 處理函數 準備好, 你可以寫在這影格之前, 或直接寫在該句下方即可: stop( ); ggyy.addEventListener("某事件", 處理函數); function 處理函數(e: Event) { // 處理函數的名稱必須是英文, 第一個字母請用小寫 // 做事... } 通常要做的事情也不多, 你只要知道幾句常用的以及有一點點邏輯概念即可! 甚麼邏輯概念喔? 阿就是要會像這樣: 如果(下雨了) 打開雨傘( ); // 注意尾巴有括號表示是方法(或稱為動作或函數) else 大聲叫出("我要乘風破浪!"); // 顯然 大聲叫出 也是函數 然後翻譯為英文(歹勢, 不支援用中文文法寫程式:-) if( isRaining ) openUmbrella( ); // openUmbrella( ) 是一個方法或稱函數(函式) else cry("我要乘風破浪!"); // cry 也是一個函數, 接受一個字串當作參數(給它用的資料) 現在寫一個簡單的範例:上面這個程式會使得目前這影格停留大約 2 秒之後進入下一個影格! Why 這樣就會停大約兩秒 ? 因為 stop( ); 使其停在目前影格, 可是目前的 Flash 版本每秒鐘播放24個影格(24fps), 所以每 24 分之一秒會發出一次的 flash.events.Event.ENTER_FRAME 事件, 這使得 haha( ) 這函數每秒會被執行大約24次, 所以當 kk 累積到 51 之時因為大於 50 就會執行 nextFrame( ); 這函數! 此時大約 2 秒多一點點, 因為 51/24 大約 2.1, 所以大約2秒; 所執行的nextFrame( );是內建的函數(也可以說是Flash的命令), 會使得播放磁頭移往下一個影格(Frame)! 如果你把 nextFrame( ); 改為 nextScene( ); 則會跳到下一個場景(Scene)的第一個影格! 又, 如果你把 nextFrame( ); 改為 gotoAndStop(38); 則會跳到總影格的第 38 影格並停在該影格。 所謂總影格意思是從第一場景的第一影格數 1, 不分場景, 連起來一直往下數到第38影格。 如果你是用 gotoAndPlay(38);則是跳到總影格第38影格並繼續播放! 當然, 如果你在第38影格某個圖層有寫 stop( ); 則會停在該影格!
stop( ); var kk: int = 0; // 記憶體放個變數 kk, 是整數, 先放入 0 addEventListener(flash.events.Event.ENTER_FRAME, haha); function haha(e: Event) { // haha是 處理函數 名稱, 第一個字母請用小寫 ++kk; // 每次加 1 if(kk > 50) nextFrame( ); // 如果 kk 大於 50 就跳到下一個影格 }
有點概念了吧? 前面說過, 撰寫程式(programming)就好像你要教一個很聽話但沒主見的小孩子(電腦)做事, 你說甚麼他就做甚麼, 完全照你的"規劃"(program; 計畫, 又翻譯為程式)一步一步做! 只是因為電腦很快, 於是就可以做出看起來很厲害的事情了。Top函數(Function)是甚麼碗糕? 為了方便, 把幾句命令集合在一起, 給他取個名字, 以後方便使用, 這就是函數了; 習慣上函數名稱的後面有一對小括號, 裡面夾著 0 個到很多個參數(Parameter)。 其實前面已經談到很多關於函數的議題, 前面一開始寫的 him( ) 或是內建的 nextFrame( ) 以及 移動播放頭的 gotoAndStop( ) 與 gotoAndPlay( ) 都是函數(function; 函式)。 撰寫程式一定要善用立法委員包工程的概念與大哥叫小弟做事的概念! 爹公蝦密咧? 立委包了工程大部分都是轉包出去(函數:-), 大哥出一張嘴巴也都叫小弟(也是函數)去做事! 甚至有錢人家裡請許多外勞(有算是函數)幫忙做事! 所以我們可以把工作拆解為許多函數, 然後只要依序叫用各個函數就可以完成我們要的工作了。 請注意, 函數(Function; 函式; 又稱 Method, 方法)自己不會自動執行, 整個函數可被當作一個命令使用, 用到了才會跳過來進入函數執行, 函數結束又回到叫用它的敘述之下繼續執行, 使用函數很簡單, 只要寫函數名稱接著一對小括號( ), 例如 gotoAndStop(38); 小括號內可以放 0 個到很多個參數(argument; 引數)以便傳入函數內讓函數參考! 剛剛提到的參數(Parameter), 在使用函數者把要傳過去的稱 argument (引數), 在接受參數的函數頭部則稱之為 parameter (參數), 或稱 formal parameter (形式參數); 不過一般都是通稱參數(Parameter)。 以下是叫用 myCntDown 所屬類別的 start 函數: myCntDown.start(8, "時間到"); 這句傳了兩個參數(引數)過去, 第一個 8 是整數, 應該是希望倒數八秒, 第二個參數是字串"時間到", 應該是希望算完發出(dispatch)一個"時間到"事件 (Event)。 當然, 在 myCntDown 所屬的類別(class)裡面一定要有可接受該兩參數的 start(int, String)函數。 函數(function; 又翻譯為函式), 又通稱為方法(Method), 代表一連串動作(Action), 或者說代表一系列的行為(behavior), Flash 規定函數的寫法一定是用關鍵字function 開頭, 然後是你的函數名稱, 接著用括號夾住 0 個到多個參數(parameter), 如果是註冊用來處理某事件用的函數, 則一定要有一個參數, 例如一開始的 him( ); 且其型別(type)一定是 Event 或是 Event 的子類別(sub class), 例如 MouseEvent(滑鼠事件) 便是 Event 眾多子類別中的一種。 然後是可有可無的 : returnType 代表要回傳啥資料? (上面例子因沒寫, 相當於寫 : void 代表不必回傳任何資料!) 最後則是用一對大括號 { } 夾住一系列的命令或句子。 函數名稱通常可以隨便取, 但請遵守函數與變數的命名慣例(開新窗)。 請注意, 有些語言或遊戲引擎採用 Framework 的概念, 就是函數名稱是規定死的, 例如 Java 語言的事件處理函數, 名稱都是固定的, 連大小寫以及參數型別和數量都必須照規定; 又如Unity遊戲引擎, 最常寫的函數是 Update, Start, 總共有五十幾個規定好名稱但我們可以寫的函數, 要注意 Unity 函數命名習慣不同, 我們可以重寫蓋掉的該五十幾個函數名稱第一個字母都是大寫。 更多關於 Unity遊戲引擎所用腳本語言API可點這連過去看(開新窗) 世事真的難料要預防意外(Exception Handling) 前面我們說在"規劃"讓電腦做事已經會考慮不同情況, 所以會善用 if 敘述事先規劃不同情況做不同的事情。 但是, 有時會發現世事真的難料, 某段程式可能因考慮不週會在執行階段出槌導致程式當掉! 為了避免程式死得不 明不白, 我們可以採去預防措施, 以下是 Flash 程式的寫法:如果是 Java 程式, 則應該這樣寫:
try { //... 這是可能出槌的程式碼 //.. 夠認真應該一個 try block 只夾住一句可疑的敘述 //.. 偷懶就夾住一整段 :-) }catch( e: Error) { trace("有問題囉 ... "); }這種事先無法利用 if 把問題或狀況排除, 只好用 try block 夾住一段可能出問題之程式碼的做法有個專有名詞, 稱作例外處理(Exception handling; 意外處理; 異常處理)。有了這招, 我們就可確保程式只要編譯階段沒有錯, 就 不會在執行階段 (Run time)當掉, 不過請注意, 不會當掉不表示沒問題, 如果你沒把問題找出並解決, 那只是學鴕鳥喔! 程式語言有哪些敘述(Statements; 指述)可用? 用來寫程式的句子稱作 statement, 翻譯作指述(指令的描述)或敘述, 或乾脆說是一句話也可以, 那程式語言(電腦語言)到底有多少句話可以用呢? 其實不多, 如果你是從最前面看到這, 阿那個.. 其實你已經看過全部的敘述(Statements; 指述)。 真的嗎? 當然是真的, 現在就來個總整理。
try { //... 這是可能出槌的程式碼 //.. 夠認真應該一個 try block 只夾住一句可疑的敘述 //.. 偷懶就夾住一整段 :-) }catch(Exception e) { System.err.println("有問題囉 ... "); e.printStackTrace( ); // Log.d("某處", "發生了問題 ..."); // 這是 Android 的 Java }真的只有這些嗎? 可是各電腦語言的手冊都好幾百頁ㄟ ! 別懷疑, 真的只有以上這些! 何況前面不是說過, 阿那些作曲家不過就是把 1 2 3 4 5 6 7 兜來兜去, 就可以搞出那麼多曲子, 阿程式設計當然也只要幾句兜來兜去就很厲害了:-) 至於其他一堆有的沒的, 都是程式庫(Library)啦, 自從 Java 語言出現之後, 大家都把程式庫越搞越大, 包括一些預先準備的物件(Objet)以及類別和函數, 也就是通稱的 API (Application Programming Interface)啦。
各家電腦語言大約有百分之八十以上的相似度, 可以使用的敘述共分為以下八類: (1)註解(Comment), 就是寫給人看的, 通常有兩種: // 這兩斜線之後直到一列結束都是註解 /* 這個註解可以橫跨很多列, 直到遇見 星號緊跟著斜線 */ (2)宣告(Declare)/定義(Define) 變數與常數 int kk = 38; // Java 定義一個整數並給初始值 38 var kk: int = 38; // Flash 定義一個整數並給初始值 38 (3)運算式(Expression): 數學運算式、關係運算式、邏輯運算式 可以點這看看有那些運算符號(Operator; 運算子) (4)設定值(指定值)敘述(Assignment statement) 用等號 = 把等號右邊的運算式之答案放入等號左邊變數 嚴格說來這可以不算一類, 因為等號 = 也算是一個運算符號。 (5)宣告/定義 函數(function; 函式); Flash 的函數前面已經介紹過, 以下是 Java 的函數範例: void him(Event e) { // void 表示不會回傳任何資料 // 做事... } (6)定義類別(Class) 就是把資料以及與資料有關的函數包到一個類別(class)內, 以便當作物件來使用, 物件的概念也是仿照真實世界! 關於物件導向概念請點這連過去看(開新窗) (7)複合敘述(Compound statement), 把很多敘述用左大括號與右大括號夾住當作一句, 各句以分號隔開 { 第一句; 第二句; 愛幾句都可; 最後一句不必寫分號} 嚴格講起來這也不算一類 ! (8)控制敘述(Control statement) 讓程式執行順序不是照著寫的順序 (a)叫用函數(call a function; 調用函數) (b)if 敘述(if statement), 又稱選擇敘述(Selection statement)或 Alternative statement 包括 if .. else 以及多重 if 甚至功能類似的 switch .. case 都算這類選擇敘述。 (c)迴圈(Loop)或稱重複敘述(Repetition statement): 就是前面討論過的 for Loop, while Loop, 以及用不太到的 do while 敘述。 (d)例外處理 (Exception handling) 就是前面剛討論過的處理世事真的難料之事
點這看Flash ActionScript 3.0 程式設計手冊(開新窗) 點這看 Java SE APIs onLine (6.0)(開新窗) 點這看關於 Unity遊戲引擎所用腳本語言API可點這連過去看(開新窗)Top
Flash拖拉物件放掉後如何知道放在啥東西上? 很多人會以為這是碰撞偵測(collision detection), 其實不是! 這只是看看你停止拖拉(stopDrag)之後, 到底把物件放在哪個"顯示物件容器"上, 所以正確的做法是檢查你的 dropTarget, 例如: if( haha_mc.dropTarget.parent.name == "backware") { // do something } 請注意, 不要寫成 if( haha_mc.dropTarget.name == "backware") ... 這樣永遠不會查得到! 原因是它有"容器"的概念! 甚至, 如果 target 物件很複雜, 你可能要寫成以下這樣才查得到: if( haha_mc.dropTarget.parent.parent.name == "backware") { // do something } 點這看 Adobe AS3 flash.display.DisplayObject 顯示物件類別的 參考手冊 點這看 Adobe AS3 flash.display.DisplayObjectContainer 顯示物件容器類別的 參考手冊Top
Flash碰撞偵測 hitTestObject(物件) 與 hitTestPointer(X座標, Y座標) 在 AS2 時代的 hitTest( ) 函數到了 AS3 被拆開為兩個函數: hitTestObject(物件); 與 hitTestPointer(X座標, Y座標); hitTestObject: 判斷影片片段和指定物件的的範圍框是否有重疊或相交。 因為其實物件都是方形範圍, 所以有時看起來沒碰撞也會被偵測為已經撞到! 範例: if( my_mc.hitTestObject( your_mc ) { // 撞到了, do something } hitTestPoint: 顧名思義, 只偵測一個點是否在物件的形狀範圍內; 這時你可以給第三個參數為 true 以便真的只偵測有像素部份, 例如: if( my_mc.hitTestPointer( mouseX, mouseY, true) { // do something } 但是這只對於向量圖有效, 如果是點陣圖(bitmap; .bmp檔案)則沒有用, 仍是偵測方型範圍。 更多關於碰撞偵測的範例與進階討論, 請點以下網址連過去看: http://sierakowski.eu/list-of-tips/39-collision-detection-methods-hittest-and-hittestobject-alternatives.htmlTop 善用程式碼片段 (Code Snippets) Flash 已經把許多常用的"動作"寫成程式碼片段(Code snippets), 例如按一下前往網頁, 按一下跳到某影格, 甚至倒數計時範例或水平動畫, 垂直動畫等等, 都可以彈指之間就生出來! 請點這裡看相關說明。 甚至, 我們還可以自己蒐集定義自己常用的ActionScript3.0 程式碼片段, 詳細的說明請點這連過去看"如何自己定義程式碼片段"。(開新窗) 可以把這個我寫的程式碼片段 godSnippets.xml 抓回你電腦(按滑鼠右鍵另存新檔), 然後從你的Flash動作面板匯入它。 善用程式碼提示 (Code Hint) 如何善用 程式碼提示(Code Hint)? 很簡單! 當然你還是得先打入前面幾個字母(這時可不必管大小寫)! 最簡單就是先打入 goto 接著去點按 有個左括號連著說明圖示的 "顯示程式碼提示" 然後會看到所有 goto 開頭可以用的語句, 其實也只有 gotoAndStop( 和 gotoAndPlay( 兩句子可選啦 ! 在希望選的項目上滑鼠連敲兩下即可 !
看到了吧: 原來寫程式很簡單:-) 每次只要敲幾個似曾相似的英文字 :-)) 以剛剛舉例的練習來說, 這次只要會敲 goto 然後去點按那個顯示程式碼 阿就可以選到你要的命令! 至於該命令的詳細語法則輕輕點一下該命令的英文字, 然後立刻敲 F1 就可以看到說明 !
再看看以下例子... 以下則是自動產生的喔! 利用了Code Snippets(程式碼片段), 以及"顯示程式碼提示"功能! (注意以下的程式碼是自動產生在場景一的 Actions 圖層的最後一個影格) 當然我有打入一列程式碼: 先打了 goto 然後立刻去點那個"顯示程式碼提示", 接著點兩下選想要的!gotoAndStop( 參數 ) 與 gotoAndPlay( 參數 ); 這兩個函數很常用! 阿如果不知道 gotoAndStop( ) 的括號內的參數意義, 可以先在 gotoAndStop 這字輕點一下, 然後立刻敲 F1 功能鍵, 就會把 HELP 視窗叫出來且顯現 gotoAndStop( ) 這函數所需之參數以及其意義! 會寫 Flash 程式 (Action Script 3)的薪水絕對不止 22K 喔! Flash 高手(會畫畫又會一些 ActionScript 3)大學畢業起薪至少五萬元! 大家加油囉!
如果你已經看了三遍但仍有些地方看不太懂, 那就先不要管它了, 大概知道個概念即可, 有些以後看到其他相關的自然就會懂了 :-) 原則上, 儘量用真實世界的角度去思考, 因為物件導向(Object Oriented)概念就是參考真實世界的現象設計的。
Top看完這篇程式設計概念的文章之後, 你最需要的應該是稍微了解一下物件導向(Object Oriented)的概念! 想知道更多關於物件導向程式設計(Object Oriented Programming)概念的請按這連過去看。 (會蓋掉此篇, 但你可以點按視窗左上角的回到這篇)