flahs as 無基礎(chǔ)入門經(jīng)典教程
做過Flash動畫的Flash愛好者們都知道,要做好一個Flash動畫,AS是必不可少的,即使只是很簡單的幾句代碼也能起到整個Flash畫龍點(diǎn)睛的作用。這里我只簡單的介紹一下AS的基本常識。 首先我們要了解AS要寫在什么地方,什么時候AS會被觸發(fā)執(zhí)行。 1、幀: 寫在關(guān)鍵幀上面的AS,當(dāng)時間軸上的指針走到這個關(guān)鍵幀的時候,就寫在這個幀上面的AS就被觸發(fā)執(zhí)行了。常見的例子有在影片結(jié)尾的幀寫上 stop() 等。操作方法就是點(diǎn)選關(guān)鍵幀,然后打開AS面板。 2、按鈕: 不同于幀上面的AS,按鈕上面的AS是要有觸發(fā)條件的。要把AS寫在按鈕上,操作方法是點(diǎn)選目標(biāo)按鈕,然后打開AS面板。舉個例子能說的更明白。 假設(shè)有一個動畫,要讓它在播放完同時停止,那么,你要做的就是在這個動畫的最后一幀寫AS stop(); 再假設(shè)有個按鈕,效果是按下按鈕后停止播放,那么步驟如下。 做一個按鈕,放到主場景,點(diǎn)選按鈕,然后打開AS面板。現(xiàn)在如果也在按鈕上寫 stop(); 那么,輸出的時候就會提示錯誤。正確的應(yīng)該這樣寫 on(release){ stop(); } 這里要比幀的動畫多這些代碼: on(release){} , 整個代碼翻譯過來就是: 當(dāng)(松開){ 停止 } 紅色的代碼表示鼠標(biāo)的觸發(fā)事件事件之一,這里用的是 release 松開,按鈕的常用事件: release 松開 releaseOutside 在按鈕外面松開 press 按下 rollOver 鼠標(biāo)進(jìn)入按鈕的感應(yīng)區(qū) rollOut 鼠標(biāo)離開按鈕的感應(yīng)區(qū) 現(xiàn)在很明確了:寫在按鈕上面的AS一定就是這種格式的: on(事件){要執(zhí)行的代碼} 3、MC(電影剪輯) 如果你看懂了上面的內(nèi)容,那么寫在MC上面的AS和寫在按鈕上的大同小異。操作方法就是點(diǎn)選MC,然后打開AS面板??磦€例子 onClipEvent(load){ stop(); } 同樣,MC需要一個事件來觸發(fā)AS的執(zhí)行。翻譯這段代碼就是 當(dāng)剪輯(載入){ 停止 } 紅色代碼同樣表示一個事件。MC的事件有下面這些: load 載入,當(dāng)MC出現(xiàn)的時候執(zhí)行。也就是除非卸載這個MC,否則load事件內(nèi)的代碼只執(zhí)行一次 unload 卸載,當(dāng)MC卸載的時候執(zhí)行 enterFrame 存在的每個幀。在MC存在的每個幀都要執(zhí)行一次代碼。如果你的場景有100個幀,有個MC從41幀開始出現(xiàn)到100幀才消失,那么這個MC上面的代碼執(zhí)行了60次 mouseDown 按下鼠標(biāo),在場景內(nèi)任何地方都算。和按鈕不一樣的地方 mouseMove 移動鼠標(biāo),只要移動鼠標(biāo)就執(zhí)行代碼 mouseUp 松開鼠標(biāo) 同樣你要明確:寫在MC上的代碼一定總是這種格式: onClipEvent(事件){代碼} 看到這里,如果你明白的寫在 幀、按鈕、MC上的代碼有什么不一樣,任務(wù)就算完成了
AS 對象篇 重點(diǎn) :點(diǎn)語法學(xué)會表達(dá)對象 學(xué)會用絕對路徑和相對路徑表達(dá)對象 雖然AS不是真正的面向?qū)ο蟮木幊?,但是它也有對象的概念。這個概念貫穿整個AS的始終,所以,對對象的理解,比對語法或者其他的理解更為重要?,F(xiàn)在開始吧: 首先,我們來了解一下路徑,路徑分兩種:絕對路徑和相對路徑。做過html的朋友應(yīng)該知道這個概念。但這里我還是要詳細(xì)解釋一下,我認(rèn)為對路徑的理解要深入,我初學(xué)的時候就是磕在路徑上。 在講路徑之前,有必要先講一下 .語法 : 舉例說明,這里要表示房間里的桌子上的一本 書,用 .語法這么表示: 房間.桌子.書 如果要再細(xì)到書上的頁上面的字,很顯然 房間.桌子.書.頁面.字 看明白了吧?我也不懂得怎么說, .語法就是這樣表示對象的,點(diǎn)的前面是其后面的父級。如房間是桌子的父級,桌子的子級就是書。 還是不明白?這樣吧,你把 . 里寫成“里面的”就可以了,這樣就是 房間(里面的)桌子(里面的)書(里面的)頁面(里面的)字 這樣容易多了吧? 現(xiàn)在我開始說路徑了,其中也要夾雜的對象的說明,看: 從例子入手。新建一個Flash文件,然后創(chuàng)建一個MovieClip,MC命名為“MC”,放在主場景里面,然后再創(chuàng)建一個按鈕,放在“MC”里面,然后從庫里面拖一個出來放在主場景,分別給這兩個元素實例命名(Instance Name , 注意是實例名不是MC的名字):MC->myMC button->myBtn 現(xiàn)在我們假設(shè)主場景是房子,MC是桌子,按鈕是書,那么分別怎么表達(dá)房子,桌子,書呢?如下 _root 房子 _root.myMc 房子.桌子 _root.myMc.myBtn 房子.桌子.書 這里的 _root 是Flash的關(guān)鍵字,表示主場景的 Timeline (時間線)。 很容易理解對不。這里的 房子,桌子,書 都是我們要理解的“對象”。 當(dāng)你找到這個對象后,才能對對象進(jìn)行操作,才能給對象施加方法。比如,我現(xiàn)在要打掃房子,打掃是方法,但對象是房子,表達(dá)式是這樣 : 房子.打掃() 如果你不能正確的表達(dá)房子這個對象,你的打掃也就不能正確的實施了。 *說明:這里為什么要在打掃后面加()呢?因為打掃是方法不是對象,為了讓Flash知道這是個方法,我們必須加上(),要不然它會以為房子里面有“打掃”這個東西。 現(xiàn)在,我們可以很容易的對房間里面的各個東西進(jìn)行操作,如 房子.打掃(); 房子.木桌子.整理(); 房子.玻璃桌子.打碎(); 房子.書桌.書.看(); 等等,相信你把它們"翻譯"成AS代碼沒什么問題吧 比如要主場景停止播放,就是 _root.stop(); 要MC停止播放,就是 _root.myMc.stop(); 現(xiàn)在說說相對路徑。還是上面的例子。假如給你下了一個命令:修理房子里面的紅色的椅子。那么怎么表達(dá)呢?就是: 房子.紅色椅子.修理() 無論給你下命令的人在哪里告訴你的,你都會知道要修理的椅子是哪一張。但是他如果這么說:修理你現(xiàn)在坐的這張椅子。紅色的?還是藍(lán)色的?這就要取決于你坐在哪個椅子上了。那么相對的表達(dá)式就是 我坐的椅子.修理(); 這里為什么不這么寫呢: 房子.我坐的椅子.修理() 這么寫是錯的,因為我坐的椅子是不固定的,我說不定把椅子搬到房子外面去坐,那這個表達(dá)式就錯了,因為椅子根本就不在房子里面。 換過來用Flash實例說明。現(xiàn)在我想讓主場景下的 myMC 在一開始就不要播放,而是先停止。那么你有什么辦法呢? 我你猜想到的辦法可能就是在主場景放入這個MC的那個幀寫上: _root.myMc.stop(); 這個是對的。但是一旦 myMc 的名字一變,你就得跟著改這句話了。 有沒有辦法不管這個“MC”的實例名不管怎么改,都會被我們同樣一句的AS找到?當(dāng)然可以,前提是你的AS必須“坐在這個MC上”。 進(jìn)入Mc的編輯狀態(tài) , 在 Mc 的 Timeline 的第一幀寫上 this.stop(); 這里的this也是Flash的關(guān)鍵字 , 這個 this 指AS所在的這條 Timeline . 現(xiàn)在不管你這個MC放在哪里,命名是什么,我都不管,反正肯定會停下來。為什么,因為AS正“坐在MC上”。 如果你在這里寫上 _root.stop(); 那就錯了。為什么?仔細(xì)想想。 這個 this 就是相對路徑的關(guān)鍵字之一。你必須要仔細(xì)理解它。 另外的一個關(guān)鍵字就是 _parent 。如果你理解了 this , 那么 _parent 并不難理解。舉例: 還是哪個假設(shè) 房子(_root) , 桌子( mc_zhuozi ) , 書 (mc_shu) 他們的關(guān)系是(括號內(nèi)為mc實例名) 房子.桌子.書 _root.mc_zhuozi.mc_shu 在 mc_zhuozi 的 timeline 里面寫 _parent.打掃(); 意思就是打掃房間; 在 mc_shu 的 timeline 里面寫 _parent.打掃(); 意思就是打掃桌子。 _parent 也就是父級。桌子的 _parent 就是房子的 timeline , 書的 _parent 也就是 桌子的 timeline。點(diǎn)的后面的對象 的 _parent 就是點(diǎn)前面的對象。
AS 語法篇 首先要讓大家明白的是:AS 語法的大小寫是敏感的。 如: gotoAndPlay() 正確 gotoAndplay() 錯誤 。 關(guān)鍵字的拼寫必須和語法一致,要做到很容易,因為在Flash的AS面板里面,關(guān)鍵字會有不一樣的顏色顯示。 很多Flash小鳥們也許要開始埋怨,記不住咋辦?我這里有個辦法,就是背。不要流下委屈的淚水,俺們都是這么走過來的。多用兩次你就記住了。 這里說一下,我們要從開始就養(yǎng)成編程的好習(xí)慣,如在每個語句后面都加上分號,有可能的話,盡量給復(fù)雜的語句加上注釋。注釋的例子 //這個是注釋,但是只能有一行 /* 這個也是注釋,可以寫很多行 */ 接下來,介紹幾個類型的語法。 1、幾個常用的控制場景的方法,如 play(); //讓時間軸的指針播放 stop(); //停止時間軸的指針在程序觸發(fā)時候的那個幀 gotoAndPlay(); //讓指針跳轉(zhuǎn)到某個幀,然后繼續(xù)播放 gotoAndStop(); //讓指針跳轉(zhuǎn)到某個幀,停止在那個幀 nextFrame(); //往下走一幀 prevFrame(); //往前走一幀 上面的都是方法。 方法?解:打個比方,我們管吃飯叫作一種方法,用來解決肚子餓這個問題。我們管stop()叫做一種方法,用來解決時間軸指針停下來的問題。我們管上面的幾個東西叫方法,用來解決時間軸指針運(yùn)動的問題。 2、控制屬性的語法。有很多,我列幾個 _x _y _alpha _width _name .....等等屬性 上面的都是屬性 屬性?解:打個比方。我們管你的身高叫做屬性,用來標(biāo)識你的高度。我們管你的體重叫屬性,用來標(biāo)識你的質(zhì)量。我們管 _x 叫屬性,用來標(biāo)識目標(biāo)的X軸坐標(biāo)。我們管_alpha叫屬性,用來標(biāo)識目標(biāo)的透明度.......我真羅嗦啊,唉。 3、控制語句流程的語法,如 if (條件){ //條件滿足執(zhí)行這里的代碼 }else{ //條件不滿足執(zhí)行這里的代碼 } for(i=0;i<N;i++){ //執(zhí)行這里的代碼N次 } while(條件){ //當(dāng)條件滿足時一直執(zhí)行這里的代碼 } 等等。這些都是基本的語法,也是AS的基礎(chǔ)。 4、其他方法和自己定義的方法。 這里我不能把所有的語法都一一列出來介紹,因為實在是太多了,具體可以參考Flash自帶的幫助手冊。我們只能在以后的應(yīng)用中慢慢熟悉。這里,你有個基本概念就行了。到后面我會給每句話都加上注釋。 回顧一下,今次要大家記住的東西: AS 語法的大小寫是敏感的。 方法的概念。 屬性的概念。
[轉(zhuǎn)帖]AS基礎(chǔ)精典教程 作者和出處俱不詳,版權(quán)歸原作者所有 次給大家?guī)鞰OOCK在世界性FLASH大會:FF2K1大會上的演說,要說到Action的權(quán)威,當(dāng)然要數(shù)MOOCK,他寫的ASDG(一本書)是可以和FLASH自帶的AS字典相提并論的寶貝。雖然他是這樣一個高高手,但是他的這個演講卻是非常的淺顯,如果你某處讀起來覺得難,那也一定是chocobo翻譯得不好。(有些地方實在是太淺,我受不了就改了 ) 這篇文章預(yù)算的演講時間很長,所以讀起來也會覺得較長,你可以分開來讀。 還有,本文是關(guān)于FLASH5的AS的,畢竟FLASH4的AS已經(jīng)淘汰。 第一章:由O開始 為了示范,MOOCK將會做一個多選題問答的動畫來做為例子。 這個例子以4種不同版本的方法來實現(xiàn)。 對于用戶來說,4種版本使用起來將沒有區(qū)別,只是對于我們開發(fā)者來說,研究的就是如何改進(jìn)這些FLASH代碼的結(jié)構(gòu)與組織。 改進(jìn)的重點(diǎn)在于: *更便易的維護(hù) *更便易的擴(kuò)展 *更快捷的建設(shè) 要牢記的是,學(xué)習(xí)編程是一個過程(process)而不是一個事件(event)。 如果你第一次學(xué)習(xí)到的時候不能照著完成也不必?fù)?dān)心。 接下來,MOOCK說到為了照顧沒有多少編程經(jīng)驗的菜鳥,會由最最最簡單的開始。 關(guān)于計算機(jī)語言: 編程語言是用來發(fā)信息給電腦,從電腦接受信息的 編程語言也有詞匯表和文法,如人類的語言類似 通過編程語言我們可以告訴電腦去做什么,也可以從他那獲得信息 關(guān)于語法和邏輯 學(xué)習(xí)編程的思想比學(xué)習(xí)一種語言的語法重要 假設(shè)FLASH是懂我們語言的單詞的,我們對FLASH說:“Flash, 讓一個球在屏幕里面彈來彈去吧” FLASH會什么都做不了,F(xiàn)LASH要我們用他的世界懂的東西,例如:movie clips, buttons, frames,來描述它要做的事 那我們再說一次:“Flash, 讓一個名字叫ball_one的movie clip在屏幕里面彈來彈去吧” 我們已經(jīng)用MC這個FLASH懂的東西來描述了,但FLASH還是什么都不做,因為它需要更多的信息: *這個球有多大 *它放在哪里? *一開始它首先往哪個方向運(yùn)動? *它初始的速度是多少 *它在屏幕的那一個范圍之內(nèi)彈來彈去呢? *彈來彈去要持續(xù)多久呢? 看來我們需要有邏輯結(jié)構(gòu)地告訴FLASH它應(yīng)該怎么去做 1、一個球指的是一個叫ball_one的圓形MC,直徑50像素 2、還有一個方形MC叫square,邊長300像素 3、將ball_one放在square上某處 4、以一個隨機(jī)的角度,75像素每秒的速度開始移動ball_one 5、如果ball_one接觸到square的某邊,就彈回 6、一直不停地運(yùn)動下去,知道我們讓它停 如果FLASH真的懂我們語言的單詞,他應(yīng)該知道如何開始做了 總結(jié)一下關(guān)鍵點(diǎn): 無論是使用什么語言,編程思想的藝術(shù)都在于用如何將邏輯步驟列出 在你開始將要做的事用計算機(jī)語言描述之前,用我們?nèi)祟惖恼Z言描述一次會很有幫助 即使你將他們翻譯成任何的計算機(jī)語言,他們的邏輯步驟應(yīng)該是一樣的 電腦不懂用假設(shè)完成去你的想法,他們沒有思考能力(chocobo:就是你要把要求完全無遺漏地寫出來讓它運(yùn)行)
第二章:基礎(chǔ) 首先了解如何在FLASH輸入程序 在FLASH菜單Window里面Actions可打開ACTION面板,ACTION面板分右面的腳本窗,和左面的工具窗 腳本窗就是放腳本的地方,而工具窗用于快速地輸入各種ACTION,運(yùn)算符,函數(shù),屬性,對象 MOOCK建議大家使用專家模式,在FLASH菜單的Edit的Preferences的Actions panel里面選Expert Mode,以后每次打開ACTION面板都會自動設(shè)置為專家模式(專家模式可直接輸入代碼,初學(xué)者學(xué)下去就會知道,很多代碼無法在普通模式里輸入) AS的一些概念 所有代碼都需存于某個地方,可以是frame(幀), button(按鈕), or movie clip(電影夾子)。 只要你選擇了某按鈕或MC,你之后輸入的代碼就存放在它的上面了,注意此時ACTION面板上方提示為Object Actions。同理你也可以將代碼存放于幀,不過此時提示為Frame Actions。 當(dāng)你在專家模式的時候仍無法輸入代碼,你首先要檢查你是否選擇了frame, button, 或MC來存放代碼。 然后我們象學(xué)所有語言一樣吧,來個HELLO WORLD吧 在ACTION面板輸入 var message = "HELLO WORLD"; trace (message); 然后我們按CTRL和ENTER鍵,看到結(jié)果了嗎? 以下兩章比較基礎(chǔ)。MOOCK是騙演講費(fèi)嗎? 第三章:解讀 第一行代碼:var message = "HELLO WORLD"; 告訴FLASH記住一個名字叫message的容器(通常在計算機(jī)里稱為變量(variable),在FLASH里面,變量可以裝文字,和可以裝數(shù)字)里面裝了這樣的數(shù)據(jù)(datum),內(nèi)容為:"HELLO WORLD" “=”等號是一個常用的運(yùn)算符號(operators),在FLASH里面它不是代表相等,而是代表賦值 var 命令的含義是宣布給整個電影,此變量的內(nèi)容是什么。 第二行代碼:trace (message); 就是要FLASH顯示message里面的內(nèi)容,為什么FLASH能輸出內(nèi)容呢,因為當(dāng)你按CTRL+ENTER又或者在網(wǎng)上打開這個電影的時候,你輸入的每一段Action Scrpit代碼,都會通過FLASH的解釋器(interpreter)來解讀然后執(zhí)行 如果解釋器能解釋你的代碼,他會運(yùn)行它,并返回你要返回的結(jié)果,如果解釋器看不懂你的代碼,他也會返回錯誤代碼——告訴你錯誤的原因 通常,我們發(fā)給解釋器的命令不只命令這么簡單,還包括命令的內(nèi)容例如trace (message); 這個trace輸出命令的內(nèi)容就是message,計算機(jī)里就稱為參數(shù)(argument或parameter),如果一個命令支持多個參數(shù),參數(shù)之間一般用“,”來分割 第四章 還有一些概念 表達(dá)式(expression):(2 + 3) * (4 / 2.5) - 1可稱為一個表達(dá)式,"a"+"b"也是表達(dá)式,需要解釋器運(yùn)算才得到結(jié)果的值,一個相反的概念,不需要運(yùn)算的直接引用的,稱為literal 條件(conditionals):(look at a series of options and make a decision about what to do based on the circumstances) 不翻譯了,大概意思就是美女穿著新衣上街,會先看看外面會否下雨,這就叫條件判斷啦 if(天氣=="下雨"){trace("還是帶把雨傘吧")} 循環(huán)(loop):如果要輸出5個數(shù)字,你是寫5遍trace命令嗎?更多的就不行了吧 你可以用while和for命令來完成重復(fù)的動作 事件(events):放在frame里面的代碼只要電影播放到就會執(zhí)行,放在MC、button的代碼則只在解釋器發(fā)現(xiàn)預(yù)先設(shè)置好的事件被觸動的時候執(zhí)行。最典型的就是一下鼠標(biāo)點(diǎn)擊按鈕造成press時間啦。 函數(shù)(functions):將一組程序打包成一句命令來調(diào)用他,其實FLASH里面的很多命令就是函數(shù):trace、play、gotoAndStop等等都是。 第五章 開始第一個版本的選擇題的制作 多選題共有兩道 如圖,大家應(yīng)該養(yǎng)成一個好習(xí)慣,用一個獨(dú)立的層來放置代碼,并把該層放到最上面會更便于修改。 第二層則獨(dú)立放置Label。不要覺得麻煩,只要你想到世界上大部分好的閃客都是如此做的,你就不會嫌麻煩了。 以下的層放的是選擇題的內(nèi)容,如上圖 開始創(chuàng)建題目 在question 1層的第一幀,寫上題目"When were movie clips introduced into Flash?" (什么時候FLASH開始引入電影夾子的概念?) 再寫上三個選項:Version 1, Version 2, Version 3 跟著我們再做一個用來選擇的方框按鈕,從Library里面拖出這樣的三個按鈕,分別放到各個選項的前面。 第二題的創(chuàng)建我們用第一題來做個模版,選擇question 1層的第一幀,選擇菜單上的Edit>>Copy Frames 再選擇question 2的第十幀,Edit>>Paste Frames 將第一題復(fù)制過來了 當(dāng)然問題要改成"When was MP3 audio support added to Flash?" (什么時候FLASH開始支持MP3格式導(dǎo)入?),答案也要改成Version 3, Version 4, Version 5 數(shù)據(jù)初試化 雖然是個很簡單的FLASH,但是象其他復(fù)雜的FLASH一樣,先告訴FLASH要用到的數(shù)據(jù),例如題目的答案等,這是個好習(xí)慣,越復(fù)雜的FLASH,受惠越多 正常來說定義數(shù)據(jù)應(yīng)該LOADING結(jié)束之后的。 為了把題目定在第一題,ACTION還需要一句stop(); 選擇第一幀,在ACTION面板里面輸入代碼 // init main timeline variables var q1answer; // user‘s answer for question 1 第一題用戶的答案 var q2answer; // user‘s answer for question 2 第二題用戶的答案 var totalCorrect = 0; // counts number of correct answers 答對的題數(shù) var displayTotal; // text field for displaying user‘s score 顯示用戶分?jǐn)?shù)的變量 // stop the movie at the first question stop(); 你會發(fā)現(xiàn)//開頭的那一行代碼都變了色,//代表的是注釋,是用來輔助閱讀代碼用的,對代碼執(zhí)行沒有影響(是的,你在里面寫笑話,寫小說都可以,不會影響你的FLASH的^-^) 我們定義了四個將要用到的變量,用途已經(jīng)在注釋里面寫了,寫注釋也是一個好習(xí)慣 關(guān)于命名變量名 變量起名displayTotal,意思是 display total,因變量名不能使用空格和破折號,所以用第二個單詞的開始字母大寫,以此分隔單詞 一些程序員也喜歡用下劃線:display_total 記住一定要給你的變量起一個一眼就能識別意義的名字 添加label 我們知道第二題是在第10幀的,我們只需要一句AS:gotoAndStop(10); 就可以執(zhí)行第二個問題了 不過MOOCK告訴你這不是好習(xí)慣,因為動畫的內(nèi)容是不斷改變的,所以我們應(yīng)當(dāng)習(xí)慣使用label,即使幀數(shù)如何變化,只要label指向正確,不需要修改ACTION都可以繼續(xù)運(yùn)行(chocobo再提醒你吧,不要使用相同的label,即使在不同是Scene當(dāng)中) 好了,我們在label層的第1、10、20分別F6創(chuàng)建關(guān)鍵幀,給他們寫上init、q2、quizEnd 要給按鈕寫上代碼了 在三個按鈕里面分別寫入代碼,大同小異的: 按鈕一: on (release) { q1answer = 1; gotoAndStop ("q2"); } 按鈕二: on (release) { q1answer = 2; gotoAndStop ("q2"); } 按鈕三 on (release) { q1answer = 3; gotoAndStop ("q2"); } 這三段代碼用人類的語言描述,就是:當(dāng)用戶點(diǎn)擊某個按鈕選擇答案后,把他選擇的答案記錄到q1answer變量中去,然后進(jìn)入下一題。 on這個單詞代表隨后的就是一個要觸發(fā)的事件 release是指在按鈕上松開鼠標(biāo)這樣一個事件 當(dāng)動畫執(zhí)行到這里的時候,三個按鈕都會分別監(jiān)聽用戶有沒有做在按鈕上放開鼠標(biāo)這個動作,一旦發(fā)生,按鈕就會自動執(zhí)行大括號{}里面的代碼了 若用戶選第一個,{}中是: q1answer = 1; //用q1answer變量記住用戶選擇的是第一個答案 gotoAndStop ("q2"); //進(jìn)入下一題 上面我用了注釋的方法來解釋兩句代碼,你必須習(xí)慣,因為不是所有源程序都有教程,但是好的源程序都會有注釋 第二題的按鈕與前面相似,只是變量換為q2answer,選擇完進(jìn)入結(jié)束的畫面,例如第一個,改為: on (release) { q2answer = 1; gotoAndStop ("quizEnd"); } 結(jié)束的畫面 結(jié)束應(yīng)該做什么,當(dāng)然是告訴用戶分?jǐn)?shù)啦,寫在第20幀,就是label為quizEnd的那幀的代碼: // tally up the user‘s correct answers if (q1answer == 3){ totalCorrect = totalCorrect + 1; } if (q2answer == 2){ totalCorrect++; //totalCorrect++其實是totalCorrect = totalCorrect + 1;一個更簡潔的寫法,幾乎少打了一半的字母啊。 } // show the user‘s score in an on-screen text field displayTotal = totalCorrect; 用人的語言描述:如果第一題選3,答對數(shù)加一,如果第二題選2,答對數(shù)加一,把答對題目數(shù)賦予另一變量 現(xiàn)在答對的題數(shù)是放到變量displayTotal中了,怎么顯示? 在quiz end第20幀處建關(guān)鍵幀,鍵入"Thank you for taking the quiz! Your score final score is: /2"(謝謝回答問題,你最后成績是答對了 /2道題) 在"/2"之前那個空白的地方放上一個文本框,菜單Text>>Options顯示文本面板,把Static Text下拉改為Dynamic Text,順便把Border/Bg的鉤去掉,最后在Variable那一欄填上要顯示的變量名displayTotal 你是不是和chocobo一樣不耐煩了?快下載http://www./webdesign/lect...oockQuizzes.zip ;吧,里面的quiz.fla就是本章的內(nèi)容,其他的fla的內(nèi)容也將會在后面講到
[nextpage]
第六章 再來補(bǔ)充一點(diǎn)AS知識 數(shù)據(jù)分類是很有必要的,象8005154556這樣的一個數(shù)字是沒有多大意義的,但是如果將他歸類到電話號碼:800-515-4556,那就有意義了。(這是WHO的電話啊?是不是MOOCK的?呵呵) AS里面數(shù)據(jù)的類型相對其他語言已經(jīng)算少的,有: * 字符串String 由一系列的characters組成,可以包含字母,數(shù)字和符號,一般用雙引號""擴(kuò)住(記住不要寫了全角的“”) * 數(shù)字Number * 布爾值Boolean 用于條件判斷的時候,只有兩個值true和false * Null and Undefined 這也是數(shù)據(jù)的類型之一,Null代表變量還沒有內(nèi)容,Undefined是連變量都未定義 * 數(shù)組Array 用來按順序地存放一組數(shù)據(jù) * MovieClip 這也是數(shù)據(jù)的一種嗎?你就當(dāng)它是FLASH特有的一種數(shù)據(jù)吧,裝的就是一個個MC INSTANCE(解釋一下吧,MC從library拖到場景中就是一個獨(dú)立的instance,一個MC可以創(chuàng)立多個instance),還有MC里面的其他數(shù)據(jù) * Object 可以是FLASH已經(jīng)內(nèi)部定義的,或者是用戶寫程序時自定義的一類數(shù)據(jù) 再分類一下 number, string, boolean, undefined, and null,這些屬于簡單的數(shù)據(jù)類型,特征是只有一個值 array, object, movieclip. 就可以包含不止一個值 chocobo:其實array也應(yīng)該算是object,上面這些概念的東西總是有些沉悶,沒關(guān)系,留下印象,以后用到了,自然會回過來真正了解一遍的 第七章 可以重復(fù)的函數(shù)(function) 不是用幾個例子來示范嗎?怎么還不講例子???是的,下一個例子要用到函數(shù),所以再補(bǔ)充點(diǎn)函數(shù)知識。(上當(dāng)了吧?chocobo也上當(dāng)了,開始翻譯的時候沒想到這篇東西這么長的,這才講完第一個例子呢 55~) 一個函數(shù)是下面這個樣子的: function funcName () { statements } 在ACTION面板里面,function這個單詞是變色的,F(xiàn)LASH認(rèn)識這個單詞,它代表后面的就是描述函數(shù)的內(nèi)容 funcName是函數(shù)的名字,當(dāng)你以后要用這函數(shù)的時候,就要敲這個名字了(是的,建函數(shù)就是為了以后反復(fù)調(diào)用它) ()小括號里面是參數(shù),什么是參數(shù)一會再講 {}大括號里面的就是函數(shù)所要完成功能的一句句代碼。 當(dāng)我們建立函數(shù)之后,函數(shù)并不運(yùn)行,只在你用函數(shù)的名字調(diào)用它出來,才正式開始運(yùn)行 例如我們有這樣一個函數(shù) function sayHi () { trace("Hi!"); } 當(dāng)我們在FLASH某幀需要sayHi的時候,輸入AS: sayHi(); 是不是和最常見的stop();還有play();一樣???因為它們都是函數(shù)嘛 sayHi函數(shù)真是智,來個有意義的函數(shù)吧。先在場景里放好一個名字叫ball的instance(千萬記得要給instance輸入名字,否則函數(shù)運(yùn)行沒結(jié)果別找我) 在第一幀輸入這樣一個函數(shù): function moveBall () { ball._x += 10; // 怕有人不懂,解釋一下,_x代表ball的橫坐標(biāo),ball._x +=10 的意思是ball._x = ball._x + 10 ,這樣省略的寫法還有 -= *= /= 等等 ball._y += 10; } 再做一個按鈕,按鈕的AS: on (release) { moveBall(); } 好的,運(yùn)行,從AS你可以看到,每點(diǎn)一下按鈕,執(zhí)行一次函數(shù),而函數(shù)讓小球下斜下移動。(FLASH的坐標(biāo)軸,原點(diǎn)在左上角) 為什么要建立函數(shù)呢,就是想更有效率,現(xiàn)在有這個函數(shù)已經(jīng)不用每移動一下寫一次AS了,但還是不夠,我們需要更有擴(kuò)展性(flexibility)的函數(shù) 這個函數(shù)只能移動叫ball的MC,只能向固定的方向移動固定的距離,我們需要可以移動任何MC,向任何方向移動任何距離的函數(shù),這樣可以省卻很多輸入AS的工夫(這就叫一勞永逸,呵呵) 我們的新函數(shù)有三個地方是每次調(diào)用都不一樣的 1、移動的那個MC的名字 2、水平移動的距離 3、垂直移動的距離(呵呵,用極坐標(biāo),也可以把2、3說成移動的距離,和移動的角度,不過大家都不習(xí)慣極坐標(biāo)) 為了告訴函數(shù)這些變化的地方,我們需要參數(shù)(parameters),參數(shù)在定義函數(shù)的時候就要輸入,我們的函數(shù)改寫好了: function moveClip (theClip, xDist, yDist) { theClip._x += xDist; theClip._y += yDist; } 當(dāng)我們要實現(xiàn)原來函數(shù)功能的時候,現(xiàn)在調(diào)用新函數(shù)就變成 moveClip (ball, 10, 10); 定義函數(shù)的時候function moveClip (theClip, xDist, yDist) { 這里的theClip等參數(shù)(parameters)只是定義,本質(zhì)上說是不存在的,因為沒有內(nèi)容嘛 當(dāng)我們用moveClip (ball, 10, 10);調(diào)用的時候,ball就輸入到theClip中去了,這里的ball稱為arguments(偶讀得書少,不會翻譯) arguments可以是一個變量,也可以是一個表達(dá)式(例如"a"+"b",先得出結(jié)果再傳輸給函數(shù))只要用逗號隔開各個參數(shù)就行 函數(shù)如何結(jié)束呢 正常來說,函數(shù)運(yùn)行完 {}里所有語句結(jié)束,我們也可以用一句AS:return; 讓它中途結(jié)束,例如: function say(msg) { return; trace(msg); } 這個函數(shù)被調(diào)用的時候?qū)⑹裁炊疾蛔鼍徒Y(jié)束 return還有更重要的用途: function sqr { // Squares a number 平方 return x * x; } a=sqr(2); //a將會被賦予2的平方 4 return更重要的用途就是返回數(shù)據(jù) 在AS里面,有個內(nèi)建的函數(shù)Math.sqrt(就是說你敲入的時候會變色),其功能和我們剛才做的sqr函數(shù)是一樣的,現(xiàn)在你該知道內(nèi)建函數(shù)也沒什么神秘的,我們一樣可以做出相同功能的來。 第八章 第二個版本選擇題的制作 讀到這你發(fā)現(xiàn)什么,我是發(fā)現(xiàn)了,MOOCK不是在教AS,他簡直是在上編程課。 在第一個版本的制作里你發(fā)現(xiàn)了什么缺點(diǎn)?是的,輸入了很多次AS,很麻煩。 我們要做的是用函數(shù)來集中我們的代碼,只有集中了才好修改,越復(fù)雜的程序越是如此(想象一下在很多個MC之間查代碼,真是頭痛,當(dāng)然是集中一塊好) 這個多選題,我們就歸結(jié)成兩個函數(shù)吧answer和gradeUser 代碼(可以直接看源程序,在上面地址那個ZIP里面的quiz-version2.fla): 大部分的代碼都被集中到第一幀了,千萬不要被一大堆代碼嚇著了,代碼這么長,只是為了讓閱讀者看得更清楚而已。(其實越短的代碼才越可怕呢,呵呵) // Stop the movie at the first question stop (); // Initialize main timeline variables 定義變量 var displayTotal; // Textfield for displaying user‘s score var numQuestions = 2; // Number of quiz questions var q1answer; // User‘s answer for question1 var q2answer; // User‘s answer for question2 var totalCorrect = 0; // Number of questions answered correctly 以上和例一一樣 var correctAnswer1 = 3; // The correct choice for question 1 第一題的正確答案 var correctAnswer2 = 2; // The correct choice for question 2 第二題的正確答案 // Function to register user‘s answers 這個函數(shù)的功能是提交答題者的答案 function answer (choice) { answer.currentAnswer++; //現(xiàn)在answer.currentAnswer是1,正在提交的是第一題,下一次answer.currentAnswer就變成2,代表提交的是第二題 set ("q" + answer.currentAnswer + "answer", choice); // 不復(fù)雜不復(fù)雜,"q" + answer.currentAnswer + "answer"第一題的時候就是q1answer,第二題是q2answer,把參數(shù)choice傳過來的值放到兩個變量里面而已 if (answer.currentAnswer == numQuestions) { // 判斷是不是兩題都答完了,是就轉(zhuǎn)到問題結(jié)束幀 gotoAndStop ("quizEnd"); } else { gotoAndStop ("q" + (answer.currentAnswer + 1)); } } // Function to tally user‘s score 這個函數(shù)是改題的 function gradeUser() { // Count how many questions user answered correctly 將兩個答案和正確答案比較,對就totalCorrect加一 //此處用了一個for循環(huán),大家如有疑問的,可以查AS字典,在帝國就有中文版 for (i = 1; i <= numQuestions; i++) { // 下面用的eval有必要說一下,它的作用是將字符串和變量組成一個新的變量名,是個很方便的功能 if (eval("q" + i + "answer") == eval("correctAnswer" + i)) { totalCorrect++; } } // Show user‘s score in an on-screen text field 將答案顯示出來,與第一個例子同 displayTotal = totalCorrect; } 好了,第一幀的函數(shù)寫好了,之后每個答案的選擇按鈕就簡單了 例如第一題的選項一,就寫: on (release) { answer(1); } 第二題的寫法同上(如果你的選擇題有很多道,做法都是一樣的,只要復(fù)制第一題,然后把題目改了就行) 最后在quizEnd幀里面調(diào)用改題的函數(shù)gradeUser(); 分析第二個例子是代碼,你會發(fā)現(xiàn)比第一個例子精簡了很多。 而集中在同一幀的代碼,將: * 更容易修改 * 更容易升級 * 更少的出錯機(jī)會 * 更容易查錯 * 更精簡(更少的字節(jié)數(shù)) 第九章 數(shù)組(arrays) 在下一個新版本的多選題里,我們將使用什么AS的特性,來讓它更好呢? 那就是數(shù)組。 數(shù)組就是一系列的數(shù)據(jù)(MOOCK又開始上課了,chocobo的英文和計算機(jī)都不算好,為免誤人子弟,概念性的東西盡量精簡) 例如這樣兩個變量儲存的數(shù)據(jù): fruit1 = "oranges"; fruit2 = "apples"; 它們是互相獨(dú)立的,使用起來很不方便,我們需要的是數(shù)組,以下是數(shù)組的定義方法,用“”框住,用“,”分隔開每個元素: fruitList = ["oranges", "apples"]; 現(xiàn)在兩個數(shù)據(jù)是放到同一個數(shù)組里面了,我們開始詳細(xì)解說數(shù)組 數(shù)組里面每一個數(shù)據(jù)稱為元素(element)。 而每一個元素都有個獨(dú)立數(shù)字代表所處的位置,數(shù)字叫索引(index),注意! 第一個數(shù)據(jù)的索引是0,第二個才是1 要按索引來提出數(shù)據(jù),我們要用一個運(yùn)算符,例如使用fruitList第一個元素賦值給a: a=fruitList; 又例如將a的值賦給fruitList第一個元素: fruitList=a; 當(dāng)然里面也可以放表達(dá)式、變量: var index = 3; // Set numApples to 2 var a = fruitList[index]; 下面是個使用表達(dá)式的例子: // Create a myFrames array. Note the legal formatting. 建立一個記錄LABEL的數(shù)組 var myFrames = ["storyEnding1", "storyEnding2", "storyEnding3", "storyEnding4"]; // Set randomFrame to a randomly picked element of myFrames // by calculating a random number between 0 and 3 // 隨機(jī)從數(shù)組中提取一個LABEL var randomFrame = myFrames[Math.floor(Math.random() * 4)]; // Now go to the random frame // 然后跳到該LABEL播放 gotoAndStop(randomFrame); 而數(shù)組包含數(shù)據(jù)的個數(shù)稱為長度(length),例如fruitList.length 就等于2 對數(shù)組最常用的處理就是從數(shù)組中選出有用的數(shù)據(jù)了,來看一個運(yùn)用循環(huán)的例子: // Create an array 建立數(shù)組,里面放了一些歌的類型 var soundtracks = ["electronic", "hip hop", "pop", "alternative", "classical"]; // Check each element to see if it contains "hip hop" // 一個循環(huán),檢查每一個元素是否等于"hip hop"這個類型 // 另外,請留意此處MOOCK對FOR的寫法,J=0之前有一個VAR,這好象可有可無,其實是一個好習(xí)慣! for (var j = 0; j < soundtracks.length; j++) { trace("now examining element: " + j); if (soundtracks[j] == "hip hop") { trace("the location of ‘hip hop‘ is index: " + j); break; // 跳出循環(huán),找到了就不用再找了 } } 關(guān)于數(shù)組的方法(method) 方法就是從屬于某一對象(object)的函數(shù),通常都是對該對象進(jìn)行處理的函數(shù) 好象太抽象了?我們還沒講到什么是對象,其實數(shù)組是對象的一種,我們就暫且將數(shù)組的方法理解為一個專門處理數(shù)組內(nèi)數(shù)據(jù)的結(jié)構(gòu)和內(nèi)容的工具吧 例如一個叫push()的方法就是一個工具,用于為數(shù)組添加一個元素,并且加在該數(shù)組的最后 使用起來并不復(fù)雜,看例子就知: // Create an array with 2 elements var menuItems = ["home", "quit"]; // Add an element 加一個元素 // menuItems becomes ["home", "quit", "products"] // 現(xiàn)在數(shù)組的結(jié)構(gòu)變成["home", "quit", "products"] menuItems.push("products"); // Add two more elements 這次是加兩個 // menuItems becomes ["home", "quit", "products", "services", "contact"] menuItems.push("services", "contact"); 跟push()相反從最后彈出一個元素的方法是pop() 而跟push()類似,但是是將一個元素加到數(shù)組的開頭的方法是unshift(),與之相反的是shift() 方法sort和reverse,用于重新排列數(shù)組的元素 方法splice用于從數(shù)組中間刪除某元素 方法slice和concat可以在某些數(shù)組的基礎(chǔ)上生成另一個新的數(shù)組 方法toString和join可以將整個數(shù)組變成單一個字符串 以上方法都可以從AS字典里面查到
[nextpage}
第十章 第三個版本的選擇題 首先,此版本沿用了上一版本的函數(shù)answer和gradeUser 在這一版本中,用戶的答案與正確答案將使用數(shù)組來存放 看看我們的新代碼: stop(); // *** Init main timeline variables var displayTotal; // Text field for displaying user‘s final score var numQuestions = 2; // Number of questions in the quiz var totalCorrect = 0; // Number of correct answers // 上一版本中,用戶答案使用了兩個變量來存放,但是試想如果是10題、100題呢?使用數(shù)組將更容易管理,也更容易處理 var userAnswers = new Array(); // Array containing user‘s guesses 這是定義數(shù)組的語句,但是還未輸入數(shù)據(jù) var correctAnswers = [3, 2]; // Array containing each correct answer 這一句既定義數(shù)組,同時輸入數(shù)據(jù),因為正確答案是已知的 // *** Function to register the user‘s answers function answer (choice) { // Tack the user‘s answer onto our array 將數(shù)據(jù)PUSH進(jìn)數(shù)組,因為是順序答題,所以用方法PUSH userAnswers.push(choice); // Do a little navigation, baby // 如果答案數(shù)超過題目總數(shù),自然就跳到quizEnd幀了 // 注意在本例中,已經(jīng)不用上例的answer.currentAnswer而是使用userAnswers.length來控制問題是否結(jié)束 // 我們甚至可以用correctAnswers.length來代替numQuestions,記錄正確答案數(shù)組的長度,不就是題目總數(shù)嗎? if (userAnswers.length == numQuestions) { gotoAndStop ("quizEnd"); } else { gotoAndStop ("q"+ (userAnswers.length + 1)); } } // *** Function to tally the user‘s score function gradeUser() { // Count how many questions were answered correctly. // 開始改題,這里就不用再用上個版本的eval啦,那個東東實在是難懂兼難用,這個版本相對就很清晰明快 for (var j = 0; j < userAnswers.length; j++) { if (userAnswers[j] == correctAnswers[j]) { totalCorrect++; } } // Show the user‘s score in a dynamic text field displayTotal = totalCorrect; } 電影的其他部分不用改動(這就是使用FUNTION的好處啦,升級多快~) OK,進(jìn)入下一章之前想想目前版本的點(diǎn) * 題目,每次修改題目都要進(jìn)入FLASH的場景修改,麻煩 * 按鈕,每題就要做三個按鈕 這都是麻煩的地方,我們要更精益求精地修改,讓我們的多選題,輕易地從兩題變成10題、100題 接下來我們要做的是 * 進(jìn)一步改進(jìn)我們存放數(shù)據(jù)的結(jié)構(gòu) * 讓我們可以動態(tài)地生成每一道題目,只需輸入數(shù)據(jù),而不需要在FLASH里面作就可以自動生成 所以——我們需要面向?qū)ο缶幊蹋?object oriented programming) chocobo:嘻嘻,眾菜鳥是不是都倒了,AS基礎(chǔ)教程竟然開始講OOP了,呵呵,沒關(guān)系啊,上面的教程一直都這么淺,以后也深不了 第十一章 一點(diǎn)面向?qū)ο缶幊讨R At is heart, OOP simply means that you treat portions of your program as self-contained, but interrelating modules called objects. 這是什么呀?我不翻譯了,概念的我們就先不懂吧,對象主要構(gòu)成包括屬性(properties)和方法(methods) 一個對象通常都以現(xiàn)實世界里的某個東東做藍(lán)本 例如我們可以定義一個對象叫球 那么這個球?qū)羞@樣的屬性:半徑、X坐標(biāo)、Y坐標(biāo)、顏色 同時,也會用屬于球自己的方法例如:移動球、計算球的面積 當(dāng)然,我們還可以定義一些相對抽象的對象,例如我們要做的多選題 所有的對象都屬于某類(class),類的意思其實是用于創(chuàng)建對象的模版 一個實例(instance)就是某一個類的特定某一個case(好復(fù)雜,概念性的東西我翻不過來啦,反正實例就類創(chuàng)建出來的某一個對象) 還是再舉例吧 * 例如我們有個一個叫Chair的類 * 這個類定義了一個東西需要它有四條腿,一個坐墊 * 然后我們就可以用Chair這個類來定義我們的不同對象(可理解為椅子的款式),每個對象就有它特有的高、寬、材料、重量、顏色,正是這些屬性使每個對象互相區(qū)別。 所有的椅子互相區(qū)別,有自己的屬性,但是他們又有同樣的結(jié)構(gòu):四條腿、一個坐墊 OK,那AS里面的類和對象呢? 是的,AS里我們可以自己創(chuàng)建對象,也有可以使用的內(nèi)建對象 內(nèi)建的類(你可以用它來創(chuàng)建對象)包括:Array, Boolean, Color, Date, MovieClip, Number, Object, Sound, String, XML, XMLSocket 內(nèi)建的對象(已經(jīng)可以直接使用的對象)包括:Arguments, Key, Math, Mouse, Selection 內(nèi)建的類、對象當(dāng)然都是在FLASH里面有自己功能的東西。而正是這些功能非常常用,F(xiàn)LASH才內(nèi)建了這些類和對象,例如: Mouse.hide(); // Hide the mouse pointer 將鼠標(biāo)隱藏,你經(jīng)常用吧?現(xiàn)在才知道其實是內(nèi)建的Mouse對象的一個hide()方法吧? 在學(xué)習(xí)如何創(chuàng)建自己的類和對象之前,先來了解一下內(nèi)建類和對象是怎樣工作的吧 與數(shù)組的結(jié)構(gòu)類似,對象是容器們(containers)的容器(container) 一個對象,用各個獨(dú)立的屬性來存放數(shù)據(jù),只不過數(shù)組區(qū)分每個容器是用數(shù)字,而對象則是用屬性名,要調(diào)用一個數(shù)組里面某個數(shù)據(jù),我們需要它是索引值,而要調(diào)用對象的屬性,則要知道屬性名 看看以下這個例子,這是個叫BALL的對象“ BALL對象有兩個屬性:radius 和 color 而兩個屬性分別賦值為:50 和 0xFF0000 (這是AS里面表達(dá)16進(jìn)制的方法) 概念清楚了,說一AS里面使用對象要注意的地方 首先,對象的屬性很靈活,它儲存的數(shù)據(jù)可以是strings(字符串), numbers(數(shù)字), booleans(布爾值), null(空), undefined(未定義), functions(函數(shù)), arrays(數(shù)組), movie clips(電影夾子), or even other objects(甚至是其他的對象,包括自定義的). 調(diào)用屬性,可用點(diǎn)語法:objectName.propertyName 例如我們賦值給BALL里面的屬性radius: ball.radius = 100; 我們也可以用符號來訪問屬性,但是里面的屬性名需用雙引號擴(kuò)住,同上例: ball["radius"] = 100; (所以說數(shù)組也是對象一種,訪問方法也一樣,并沒有搞特殊化) 與點(diǎn)語法比較,更靈活,可以動態(tài)地改變屬性的名字,里面可以是變量或表達(dá)式,例如: var propName = "radius"; ball[propName] = 100; 這點(diǎn)是點(diǎn)語法無法辦到的 純粹的OOP中,我們幾乎不會直接訪問對象的屬性 我們一般都使用方法(methods) ,來改變屬性 例如改變mySound這個聲音對象的音量屬性 AS的用法應(yīng)該是mySound.getVolume(100); 而不是mySound.volume=100; 但是為了簡單,多選題這個例子里不一定遵循這個原則,事實上AS里面很多對象都不可以辦到這點(diǎn),所以有人說AS不是面向?qū)ο笳Z言。 關(guān)于對象的方法 方法method其實是一些附屬于對象的函數(shù),其作用主要是訪問對象中的數(shù)據(jù),或完成某種功能 所以調(diào)用方法和調(diào)用普通函數(shù)類似:objectName.methodName() 只是前面加上了對象的名字 例如上面的BALL對象,我們需要它的面積,使用 getArea 這個方法: ball.getArea(); 預(yù)習(xí)一下,在下一個例子中,雖然MOOCK不打算建立自己的方法,但是將使用內(nèi)建于MovieClip對象的兩個方法: *MovieClip.attachMovie() 此方法是將Library(CTRL+L按出來的那個)里面的symbol復(fù)制一個instance到場景中 (chocobo:給不懂概念的人緊急補(bǔ)習(xí),放在庫(Library)里面的叫符號(symbol),拉到場景中就叫實例(instance),一個符號可創(chuàng)建多個實例,符號改變則實例隨之改變) 與之類似的是MovieClip.duplicateMovieClip(),但是該方法需要事先在場景里已經(jīng)有一個實例 *MovieClip.removeMovieClip() 此方法與上面相反,是刪除場景里面的instance的 大家看到了,在下一例中,我們將使用MovieClip這個內(nèi)建對象,因為它就可以滿足我們的需要,不必新類型的對象了 我們先來熟悉一下MC這種對象 它有很多屬性_height(高度)、 _alpha (透明度),MC的屬性大家可以在AS字典里面查到,在AS面板里這寫屬性也是變色顯示的 同時MC的方法,例如 MC.play(); 等也可以查到 當(dāng)我們在MC里面的時間線使用這些屬性、方法的時候,可以省略不寫前面部分,直接寫play(); MC可以互相嵌套,MC當(dāng)中又有MC,就出現(xiàn)類似: mc1.mc2.play(); 的情況 為了調(diào)用包含自己的上一級MC的方法、屬性,AS里面用_parent,例如: 在mc1包含mc2 ,在mc2中想使mc1播放:_parent.play(); 還有另一個保留字:_root指代該電影的主時間線 例如想在某個mc里面讓整個電影播放:_root.play(); 想在某個MC中讓另一mc1播放:_root.mc1.play(); 還有,MC中定義的變量,將作為MC的一個屬性可被訪問 在mc1里面寫了一句 var a=1; 我們將可使用 mc1.var來調(diào)用它 關(guān)于類(class) 這個概念大家還是不大懂吧?類就是定義一個對象將擁有什么的方法跟屬性的東東,類似MC里instance與symbol的關(guān)系,instance的結(jié)構(gòu)就是由symbol決定的,每個instance又可以不一樣 AS里面沒有專門定義類的例如class這樣的關(guān)鍵字,我們使用函數(shù)來定義類,這種函數(shù)稱構(gòu)造函數(shù)constructor function,函數(shù)的作用就是產(chǎn)生我們定義好的類的實例(就是對象) 舉例最實在: // make a Ball constructor 最簡單的構(gòu)造函數(shù) function Ball () { // do nothing 里面是空的 } 現(xiàn)在我們可以定義新類型Ball的對象了 myBall = new Ball(); 語法就是前面是新對象實例名,等號后是new加構(gòu)造函數(shù)名 myBall就擁有了Ball定義的一切結(jié)構(gòu)了(雖然Ball里面是空的,嘻嘻) 不過不是所有對象創(chuàng)建都用new,例如mc創(chuàng)建就用的是attachMovie()或duplicateMovieClip() 好了,我們的構(gòu)造函數(shù)總不能空的,如何定義類,讓新對象有自己的屬性呢? 使用this這個關(guān)鍵字,看例子,新的構(gòu)造函數(shù): function Ball () { this.radius = 10; this.color = 0xFF0000; this.xPosition = 35; this.yPosition = -4; } 以后我們定義出來的新對象,都擁有半徑,顏色、XY坐標(biāo)屬性啦 慢著,怎么每個新對象都一模一樣??? 再改,用函數(shù)的參數(shù)來定義動態(tài)的屬性: // Make the Ball constructor accept // property values as arguments. function Ball (radius, color, xPosition, yPosition) { this.radius = radius; this.color = color; this.xPosition = xPosition; this.yPosition = yPosition; } 我們可以定義不同屬性的對象了 myBall = new Ball(6, 0x00FF00, 145, 200); 本教程關(guān)于還有創(chuàng)建方法以及如何在類之間繼承方法和屬性沒講, 無論如何,OOP都不可能在這么短時間之內(nèi)說清楚, 但這不妨礙我們做下一個例子了。
第十二章 第四個版本的選擇題 第三個版本的時候我們已經(jīng)設(shè)想好,新版本中題目將是動態(tài)生成的,不用我們在FLASH的場景里面一題一題輸入了,我們要做的只是輸入題目和題目答案的數(shù)據(jù)就夠了。 很明顯,每一條題目都將是一個對象(不然我們學(xué)這么多對象的知識干嘛?),而這些所有的題目,會用一個數(shù)組來存放 再重提一下,可配合源程序?qū)W習(xí) http://www./webdesign/lect...oockQuizzes.zip ; 好,開始設(shè)計題目的模版 模版就是一個MC,包含兩個TEXT FIELD,里面不用填東西,分別起變量名為:(FOR小鳥:TEXT FIELD就是按工具條里T按鈕拉出來的文本框,同時還要在文本面板(ctrl+t)里將其改為Dynamic Text,變量名則在面板的Variable處改) * qNum (以后將顯示題目的編號) * qText (以后將顯示題目的正文) 我們還要在庫里面做標(biāo)識,點(diǎn)一庫面板(ctrl+l)右上的Options>> Linkage ,選第二個Expert this symbol,identifier填上questionTemplate,至此,題目模版完成 再制作選項的模版 選項模版應(yīng)包括一個選擇用的按鈕 還有該選項的內(nèi)容,一個起名為answerText的TEXT FIELD 在本例的后面,將為每一個動態(tài)生成的選項一個唯一的名字,譬如: "answer0", "answer1",..."answern". 答題者所選定的答案將由這個名字來決定,調(diào)用一個MC的名字,用的是_name這個屬性 所以答題的按鈕上面的AS為: on (release) { // Trim the prefix "answer" off this clip‘s name // 下面使用了String.slice()方法,例如_name為answer0,它將被處理成0,slice的具體語法請查閱AS字典 // 按鈕提交什么由該MC的名字決定的,我作個標(biāo)記 @@ ,記得一會看回來 choice = _name.slice(6, _name.length); // 與前面的例子一樣,最后將答案提交給answer函數(shù)處理,不過現(xiàn)在我們是在某一MC里面用外面主時間線的函數(shù)了,所以得加上_root _root.answer(choice); } 最后,Options>> Linkage,標(biāo)識名:answerTemplate,制作模版的工作就完成了 下面將是放在第一幀的程序主體,可要打起精神來了: // Stop the movie stop(); // Init main timeline variables var displayTotal; // Text field for user‘s final score var totalCorrect = 0; // Number of questions answered correctly // Array containing the user‘s guesses 記錄作答答案的數(shù)組 var userAnswers = new Array(); // Number of the question the user is on 記錄正在作答中題目的編號 // 要注意的是,它是由0開始的,第一題的編號是0,因為我們要用到數(shù)組,數(shù)組的第一個編號是0,所以這里我們也用0 var currentQuestion = 0; // The Question constructor // 以下是新類型對象question的構(gòu)造函數(shù),包含三個屬性:正確答案,題目正文,各個選項 function Question (correctAnswer, questionText, answers) { this.correctAnswer = correctAnswer; this.questionText = questionText; this.answers = answers; } // Import the source file containing our array of question objects // 咦?應(yīng)該是輸入各條題目的數(shù)據(jù)先啊,放哪去了?因為嘛,數(shù)據(jù)輸入是個與編程無關(guān)的過程,為了讓代碼更優(yōu)雅,這些繁瑣的東西扔別地方去了,AS太長,會使查閱相當(dāng)麻煩,分開存放也是好習(xí)慣! // #include是引用外部AS命令,可以將AS分開儲存于各個后綴名為AS的文件中,輸入題目的代碼就是放到了questionsArray.as中(記得和FLA放在同一目錄下喔) #include "questionsArray.as" //// 我改變了一下教程的結(jié)構(gòu),把questionsArray.as的內(nèi)容也插入進(jìn)來了,因為跳過這段的話,看起來會有疑問 //// 以下內(nèi)容系存放questionsArray.as中的 // 輸入數(shù)據(jù)其實是建立對象 // MOOCK用一個數(shù)組還存放這些對象,這樣對象才更易于管理 // 不要被括號給弄昏了,輸入對象參數(shù)的中間還有中括號,是因為輸入題目的參數(shù)“各個選項”是一個數(shù)組 // 因為是存放于數(shù)組中,每個對象之間記得應(yīng)有逗號分隔 // Remember to place a comma after each object // in the array except the last questionsArray = [new Question (2, "Which version of Flash first introduced movie clips?", ["version 1", "version 2", "version 3", "version 4", "version 5", "version 6"]), new Question (2, "When was Action formally declared a ing language?", ["version 3", "version 4", "version 5"]), new Question (1, "Are regular expressions supported by Flash 5 Action?", ["yes", "no"]), new Question (0, "Which sound format offers the best compression?", ["mp3","aiff", "wav"]), new Question (1, "True or False: The post-increment operator (++) returns the value of its operand + 1.", ["true", "false"]), new Question (3, "Action is based on...", ["Java", "Java", "C++", "ECMA-262", "Perl"])]; //// 離開questionsArray.as部分,我們繼續(xù) // Begin the quiz 出題目!調(diào)用makeQuestion函數(shù)來完成,我們只需要給這個函數(shù)一個參數(shù):題目的編號,函數(shù)就會按編號提取數(shù)據(jù),結(jié)合我們剛才做的模版生成題目。 makeQuestion(currentQuestion); // Function to render each question to the screen // 下面就是makeQuestion函數(shù) function makeQuestion (currentQuestion) { // Clear the Stage of the last question //這句是清理上一題生成的MC,這句從第二題開始生效,questionClip就是題目的MC名,MC從哪來的?看下面就知道了 questionClip.removeMovieClip(); // Create and place the main question clip // 利用模版questionTemplate生成一個叫questionClip的MC,這個MC就是我們的問題 attachMovie("questionTemplate", "questionClip", 0); // 設(shè)定MC的位置 questionClip._x = 277; questionClip._y = 205; // 把題目編號輸入MC的qNum文本框中 questionClip.qNum = currentQuestion + 1; // questionsArray[currentQuestion]就是數(shù)組questionsArray里的第currentQuestion個對象,例如currentQuestion是0,那么就是我們的第一條題目 // questionsArray.questionText就是第一條題目對象的問題屬性 // 然后問題輸入MC的qText文本框中 questionClip.qText = questionsArray[currentQuestion].questionText; // Create the individual answer clips in the question clip // 以下循環(huán)將結(jié)合選項模版生成這一條題目的各個選項的MC // questionsArray[currentQuestion].answers記得嗎?選項這個屬性可是個數(shù)組,所以我們把它的長度作為循環(huán)的次數(shù),這個數(shù)組有多大,我們就生成多少個選項 for (var j = 0; j < questionsArray[currentQuestion].answers.length; j++) { // Attach our linked answerTemplate clip from the Library. // It contains a generalized button and a text field for the question. // 用answerTemplate做模版生成MC,MC名為"answer" + j ,即第一個選項MC名為answer0,第二個為answer1,選項的名字可是關(guān)系到按鈕選什么的,如果你忘了,看看上面有 @@ 標(biāo)記的地方 // 同時它們的深度為j,每次不同 // 但和上面不同的是,我們要把選項MC生成到題目MC里,這樣我們清除題目MC的同時也清除了選項 // 所以寫成questionClip.attachMovie questionClip.attachMovie("answerTemplate", "answer" + j, j); // Place this answer clip in line below the question. // 設(shè)定MC的位置,第一個高度為70,之后順序加15 questionClip["answer" + j]._y += 70 + (j * 15); questionClip["answer" + j]._x -= 100; // Set the text field in the answer clip to the appropriate // element of this question‘s answer array. // 下面語句的:questionClip["answer" + j]可不是指數(shù)組,j=0的時候,它代表questionClip.answer0,具體解釋可見上一章。 // 這句語句的作用是把questionsArray[currentQuestion]這個對象數(shù)組里面的answers[j]數(shù)組,輸入到對應(yīng)的選項MC的answerText文本框中,就是該選項的內(nèi)容 questionClip["answer" + j].answerText = questionsArray[currentQuestion].answers[j]; } //生成選項的循環(huán)結(jié)束 } // Function to register the user‘s answers // 以下是記錄答題者答案的函數(shù),記錄在數(shù)組userAnswers中,和上一例同 // 每一個選項如果被選都會調(diào)用此函數(shù),并用參數(shù)choice傳來作答的答案 function answer (choice) { userAnswers.push(choice); // 判斷是否題目全部完成,是的話清楚掉題目MC,并跳轉(zhuǎn)到quizEnd幀 if (currentQuestion + 1 == questionsArray.length) { questionClip.removeMovieClip(); gotoAndStop ("quizEnd"); } else { // 在這里改變題目的編號,然后調(diào)用makeQuestion函數(shù)再次生成新的題目 currentQuestion++; makeQuestion(currentQuestion); } } // Function to tally the user‘s score // 改題的函數(shù) function gradeUser() { // Count how many questions the user answered correctly for (var j = 0; j < questionsArray.length; j++) { // 將答題數(shù)組userAnswers[j]與問題數(shù)組questionsArray[j]的屬性correctAnswer逐個比較 if (userAnswers[j] == questionsArray[j].correctAnswer) { totalCorrect++; } } // Show the user‘s score in an onscreen text field // 顯示答對與題目數(shù)比 displayTotal = totalCorrect + "/" + questionsArray.length; } 好了,我們來總結(jié)一下這個例子吧 我們已經(jīng)完成了第三個版本結(jié)束時候定下來目標(biāo),更快捷的建設(shè),更便易的擴(kuò)展 我們的題目跟選項都是動態(tài)生成的,也就是說生成10、100題或更多題目也只需要修改questionsArray.as這個文件就可以了 如果說生成兩題這個例子用時要長于上面的例子,那么生成100題,你會發(fā)現(xiàn)用這個例子將是最快的。還有,在100題里面修改其中一題,也是最快的。 看完了例子,希望大家不是只明白了代碼的含義,最重要是理解運(yùn)用對象來編程的方法 同樣的例子,其實還可以用其他的對象結(jié)構(gòu)來完成的 更有效地組織數(shù)據(jù)也是編程藝術(shù)的一部分 為了更進(jìn)一步改進(jìn)我們的例子,最后一個,就是第五個版本,將用XML代替那個存放對象的數(shù)組(也就是在questionsArray.as里那個),它實在太難懂了,是不是???呵呵 XML,名字是不是很COOL啊,其實,F(xiàn)LASH里面用XML不難(其他地方的應(yīng)用就……所以千萬別說XML不難,是FLASH里面用不難),呵呵,好吧,開始吧。
[nextpage]
第十三章 XML XML是一種標(biāo)記語言,通常用于儲存,組織和傳輸數(shù)據(jù) XML文檔主要由一系列的元素(elements)和屬性(attributes)組成,看下面一個XML的例子: Colin Moock O‘Reilly 這個例子就是由元素 BOOK, TITLE, AUTHOR, PUBLISHER 組成的 在元素里就包含了一個屬性:SALUTATION 這些元素怎么讓瀏覽器解釋是什么意思呢?它需要DTD,一套決定這些標(biāo)記的意義的規(guī)則。(例如我們常聽說的WML、SVG,它們都是XML,但對應(yīng)不同的DTD) XML與HTML想比要求格式更嚴(yán)格,格式要求: * tags 一定要嵌套 (就是說有就一定要有) * 一定要有一個根元素 (例如例子中的 BOOK) * 開始部分要用XML聲明標(biāo)記 : 但是AS里面的XML不需要DTD(這就是我說FLASH里面用XML不難的原因,哈哈) 從我們面向?qū)ο蟮慕嵌葋砜?,我們XML的內(nèi)容可以當(dāng)做為對象,下圖就是我們建立XML對象的層次結(jié)構(gòu) FLASH已經(jīng)內(nèi)建有XML類讓我們可以定義自己的XML對象,同時XML對象還有很多方法。 我們還是更進(jìn)一步用例子分析吧,如果我們建立了如上圖的XML對象,那么FLASH首先會自動建立一個元素document.下面才是我們自己的元素。 本來是第一個元素的BOOK成為了document.第一個節(jié)點(diǎn)(node),不過我們把它繼續(xù)當(dāng)我們XML數(shù)據(jù)的根也無妨 當(dāng)一個節(jié)點(diǎn)包含于另一個節(jié)點(diǎn)時,這個節(jié)點(diǎn)稱為另一節(jié)點(diǎn)的子節(jié)點(diǎn)(child),反之另一節(jié)點(diǎn)稱為其的父節(jié)點(diǎn)(parent) 例子中BOOK就是document.child,document.是BOOK的parent 再看圖,BOOK有7個子節(jié)點(diǎn),是不是和你想象不同?多了四個節(jié)點(diǎn)#text,因為FLASH把標(biāo)記之間的空格和回車也讀成一個節(jié)點(diǎn)了。 幾個子節(jié)點(diǎn)的關(guān)系成為兄弟(siblings),如果要找AUTHOR的下一個兄弟(next sibling),F(xiàn)LASH就會給你找來#text 這可不是我們想要的,解決的方法 * 直接在XML里面把空格回車都刪除掉,就是說一個TAG緊挨著一個 * 用AS把無用的子節(jié)點(diǎn)刪除 * 在FLASH讀入XML源數(shù)據(jù)之前,將該XML對象的一個屬性ignoreWhite設(shè)置為true,但是該屬性只在R41版本的PLAYER生效(注:網(wǎng)上可以更新的版本為R41,但是隨FLASH附帶的FLASHPLAYER的版本是R30) 再回到我們的例圖,三個子節(jié)點(diǎn)下面還有子節(jié)點(diǎn),最尾的節(jié)點(diǎn)也可以叫葉節(jié)點(diǎn)。 但是圖里面還有個東西我們沒找到,就是AUTHOR的屬性SALUTATION,屬性不是該節(jié)點(diǎn)的子節(jié)點(diǎn),要訪問我們屬性,要用XML.attributes 概念先說這么多,現(xiàn)在看看我們怎么把XML源程序輸入進(jìn)FLASH 首先定義一個新的XML對象了: mydocument.nbsp= new XML(); 這個對象是空的,我們通過appendChild, par***ML, 和 load 三種方法來輸入數(shù)據(jù) 當(dāng)然我們也可以在定義的時候就輸入數(shù)據(jù):mydocument.nbsp= new XML(‘ hello world! ‘); 這時候我們的mydocument.有了一個叫P的子節(jié)點(diǎn),P的葉節(jié)點(diǎn)是hello world! 之后我們就可以訪問這個XML對象了,firstChild這個XML屬性指向第一個子節(jié)點(diǎn),childNodes是XML對象的子對象,指向所有的子節(jié)點(diǎn) mydocument.firstChild // Accesses P mydocument.childNodes // Also accesses P 兩個AS語句指向的都是節(jié)點(diǎn)P 要訪問葉節(jié)點(diǎn)的內(nèi)容需要屬性nodevalue 我們要顯示P節(jié)點(diǎn)的子節(jié)點(diǎn)的內(nèi)容,就要寫成:trace(mydocument.firstChild.firstChild.nodevalue); 要給它賦值: mydocument.firstChild.firstChild.nodevalue = "goodbye cruel world"; 要刪除P節(jié)點(diǎn),用方法removeNode: mydocument.firstChild.removeNode(); 新建一個節(jié)點(diǎn)叫P,用方法createElement創(chuàng)建元素: newElement = mydocument.createElement("P"); 再將該元素加進(jìn)去作為一個節(jié)點(diǎn),用方法appendChild: mydocument.a(chǎn)ppendChild(newElement); 做一個葉節(jié)點(diǎn)方法類似: newText = mydocument.createTextNode("XML is fun"); mydocument.firstChild.appendChild(newText); 更詳盡的方法還是查閱AS字典吧. 第十四章 最后一個版本選擇題 上一個版本面向?qū)ο蟮拇a對我們這個基于XML的版本很有幫助,上一個版本我們是用對象的數(shù)組來存我們的數(shù)據(jù),這個版本里面,我們使用外部的XML文件 下面先看看XML文件的結(jié)構(gòu): version 1 version 2 version 3 version 4 version 5 version 6 version 3 version 4 version 5 yes no mp3 aiff wav true false java java c++ ecma-262 perl 這個XML里面,QUIZ是我們的根元素 每一題都放在QUESTION元素內(nèi),題目正文為其屬性TEXT,正確答案為其屬性ANSWER(ANSWER=1代表選第二個答案) 每一題的選項則是QUESTION的子節(jié)點(diǎn)CHOICE 其實根本就不用解釋,大家直接看都能看懂 使用了外部XML之后,我們升級題目只需改動XML文件即可,而上一個版本,修改外部AS文件之后還是需要EXPORT一次。 這個版本里面,將保留上個版本大部分的代碼,除了輸入題目數(shù)據(jù)的部分,將用XML來代替。 以下代碼寫到questionsArray.as中覆蓋其原來內(nèi)容 首先仍然定義一個數(shù)組來存放數(shù)據(jù) var questionsArray = new Array(); 然后我們定義一個XML對象來存放XML數(shù)據(jù) var quizDoc = new XML(); 之后是建立將XML解釋為我們存放題目的對象格式的函數(shù)buildQuestionsArray(),同時將它連接到新建的XML對象的onLoad函數(shù),讓XML下載完成之后執(zhí)行這個函數(shù) quizDoc.onLoad = buildQuestionsArray 然后是執(zhí)行下載XML的AS quizDoc.load("quiz.xml"); 最后我們詳細(xì)解說一下解釋XML的函數(shù) // *** builds an array of question objects based on the dom tree in quizDoc function buildQuestionsArray () { // first, strip unwanted whitespace nodes from the tree. // 除去無用的節(jié)點(diǎn),上一章已經(jīng)有介紹無用節(jié)點(diǎn)是如何出現(xiàn)的 stripWhitespaceDoublePass(quizDoc); // now assign a convenient reference to the root QUIZ node // XML文件的根節(jié)點(diǎn)QUIZ節(jié)點(diǎn)就是 quizDoc.childNodes ,這里將其指名為quizNode,以便運(yùn)用 var quizNode = quizDoc.childNodes // for each question node that is a child of the QUIZ node... // 下面的循環(huán)將逐個提取QUIZ節(jié)點(diǎn)的子節(jié)點(diǎn),即每條題目 for(var k = 0; k < quizNode.childNodes.length; k++) { // make an array of the text nodes from each CHOICE node // 為每條題目建立一個選項數(shù)組 var choicesArray = new Array(); // 下面的循環(huán)則是將題目的子節(jié)點(diǎn),即各選項的nodevalue輸入到choicesArray數(shù)組中 for(var j = 0; j < quizNode.childNodes[k].childNodes.length; j++) { choicesArray[j] = quizNode.childNodes[k].childNodes[j].firstChild.nodevalue; } // construct a question object for each QUESTION node, // and store it in questionsArray // 用題目正文、選項數(shù)組、正確答案(正確答案目前還是字符串,所以用Number函數(shù)將之轉(zhuǎn)為數(shù)字)作為參數(shù),建立Question對象(定義Question對象的代碼已經(jīng)在上個例子中解釋了) // 將新建的Question對象作為questionsArray數(shù)組的一個元素 questionsArray[k] = new Question ( Number(quizNode.childNodes[k].attributes.answer), quizNode.childNodes[k].attributes.text, choicesArray); } // done loading and processing the quiz questions loadMsg = ""; // begin the quiz // 調(diào)用函數(shù)makeQuestion,之后的進(jìn)度就同上一個例子了 makeQuestion(currentQuestion); } // *** Strips whitespace nodes from an XML document. // *** by passing twice through each level in the tree // 下面函數(shù)用于除去無用的空白節(jié)點(diǎn),參數(shù)是需要處理的XML的根元素(我們已經(jīng)將其指名為XMLnode了) function stripWhitespaceDoublePass(XMLnode) { // Loop through all the children of XMLnode // 循環(huán)依次將根元素的子元素提取出來 for (var k = 0; k < XMLnode.childNodes.length; k++) { // If the current node is a text node... // 如果該節(jié)點(diǎn)是一個文本節(jié)點(diǎn),就開始以下檢查 ... if(XMLnode.childNodes[k].nodeType == 3) { // ...check for any useful characters in the node. var j = 0; var emptyNode = true; for(j = 0;j < XMLnode.childNodes[k].nodevalue.length; j++) { // A useful character is anything over 32 (space, tab, // new line, etc are all below). // 因為空格、TAB或換行等空白無意義字符的ASCII碼都小于32,檢查若大于32,即為有數(shù)據(jù)的節(jié)點(diǎn),同時用break;跳出檢查的循環(huán) if(XMLnode.childNodes[k].nodevalue.charCodeAt(j) > 32) { emptyNode = false; break; } } // If no useful charaters were found, delete the node. // 若該節(jié)點(diǎn)沒有數(shù)據(jù),就是解釋時的錯誤,將其刪除 if(emptyNode) { XMLnode.childNodes[k].removeNode(); } } } // Now that all the whitespace nodes have been removed from XMLnode, // call stripWhitespaceDoublePass on its remaining children. // 但是還沒完,我們只檢查了所有子節(jié)點(diǎn),而沒有檢查子節(jié)點(diǎn)的子節(jié)點(diǎn),所以以下的循環(huán)將所有子節(jié)點(diǎn)也送到本函數(shù)再繼續(xù)檢查 // 這種函數(shù)自己調(diào)用自己的方法,稱為遞歸,它將一直檢查子節(jié)點(diǎn)的子節(jié)點(diǎn)的子節(jié)點(diǎn)的……一直到該節(jié)點(diǎn)沒有子節(jié)點(diǎn)為止 for(var k = 0; k < XMLnode.childNodes.length; k++) { stripWhitespaceDoublePass(XMLnode.childNodes[k]); } } 現(xiàn)在,我們可以把SWF和XML組成的題目交給一個不會編FLASH的老師了,他只要就會用記事本修改XML文件就行了。
|