當(dāng)前位置:首頁(yè)>軟件教程>maya教程>教程內(nèi)容

mel語(yǔ)初解之一-基礎(chǔ)和界面篇(5)

來(lái)源: 作者:admin 學(xué)習(xí):20369人次

本文主要是針對(duì)初學(xué)Maya的人,如果你已經(jīng)學(xué)了一個(gè)月以上的Maya,那你就可以學(xué)習(xí)這篇mel教程了。

我來(lái)寫一點(diǎn)mel掃盲教程,主要是針對(duì)初學(xué)Maya的人,如果你已經(jīng)學(xué)了一個(gè)月以上的Maya,那你就可以學(xué)習(xí)這篇mel教程了。不一定要等到Maya掌握的非常熟練才去學(xué)mel,相反,如果你在初學(xué)Maya的時(shí)候就對(duì)mel有所了解,那對(duì)于將來(lái)更好的了解和掌握Maya會(huì)起到事半功倍的效果。

當(dāng)然首先要提到的是mel的基本概念,如下:
mel是Maya Embedded Language(Maya內(nèi)置語(yǔ)言)的縮寫,是一種強(qiáng)大的命令和腳本語(yǔ)言,讓你直接控制Maya的特征、進(jìn)程和工作流程。

其次要提到的是應(yīng)該抱怎樣的態(tài)度:
有許多人認(rèn)為mel比較難,我的看法是并不比游戲攻關(guān)難,在網(wǎng)上經(jīng)常看到有人為攻一關(guān)花掉一個(gè)月時(shí)間,學(xué)mel如果能達(dá)到這個(gè)境界一定會(huì)很了不起。學(xué)mel的確可能會(huì)枯躁一些,因?yàn)檎也坏较馛S那么多人給你去殺。
mel是個(gè)可大可小的東西,如果你不是搞程序開發(fā)的,應(yīng)該盡可能的讓mel給你節(jié)省時(shí)間,而不要在學(xué)習(xí)和編寫mel程序上花太多時(shí)間,應(yīng)盡量編寫簡(jiǎn)單且實(shí)用的程序。我的教程也是針對(duì)這一點(diǎn)寫的,如果你已經(jīng)做好了準(zhǔn)備,就和我一起進(jìn)入mel的世界吧。

今天要講的是命令組合。
打開Maya,在命令行(Command Line)輸入"cone"并按回車,視圖中創(chuàng)建了一個(gè)圓錐。如果你沒(méi)有看到命令行,用Display->UI Elements->Command Line來(lái)顯示它。你也許會(huì)問(wèn)用命令行創(chuàng)建圓錐跟用菜單創(chuàng)建有什么差別。我來(lái)告訴你,只是形式上的差別,本質(zhì)上菜單和命令行都是在執(zhí)行mel命令,可以說(shuō)你在Maya中的一舉一動(dòng)都是在執(zhí)行mel命令。

現(xiàn)在打開mel編輯器(Script Editor),mel編輯器分兩部分,上面是歷史窗,下面是編輯窗。歷史窗顯示你剛剛執(zhí)行的命令和命令的結(jié)果或錯(cuò)誤信息。編輯窗可以輸入命令,而且可以輸入多行命令,但每個(gè)MEL 命令之后必須以分號(hào)結(jié)束。選擇mel編輯器的菜單Edit->Clear History,把歷史窗清潔一下。

在編輯窗輸入"cone -ax 0 1 0 -r 1;"并按Ctrl+Enter或數(shù)字鍵那邊的Enter,視圖中創(chuàng)建了正立的一個(gè)圓錐。再看歷史窗,多了兩行,第一行是剛剛執(zhí)行過(guò)的命令,第二行是命令的返回值(Return Result)。我明天會(huì)著重講返回值,今天先來(lái)解釋一下標(biāo)志(Flag)。剛才那個(gè)"-ax"和"-r"就是"cone"命令的標(biāo)志,一般一個(gè)標(biāo)志分長(zhǎng)短兩種寫法,比如"-r"和"-radius"就是同一個(gè)標(biāo)志,寫哪個(gè)都行。長(zhǎng)標(biāo)志看起來(lái)比較清楚,而短標(biāo)志寫起來(lái)比較方便。因此,對(duì)于你比較熟悉的標(biāo)志,盡量用短標(biāo)志,不熟悉的就用長(zhǎng)標(biāo)志。改一下"cone"命令"-r"后面的數(shù)值,比如改成"cone -ax 0 1 0 -r 3"再執(zhí)行,發(fā)現(xiàn)創(chuàng)建出的圓錐半徑變大了,由此你可知道-r/-radius是控制圓錐半徑的。

當(dāng)然"cone"命令還有很多標(biāo)志,要深入了解這個(gè)命令,最好的辦法是看幫助文檔,Maya為此專門提供了一個(gè)mel命令(就是help命令)來(lái)快速察看幫助。執(zhí)行"help -doc cone",就可以打開cone命令的幫助文檔。要想看到所有mel命令的幫助,選擇Maya菜單Help->MEL Command Reference... Maya的幫助文檔中一共收錄了將近一千條mel命令,聽起來(lái)很恐怖吧。不過(guò)沒(méi)關(guān)系,要想在惡劣的環(huán)境下自在的生存,首先要學(xué)會(huì)對(duì)困難視而不見?磶椭鷷r(shí)按分類(Categories)去看,只要翻翻你感興趣的幾個(gè)分類就行了,如果你都不感興趣,就都不要看了,等用到了再去翻也不遲。

現(xiàn)在擺在你面前的一個(gè)嚴(yán)峻的問(wèn)題就是你怎樣從這近一千條mel命令找到你想要的那條命令。別怕,你雖然不熟悉mel,但你還不至于不熟悉Maya的菜單吧。選擇Create->NURBS Primitives->Cone來(lái)創(chuàng)建一個(gè)圓錐,這時(shí)你會(huì)發(fā)現(xiàn)mel歷史窗中多了一行命令,其中"cone -p 0 0 0 -ax 0 1 0 -ssw 0 -esw 360 -r 1 -hr 2 -d 3 -ut 0 -tol 0.01 -s 8 -nsp 1 -ch 1;"就是一個(gè)完整的創(chuàng)建圓錐的命令。在命令行執(zhí)行一下這句命令,會(huì)發(fā)現(xiàn)可以得到跟菜單相同的結(jié)果。有了這種方法,就不用為你掌握的mel命令太少而犯愁了。

你也許已經(jīng)意識(shí)到得到每一步操作的命令意味著什么了,就是可以把這些命令寫在一起,然后一下子執(zhí)行,就像Office里的宏和PhotoShop里的Actions一樣。好,那就開始吧。

現(xiàn)在Maya雖然已經(jīng)支持默認(rèn)燈光渲染了,不過(guò)我們建模時(shí)經(jīng)常還是會(huì)打一盞燈來(lái)觀察一下效果。具體過(guò)程是先創(chuàng)建燈光,再把它移動(dòng)到一個(gè)合適的位置,然后旋轉(zhuǎn)一下角度,然后還要調(diào)整亮度。如果你經(jīng)常要打燈光觀察模型,你一定希望點(diǎn)一個(gè)按鈕來(lái)完成這一切,我們的實(shí)例1就來(lái)解決這個(gè)問(wèn)題吧。
------------------------------------------------------
實(shí)例1:擺放燈光
首先清潔一下mel歷史窗準(zhǔn)備記錄命令。
選擇Create->Lights->Directional Light創(chuàng)建一盞直射燈,把直射燈往左后方移動(dòng)一下,再旋轉(zhuǎn)一下使它的方向指向視圖中心,Ctrl+a打開屬性編輯器,把燈光的屬性(Intensity)改為1.2。
這時(shí)再看看mel歷史窗,多了類似如下幾行:
defaultDirectionalLight(1, 1,1,1, "0", 0,0,0);
move -r -5.393374 -0.124913 3.360977 ;
rotate -r -os -33.086209 0 0 ;
rotate -r -os 0 -24.179269 0 ;
setAttr "directionalLightShape1.intensity" 1.2;

把這幾行字都選中,用鼠標(biāo)左鍵拖放到Shelf工具條上,會(huì)發(fā)現(xiàn)Shelf上多了一個(gè)mel圖標(biāo)。新建一個(gè)文件,按一下這個(gè)mel圖標(biāo),你會(huì)發(fā)現(xiàn)你成功了。

一般用戶編寫的常用的mel程序都是放在Shelf里的,因此你需要對(duì)Shelf了解一下。鼠標(biāo)左鍵在Shelf左下角的三角形那里按下,在下拉菜單選擇Shelf Editor...打開Shelf編輯器。
關(guān)于Shelf編輯器的我就不多講了,你自己瞎按一會(huì)兒也會(huì)弄明白的。我要說(shuō)的是既然你已經(jīng)開始學(xué)mel了,要那么多亂七八糟的Shelf也沒(méi)什么用,你可以只留一個(gè)General,其它的都刪掉,然后新建一個(gè)Shelf,名為myTools。注意我所說(shuō)的這些操作都是在Shelf編輯器中進(jìn)行的,不要跑到"你的文檔\maya\5.0\prefs\shelves"那里去刪Shelf,否則再啟動(dòng)Maya時(shí)那些Shelf會(huì)死而復(fù)生的。更改Shelf圖標(biāo)也在Shelf編輯器中,你可以把那個(gè)難看的mel圖標(biāo)換成你喜歡的美女?纯春萌R塢人用的Maya工作界面,都是自己定制的Shelf,我們別的地方不如人家,這一點(diǎn)還是可以跟人家很像的。

現(xiàn)在來(lái)解釋一下剛才的幾句命令。憑你對(duì)英文的理解,其實(shí)也能猜到這幾句的意思吧。

"defaultDirectionalLight"就是創(chuàng)建一盞直射燈。
"move"就是移動(dòng),"-r/-relative"是經(jīng)常用到的,意思是相對(duì)于物體當(dāng)前的位置。
例如"move -r 1 0 0;"是說(shuō)把物體沿X軸移動(dòng)一個(gè)格子,而"move 1 0 0;"是說(shuō)把物體的"translateX"屬性設(shè)為1,"translateY"和"translateY"屬性設(shè)為0。
"rotate"用了兩次,就是旋轉(zhuǎn)了兩次,看一下右邊通道框里的旋轉(zhuǎn)數(shù)值,你可以把這兩句并作一句,就是"rotate -35.534708 -20.070585 13.771703;"。"-os"是指物體坐標(biāo)軸,相對(duì)"-ws"于世界坐標(biāo)軸而言的。要想讓物體沿世界坐標(biāo)軸旋轉(zhuǎn),雙擊旋轉(zhuǎn)工具圖標(biāo)打開工具設(shè)置窗,把Rotate Mode由Local改為Global即可。
"setAttr"是設(shè)置屬性,這可是一個(gè)關(guān)鍵性的命令,需要重視起來(lái)。

對(duì)于屬性你一定不會(huì)陌生的,它是設(shè)動(dòng)畫的關(guān)鍵。屬性可以在屬性編輯器(Attribute Editor)和通道框(Channel Box)中修改,也可以用mel的"setAttr"直接修改。物體屬性的寫法是物體名+"."+屬性名(object.attribute),屬性名同mel標(biāo)志一樣有長(zhǎng)短兩種寫法。選擇通道的菜單Channels->Channel Names->...可以切換長(zhǎng)短名的顯示,平常看到的那個(gè)"Nice"名只是為了好看,在mel和表達(dá)式中都不中用。
了解屬性對(duì)于我以后要講到的表達(dá)式有決定性的意義,表達(dá)式就是通過(guò)對(duì)物體的屬性與時(shí)間之間、屬性與屬性之間建立某種運(yùn)算關(guān)系來(lái)控制動(dòng)畫的。

根據(jù)前面的說(shuō)法,"move 1 0 0 nurbsCone1;"同樣可以寫成:
setAttr "nurbsCone1.translateX" 1;
setAttr "nurbsCone1.translateY" 0;
setAttr "nurbsCone1.translateZ" 0;
或:
setAttr "nurbsCone1.tx" 1;
setAttr "nurbsCone1.ty" 0;
setAttr "nurbsCone1.tz" 0;

最后讓我們來(lái)編一個(gè)比較實(shí)用的mel命令組合吧。
------------------------------------------------------
多邊形人頭建模時(shí),一般是先建一半臉,建好后再鏡像,再圓滑一下。
你建一半臉的時(shí)候,很難想像出鏡像圓滑后整張臉的樣子吧。你現(xiàn)在學(xué)會(huì)了mel命令組合,可以實(shí)現(xiàn)點(diǎn)一個(gè)按鈕來(lái)完成鏡像和圓滑了,這樣你可以在建模的過(guò)程中預(yù)覽一下完成的效果。這樣有用的程序后面還要繼續(xù)完善下去,先給它起個(gè)形象的名字叫myFullMoon(月圓),版本訂為1.0。
------------------------------------------------------

實(shí)例2:myFullMoon1.0
打開你的半邊臉文件,為了在操作過(guò)程中減少不必要的麻煩,我們先來(lái)把模型規(guī)范化一下:
如果你的模型是右半臉,把它改成左半臉。要保證你能在前視圖看到模型的正面臉,側(cè)視圖看到側(cè)面臉,頂視圖看到頭頂。把模型放到視圖中心線的左邊。選中模型,選擇Modify->Center Pivot,選擇Modify->Freeze Transformations,選擇Display->Component Display->Backfaces不顯示背面,如圖,記住你的模型寬度是幾個(gè)格子。別忘了把mel歷史窗打掃干凈。
規(guī)范好了,就存一下盤。

選中模型,現(xiàn)在可以開始記錄命令了。選擇菜單Edit Polygons->Extrude Face。mel歷史窗記錄了四行命令,你要知道的是只有一行是對(duì)你有用的。想知道為什么?你把每行命令單獨(dú)試試就知道了,只有
polyExtrudeFacet -ch 1 -kft 0 -pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981 -tx 0 -ty 0 -tz 0 -rx 0 -ry 0 -rz 0 -sx 1 -sy 1 -sz 1 -ran 0 -divisions 1 -off 0 -ltz 0 -ws 0 -ltx 0 -lty 0 -lrx 0 -lry 0 -lrz 0 -lsx 1 -lsy 1 -lsz 1 -ldx 1 -ldy 0 -ldz 0 -w 0 -gx 0 -gy -1 -gz 0 -att 0 -mx 0 -my 0 -mz 0 polySurface1.f[0:682];
這句可以擠出面。

現(xiàn)在要在通道框里改幾個(gè)屬性,Keep Face Tog屬性改為on,Scale X為-1,Translate X為模型寬度的負(fù)值(我的是-7.5)。
歷史窗多了三行有用的命令:
setAttr "polyExtrudeFace1.keepFacesTogether" on;
setAttr "polyExtrudeFace1.translateX" -7.5;
setAttr "polyExtrudeFace1.scaleX" -1;

現(xiàn)在你可以看出來(lái)模型面的法線反了,好,把它正過(guò)來(lái)。按F8回到物體選擇模式,選擇Edit Polygons->Normals->Reverse。
這回你該從這幾行命令中看出有用的命令了: polyNormal -normalMode 0 -ch 1 polySurface1.f[0:1449];

下一步是Polygons->Smooth,找到這句命令: polySmooth -mth 0 -dv 1 -c 1 -kb 1 -ksb 1 -khe 0 -kt 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1 polySurface1.f[0:1449];

最后是取消模型的選擇: select -cl ;

好了,操作結(jié)束。來(lái)整理一下有用的命令吧,結(jié)果如下:
polyExtrudeFacet -ch 1 -kft 0 -pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981 -tx 0 -ty 0 -tz 0 -rx 0 -ry 0 -rz 0 -sx 1 -sy 1 -sz 1 -ran 0 -divisions 1 -off 0 -ltz 0 -ws 0 -ltx 0 -lty 0 -lrx 0 -lry 0 -lrz 0 -lsx 1 -lsy 1 -lsz 1 -ldx 1 -ldy 0 -ldz 0 -w 0 -gx 0 -gy -1 -gz 0 -att 0 -mx 0 -my 0 -mz 0 polySurface1.f[0:682];
setAttr "polyExtrudeFace1.keepFacesTogether" on;
setAttr "polyExtrudeFace1.translateX" -7.5;
setAttr "polyExtrudeFace1.scaleX" -1;
polyNormal -normalMode 0 -ch 1 polySurface1.f[0:1449];
polySmooth -mth 0 -dv 1 -c 1 -kb 1 -ksb 1 -khe 0 -kt 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1 polySurface1.f[0:1449];
select -cl ;

把這幾行命令都選中,用鼠標(biāo)左鍵拖放到Shelf工具條上,Shelf上出現(xiàn)mel圖標(biāo)。重新載入模型文件,按一下這個(gè)mel圖標(biāo),你又一次成功了。

對(duì)Maya熟悉一點(diǎn)的人會(huì)覺(jué)得那三個(gè)setAttr用的很愚蠢,因?yàn)橥耆梢栽趐olyExtrudeFacet命令的標(biāo)志中解決問(wèn)題。其實(shí)我們的第一步只是要求做到,第二步才是要求做好。以下是簡(jiǎn)化過(guò)的結(jié)果:
polyExtrudeFacet -ch 1 -kft 1 -pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981 -translateX -7.5 -ty 0 -tz 0 -rx 0 -ry 0 -rz 0 -scaleX -1 -sy 1 -sz 1 -ran 0 -divisions 1 -off 0 -ltz 0 -ws 0 -ltx 0 -lty 0 -lrx 0 -lry 0 -lrz 0 -lsx 1 -lsy 1 -lsz 1 -ldx 1 -ldy 0 -ldz 0 -w 0 -gx 0 -gy -1 -gz 0 -att 0 -mx 0 -my 0 -mz 0 polySurface1.f[0:682];
polyNormal -normalMode 0 -ch 1 polySurface1.f[0:1449];
polySmooth -mth 0 -dv 1 -c 1 -kb 1 -ksb 1 -khe 0 -kt 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1 polySurface1.f[0:1449];
select -cl ;

關(guān)于使用mel命令組合的方法,最后要提到一點(diǎn),如果你執(zhí)行命令時(shí)發(fā)覺(jué)mel歷史窗沒(méi)有變化,可以在mel編輯器勾選Script->Echo All Commands。一般我們不需要顯示那么多命令,因?yàn)楹芏鄬?duì)我們沒(méi)用,所以不選Echo All Commands。

通過(guò)myFullMoon1.0我們可以把一半臉變成整張臉,但如果你發(fā)現(xiàn)這張臉不夠美觀想回到半臉狀態(tài)修改怎么辦?我告訴你,按z鍵撤消上一步操作。這應(yīng)該不是你不知道的,但你可能因旋轉(zhuǎn)相機(jī)觀察而已經(jīng)操作了很多步無(wú)法撤回了,還存了盤。

如果你沒(méi)刪構(gòu)造歷史,那你就是幸運(yùn)的。介紹一個(gè)命令--"delete",就是你按鍵盤delete鍵所執(zhí)行的命令。執(zhí)行"delete polySurface1",瞧,把你那個(gè)整張臉模型都刪去了吧。如果你真的都刪去了,趕快撤消這一步,因?yàn)檫@不是你我想做的事。我們來(lái)編一個(gè)恢復(fù)成半張臉的程序myHalfMoon。

實(shí)例3:myHalfMoon
你一定猜到我這回要用函數(shù)了,對(duì),把下面的幾句代碼執(zhí)行一下:
global proc myHalfMoon()
{
delete polySmoothFace1;
delete polyNormal1;
delete polyExtrudeFace1;
}

執(zhí)行完了,好像不起作用,因?yàn)槟氵不知道它的作用。你不知道你在不知不覺(jué)中已經(jīng)定義了一個(gè)mel命令,命令的名稱就是"myHalfMoon"。試試吧,選中模型,在命令行輸入"myHalfMoon",按回車,命令就起作用了,F(xiàn)在如果說(shuō)myHalfMoon就是個(gè)mel函數(shù),你應(yīng)該覺(jué)得比天書容易理解一點(diǎn)了吧。
------------------------------------------------------
[注]
關(guān)于Maya中的函數(shù)概念問(wèn)題,按以前的說(shuō)法,說(shuō)myHalfMoon是函數(shù)是不嚴(yán)謹(jǐn)?shù)摹?
"A function is a procedure with a return value. " [Maya 4.5 Help docs]
函數(shù)是帶有返回值的程序。

這樣myHalfMoon只能應(yīng)稱之為程序(procedure),帶有返回值的程序才叫函數(shù)(Functions)。不過(guò)這樣反而帶來(lái)麻煩,我很高興看到Maya5.0已經(jīng)改變了這種說(shuō)法。

"User defined functions are called procedures. " [Maya 5.0 Help docs] 用戶定義的函數(shù)稱之為程序(procedure)。以前的定義不見了,言下之意函數(shù)的定義跟返回值沒(méi)什么關(guān)系了。

這下子可能給你帶來(lái)了更多的疑問(wèn),我先回答幾個(gè)吧。

問(wèn):Maya中的mel命令都是通過(guò)mel函數(shù)編出來(lái)的嗎?
答:不是。有900多個(gè)Maya內(nèi)置命令,這些命令是寄生在Maya模塊文件(WinNT版的模塊文件就是dll文件或mll文件),是已經(jīng)編譯好的匯編指令組合。內(nèi)置命令命令一般都帶有標(biāo)志(Flag),而mel函數(shù)命令沒(méi)有標(biāo)志。mel函數(shù)命令通常被稱為“腳本命令”(Script Command),內(nèi)置命令則直接稱“命令”(Command)。

問(wèn):怎樣才能知道一個(gè)命令是不是腳本命令?
答:用whatIs命令。
例如:"whatIs myHalfMoon;",結(jié)果中出現(xiàn)"Mel procedure"(mel程序)字樣,說(shuō)明是腳本命令。

問(wèn):返回值是個(gè)什么東東?
答:以后會(huì)講到的。

相信你一定掌握了把myFullMoon也變成函數(shù)的本領(lǐng)了吧,如果還沒(méi)掌握我可要懷疑你的智商了。不過(guò)呢,反正我的教程也是白癡級(jí)的,我就把它說(shuō)白了吧:
------------------------------------------------------
實(shí)例4:myFullMoon2.0
把Shelf上那個(gè)myFullMoon圖標(biāo)用鼠標(biāo)中鍵拖放到mel編輯窗,把mel代碼灑到編輯窗里。然后把這些代碼寫到"global proc myFullMoon(){ }"的大括號(hào)里,如下:
global proc myFullMoon(){polyExtrudeFacet -ch 1 -kft 1 -pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981 -translateX -7.5 -ty 0 -tz 0 -rx 0 -ry 0 -rz 0 -scaleX -1 -sy 1 -sz 1 -ran 0 -divisions 1 -off 0 -ltz 0 -ws 0 -ltx 0 -lty 0 -lrx 0 -lry 0 -lrz 0 -lsx 1 -lsy 1 -lsz 1 -ldx 1 -ldy 0 -ldz 0 -w 0 -gx 0 -gy -1 -gz 0 -att 0 -mx 0 -my 0 -mz 0 polySurface1.f[0:682];
polyNormal -normalMode 0 -ch 1 polySurface1.f[0:1449];
polySmooth -mth 0 -dv 1 -c 1 -kb 1 -ksb 1 -khe 0 -kt 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1 polySurface1.f[0:1449];
select -cl ;}

我不得不在一開始就強(qiáng)調(diào)格式問(wèn)題,你的代碼雖然沒(méi)錯(cuò),但代碼不只是給機(jī)器用的,還要給人看。以下是改過(guò)格式的代碼:

global proc myFullMoon(){
polyExtrudeFacet -ch 1 -kft 1
-pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981
-translateX -7.5 -ty 0 -tz 0
-rx 0 -ry 0 -rz 0
-scaleX -1 -sy 1 -sz 1
-ran 0 -divisions 1 -off 0 -ltz 0 -ws 0
-ltx 0 -lty 0
-lrx 0 -lry 0 -lrz 0
-lsx 1 -lsy 1 -lsz 1
-ldx 1 -ldy 0 -ldz 0
-w 0
-gx 0 -gy -1 -gz 0
-att 0
-mx 0 -my 0 -mz 0
polySurface1.f[0:682];

polyNormal -normalMode 0 -ch 1
polySurface1.f[0:1449];

polySmooth -mth 0 -dv 1 -c 1
-kb 1 -ksb 1 -khe 0 -kt 1
-sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1
polySurface1.f[0:1449];
select -cl ;
}

格式其實(shí)也沒(méi)有固定的寫法,總之,盡量寫得能讓人看清楚就行了。把這些代碼粘貼到記事本上,然后存成一個(gè)mel文件,注意文件名必須是"myFullMoon.mel"(腳本命令名 + ".mel"),然后把這個(gè)文件放到"我的文檔\e:\My Documents\maya\4.5(5.0)\scripts"目錄中。這樣當(dāng)你每次啟動(dòng)Maya時(shí),"myFullMoon"命令就能像Maya的其它命令一樣工作了。

把Shelf上以前的mel圖標(biāo)刪掉(就是把mel圖標(biāo)用鼠標(biāo)中鍵拖進(jìn)Shelf最右邊的小垃圾桶里)。把"myFullMoon"這幾個(gè)字拖到Shelf上重新建立圖標(biāo)。圖標(biāo)上加幾個(gè)字(mFM),如圖。以后升級(jí)"myFullMoon"的時(shí)候圖標(biāo)命令依舊,只要改"myFullMoon.mel"文件就行了。

"myFullMoon"現(xiàn)在存在一個(gè)很大的缺陷,就是只能對(duì)那個(gè)半邊臉(polySurface1)起作用,換個(gè)物體就不行了,要是程序里那個(gè)"polySurface1"能隨意改成其它多邊形物體就好了。
呵,要想好好,就要使用變量(variable)。

----------------------------------------
Maya的變量名稱必須以一個(gè)美元符號(hào)($)開頭,這是為了和物體名區(qū)別開。這很容易接受,如果可以不寫"$",Maya會(huì)以為你的"polySurface1"也是變量。不過(guò)忘寫美元符號(hào)是視金錢如糞土的mel初學(xué)者常犯的錯(cuò)誤,我盼望大家少犯這種錯(cuò)誤,不要辜負(fù)了Alia$Wavefront的一片苦心。

變量名稱中不能包含有空格或其它的特殊字符,不能用中文。變量名稱是大小寫敏感(Case Sensitive)的,不能有大小寫錯(cuò)誤。mel命令和mel函數(shù)也是大小寫敏感的,同樣不能有大小寫錯(cuò)誤。

下面把有關(guān)變量的一些知識(shí)詳細(xì)介紹一下:
------------------------------------------------------
下面列出了五種數(shù)據(jù)類型:
類型 含義 例子
int 整數(shù) 10 ,-5 ,0
float 小數(shù) 392.6 ,7.0 和-2.667
string 一個(gè)或多個(gè)字母 “What's up, chief?"
Vector 三個(gè)浮點(diǎn)數(shù) 《3 ,7.7 ,9.1 》
matrix 多個(gè)浮點(diǎn)數(shù)組 <<1.1, 2, 3; 6.7, 5, 4.9>>

在上面的類型中,除matrix(矩陣)類型外,都可以構(gòu)成Array(數(shù)組)。一個(gè)數(shù)組是某種數(shù)據(jù)類型的多個(gè)數(shù)據(jù)的序列。例如,一個(gè)包含三個(gè)元素的數(shù)組就是一個(gè)整數(shù),接著一個(gè)整數(shù),再接著一個(gè)整數(shù)。用戶可以把矩陣考慮為一個(gè)包含多個(gè)浮點(diǎn)數(shù)組的數(shù)組,或是一個(gè)二維浮點(diǎn)數(shù)組。
------------------------------------------------------
定義變量和為變量賦值
定義變量就是指明變量屬于何種數(shù)據(jù)類型。為變量賦值就是給一個(gè)定義的變量以指定的數(shù)值。
下面的例子表明了如何使用一個(gè)步驟來(lái)定義和為變量賦值:
int $temp = 3 ;
float $Temp =222.222;
string $tEmp = “Heya kid.”;
vector $teMp = <<1,2.7,3.2>>;
matrix $temP[2][3]=<<4.5,1,0.2;-13,9911,0.007>>;

當(dāng)用戶精確的定義矩陣時(shí),用戶必須指明矩陣的行列數(shù)。下面的例子表明如何為整數(shù)、浮點(diǎn)、字符串和矢量數(shù)組賦值和定義它們。例子:數(shù)組的定義和賦值
int $Temp[5]={100, 1000, -70, 2, 9822};
float $TeMp[4]={ 43.3, -10.7, 0, 82.5};
string $TemP[3]={“Lord”,”Flies”,”cool brown fox2.”};
vector $tEmp[2]={<<0,0,0>>,<<0.01,-2,16>>};

如果一個(gè)變量被定義,但沒(méi)有為其賦值,則Maya 為其分配默認(rèn)的數(shù)值0 ,而對(duì)字符串變量,Maya 為其分配兩個(gè)空引號(hào)。
------------------------------------------------------
Reserved words (保留字)
保留字是一些在MEL 中帶有固定含義的單詞。這些保留字可用于指定變量類型、邏輯控制,或描述一個(gè)數(shù)值。下面就是MEL 中的保留字。break case continue default do
else false float for global
if in int matrix no
off on proc return string
switch true vector while yes

Data type keywords (數(shù)據(jù)類型關(guān)鍵字)
int float vetor string matrix
Boolean constant keywords(布爾關(guān)鍵字)
yes no on off true false
Flow control keywords(流程控制關(guān)鍵字)
if else for while do in
break continue default switch case

其它的關(guān)鍵字
global return source catch alias proc
就像變量名稱,保留字是大小寫敏感的。因此,int 是整數(shù)類型,而Int 就不是。實(shí)際上,alias 、sourcecatch 也是保留字。因?yàn)樗鼈兪褂闷饋?lái),更像命令,它們沒(méi)有包含在上面的表中。

關(guān)于變量的數(shù)據(jù)類型(Data Types),還得從int講起。
int
int是整數(shù)(integer)的意思。例如:
int $i = 3;

有一種布爾類型的數(shù)據(jù),在mel中也用int表示。布爾數(shù)據(jù)只有兩個(gè)值,"是"或"否",mel用"1"或"0"來(lái)表示。因此,下面幾句代碼的作用是相同的。
int $bool = 1;
int $bool = yes;
int $bool = true;
int $bool = on;

與之對(duì)應(yīng)的下面幾句代碼的作用也是相同的。
int $bool = 0;
int $bool = no;
int $bool = false;
int $bool = off;

float
float是小數(shù),也就是浮點(diǎn)數(shù)的意思。例如:
float $f = 3.3333;

浮點(diǎn)運(yùn)算是3d運(yùn)算的重點(diǎn),你一定也注意到了Maya中的大部分物體屬性都是浮點(diǎn)數(shù)值。從表示顏色這一點(diǎn)就可以明顯地看出來(lái)。比如說(shuō)紅色,在網(wǎng)頁(yè)中或平面軟件中的表示為FF0000(255, 0, 0)(整數(shù)),可在3d軟件中,紅色就成了(1.0000, 0.0000, 0.0000)(浮點(diǎn)數(shù))。

下面該講到字符串(string)了,今天的重點(diǎn)就是文字游戲。

"print"命令的用法:
"print"命令可以輸出任何變量的值。如:
string $s = "你好世界";
print $s;
=======================
結(jié)果為:你好世界

string
string是字符串的意思,變量$a是個(gè)字符串,它的值為"你好世界"。
字符串的值要用引號(hào)引起來(lái)。有些情況下你不打引號(hào)Maya也會(huì)猜出是字符串,要我把這些情況一一列舉可是件很麻煩的事,反正你只須知道是字符串打上引號(hào)肯定沒(méi)錯(cuò)誤,而如果你不打引號(hào)讓Maya猜謎的話,Maya一旦猜不出就會(huì)有錯(cuò)誤提示信息,你再根據(jù)此信息來(lái)修正。

轉(zhuǎn)義符(escape character)
引號(hào)里面的字如果也有引號(hào),就把"變?yōu)閈"。和c語(yǔ)言一樣,\為mel的轉(zhuǎn)義符(escape character)。例如:
string $s = "你\"好\"世界";
print $s;
=======================
結(jié)果為:你"好"世界

除了引號(hào)以外,還有一些符號(hào)有時(shí)也要相應(yīng)改變。比如把\變?yōu)閈\,把tab空格變?yōu)閈t,把換行符變?yōu)閈n或\r\n等。

數(shù)組(array)
一旦你對(duì)字符串有了一定的印象,我就可以講幾個(gè)字符處理的mel命令了。
不過(guò)在這之前,還必須要提一提數(shù)組(array)的概念。
一群變量放在一起可以組成一個(gè)數(shù)組,例如:
int $ia[5]={100, 1000, -70, 2, 9822};

你也可以先弄一個(gè)空數(shù)組,然后往里填數(shù)據(jù)。
注意,數(shù)組是從零開始的!。
例如:
string $sa[];
$sa[0] = "你好";
$sa[1] = "世";
$sa[2] = "界";
print $sa;
=======================
結(jié)果為:你好

下面來(lái)講幾個(gè)字符處理的mel命令,當(dāng)然這幾個(gè)命令的出場(chǎng)順序要根據(jù)我們的實(shí)際需要來(lái)安排。這幾個(gè)命令分別為:
substring
tokenize
size
clear
match
substitute

會(huì)了這幾個(gè)命令,對(duì)于字符處理差不多就夠用了。

在講解之前,先把下面一行代碼在命令行執(zhí)行一下:
string $obj = "pSphere1.translateX";
=======================
結(jié)果為:pSphere1.translateX

"substring"命令的用法:
現(xiàn)在得到一個(gè)字符串$obj和它的值,可是這個(gè)值不是我們想要的。我們想要的只是這個(gè)物體的名稱("pSphere1"),而不包括它的屬性(".translateX")。怎樣從$obj中提取物體的名稱呢?方法很多,第一種方法是先指定你要提取的是"pSphere1.translateX"中的第幾個(gè)字符到第幾個(gè)字符。數(shù)數(shù)看,連猴子也能數(shù)出來(lái),"pSphere1"是"pSphere1.translateX"中的第1個(gè)字符到第8個(gè)字符。好了,現(xiàn)在用"substring"命令:

substring $obj 1 8;
=======================
結(jié)果為:pSphere1

獲取命令的返回值
這個(gè)結(jié)果是"substring"命令的返回值,這一點(diǎn)我在第一課里曾提到過(guò)。要想把命令值的返回存到一個(gè)變量里,以便以后使用,有兩種方法:

// 第一種是用"`"的方法,比較常用。
string $objName = `substring $obj 1 8`;
=======================
結(jié)果為:pSphere1

// 第二種是用eval的方法,"eval"對(duì)于執(zhí)行字符串中的命令很有用。
string $objName = eval("substring $obj 1 8");
=======================
結(jié)果為:pSphere1

對(duì)于不需要標(biāo)志的命令,還有第三種方法:
// 這種方法符合學(xué)過(guò)c語(yǔ)言的人的習(xí)慣,用于一些腳本命令很方便。
string $objName = substring($obj, 1, 8);
=======================
結(jié)果為:pSphere1

這三種方法的結(jié)果是一樣的,具體用哪種方法根據(jù)自己的習(xí)慣來(lái)決定。

"tokenize"命令的用法:
下面接著來(lái)講把"pSphere1"從"pSphere1.translateX"中提取出來(lái)的第二種方法,這種方法不用數(shù)數(shù),是一種很實(shí)用的方法。方法是從一個(gè)字符(".")的位置把字符串截成兩段,把這兩段存到一個(gè)字符串?dāng)?shù)組中。具體方法如下:
string $buffer[];
tokenize "pSphere1.translateX" "." $buffer;
string $objName = $buffer[0];
=======================
結(jié)果為:pSphere1

因?yàn)閿?shù)組是從0開始的,$buffer[0]是"pSphere1.translateX"的第一段,它的值是"pSphere1",$buffer[1]是第二段,它的值是"translateX"。

"tokenize"是一個(gè)很有用的命令,我需要再舉幾個(gè)例子把它的用法講明白。
"tokenize"的返回值是把字符串分成的段數(shù),例如用"/"可以把"1/2/3/4/5"分成5份,"tokenize"的返回值就是5。如下:
string $buffer[];
int $numTokens = `tokenize "1/2/3/4/5" "/" $buffer`;
=======================
結(jié)果為:5

如果不指定分割字符,"tokenize"會(huì)根據(jù)一個(gè)默認(rèn)的空格字符來(lái)分割。例如:
string $buffer[];
tokenize "How are you?" $buffer;
print $buffer;
=======================
結(jié)果為:How
are
you?
也就是: $buffer[0]=="How"; $buffer[1]=="are"; $buffer[2]=="you?";

"size"命令的用法:
"tokenize"的返回值可以表示字符串被分成的段數(shù),通過(guò)衡量這個(gè)字符串的大小也可以得知字符串被分成的段數(shù),這就要用到"size"命令:

string $buffer[];
tokenize "1/2/3/4/5" "/" $buffer;
int $numTokens = `size $buffer`;
=======================
結(jié)果為:5

"size"命令可以求出一個(gè)數(shù)組是由多少個(gè)元素組成,也可以求出一個(gè)字符串是由多少個(gè)字符組成。剛才說(shuō)道猴子能數(shù)出"pSphere1"是由8個(gè)符組成,現(xiàn)在你不用數(shù)也會(huì)知道這一點(diǎn),你知道我的意思當(dāng)然不是指你就是猴子:
int $size = `size "pSphere1"`;
=======================
結(jié)果為:8

要注意的是一個(gè)中文字占用兩個(gè)字節(jié),"size"為2!
int $size = `size "中文"`;
=======================
結(jié)果為:4

"clear"命令的用法:
對(duì)于一些"size"很大的數(shù)組,會(huì)占用很多內(nèi)存,你不用時(shí)要用"clear"把它清空。清空后它的"size"為0。
int $buffer[5]={1, 2, 3, 4, 5};
clear $buffer;
=======================
結(jié)果為:0

"match"命令的用法:
"match"是字符串中的查找功能,返回值是一個(gè)字符串。如果找到了,就返回要找的字符串,沒(méi)找到,就返回""。例如:
match "this" "this is a test";
=======================
結(jié)果為:this

match "that" "this is a test";
=======================
結(jié)果為:

"match"命令可以使用通配符,以下是使用規(guī)則:
. 代表任何一個(gè)單獨(dú)的字符
* 代表0個(gè)或多個(gè)字符
+ 代表1個(gè)或多個(gè)字符
^ 代表一行中第一個(gè)字符的位置
$ 代表一行中最后一個(gè)字符的位置
\ 轉(zhuǎn)義符(escape character). 把它寫在特殊的字符前面(如 '*')
[...] 代表指定范圍內(nèi)的任意一個(gè)字符
(...) 用于把部分通配符表述組織在一起

例:
match "a*b*" "abbcc";
=======================
結(jié)果為:abb

match "a*b*" "bbccc";
=======================
結(jié)果為:bb

match "a+b+" "abbcc";
=======================
結(jié)果為:abb

match "^the" "the red fox";
=======================
結(jié)果為:the

match "fox$" "the red fox";
=======================
結(jié)果為:fox

match "[0-9]+" "sceneRender019.iff";
=======================
結(jié)果為:019

match "(abc)+" "123abcabc456";
=======================
結(jié)果為:abcabc

match("\\^.", "ab^c");
=======================
結(jié)果為:^c

"substitute"命令的用法:
"substitute"是字符串中的替換功能,返回值是一個(gè)字符串,返回替換后的結(jié)果。例如:
string $text = "ok?";
$text = `substitute "?" $text "!"`;
=======================
結(jié)果為:ok!

也可以通過(guò)此方法把不想要的字符去掉。例如:
string $text = "ok?";
$text = `substitute "?" $text ""`;
=======================
結(jié)果為:ok

下面是"substitute"使用通配符的方法:
string $test = "Hello ->there<-";
string $regularExpr = "->.*<-";
string $s1 = `substitute $regularExpr $test "Mel"`;
=======================
結(jié)果為:Hello Mel

字符串的聯(lián)合(unite)
最后講一下字符串的聯(lián)合(unite)。
字符串可以做加法,但不能做減法:
string $s1 = "你好";
string $s2 = "世界";
string $text = $s1 + $s2;
=======================
結(jié)果為:你好世界

字符串的加法跟數(shù)字的加法不同:
int $i = 1 + 2 + 3;
=======================
結(jié)果為:6

string $s = "1" + "2" + "3";
=======================
結(jié)果為:123

+=
以下兩種寫法的結(jié)果是相同的:
string $s = "你好";
$s = $s + "世界";
=======================
結(jié)果為:你好世界

string $s = "你好";
$s += "世界";
=======================
結(jié)果為:你好世界

添加注釋
為了增加mel程序的可讀性,你可以在你的mel代碼中添加注釋。注釋可起到解釋、提示或描述腳本的作用,程序執(zhí)行時(shí)會(huì)跳過(guò)這些注釋,執(zhí)行注釋以外的代碼。mel的注釋跟c語(yǔ)言是一樣的。
--------------------------------------------
單行注釋
如果要?jiǎng)?chuàng)建單行的注釋,輸入兩個(gè)反斜線(//),然后輸入注釋:
int $locator = 7; //Default locator number is lucky.
--------------------------------------------
多行注釋
如果要?jiǎng)?chuàng)建多行的注釋,輸入一個(gè)反斜線加一個(gè)星號(hào)(/*)。在注釋的結(jié)束,輸入一個(gè)星號(hào)加反斜線(*/)。
用戶可以在一行或多行的某部分中使用這種注釋。
/*This is an example of a
variable-line comment.*/
--------------------------------------------
注意,在表達(dá)式中不能使用多行注釋技術(shù),表達(dá)式中只能使用單行注釋(//)。

上一課講到了獲取命令的返回值,有了這種方法,就可以繼續(xù)我們的"myFullMoon"了。我們可以把選中的物體名稱存入一個(gè)變量,再根據(jù)物體名稱對(duì)物體進(jìn)行處理。
--------------------------------------------
獲取選中物體的名稱
"ls"命令的用法:
ls -sl的意思就是獲得選擇物體的名稱,要想對(duì)物體進(jìn)行操作這是必然的一步。
我來(lái)具體演示一下方法,以便大家更好的掌握。

實(shí)例5:選擇物體清單
新建一個(gè)場(chǎng)景,創(chuàng)建一盞直射燈、一個(gè)多邊形球,一個(gè)多邊形方塊,一個(gè)Nurbs平面,一個(gè)Nurbs圓柱,一個(gè)細(xì)分方塊。如圖。
選中所有物體,然后執(zhí)行"ls -sl"命令:
ls -sl;
=======================
結(jié)果為:pSphere1 pCube1 nurbsCylinder1 subdivCube1 directionalLight1 nurbsPlane1

下面編個(gè)程序以清單的形式輸出物體名稱:
global proc printObjNameSheet()
{
string $objects[] = `ls -sl`;
int $num = `size $objects`;

string $objNameSheet;
for($i=0; $i<$num; $i++)
{
$objNameSheet += $i+1;
$objNameSheet += ")";
$objNameSheet += $objects[ $i ];
$objNameSheet += "\n";
}

string $output = "\n*******************\n";
$output += "一共選擇了";
$output += $num; // 注意$num不能寫成"$num"
$output += "個(gè)物體\n";
$output += "它們分別是:\n";
$output += $objNameSheet;

print $output;
}
printObjNameSheet;
--------------------------------------------
把上面的代碼拉到Shelf上,隨便選擇幾個(gè)物體,然后執(zhí)行這些代碼,就會(huì)看到mel歷史窗中輸出的物體名稱清單。

由于上一課已經(jīng)講過(guò)了字符處理的方法,相信你上面的大部分代碼都看得懂。不過(guò),"for($i=0; $i<$num; $i++)"這種語(yǔ)法以前沒(méi)講過(guò),現(xiàn)在來(lái)具體講講。
$i++
$i++的意思就是$i=$i+1或$i+=1。

for語(yǔ)句
for語(yǔ)句是一個(gè)典型的循環(huán)語(yǔ)句。我下面具體分析一下。

string $objects[] = `ls -sl`;
int $num = `size $objects`;

如圖,已知我們選中了三個(gè)物體,物體名分別存入了$objects數(shù)組中。
跟據(jù)我們所知的,用代數(shù)的方法把所知的值代入變量中,就有了以下結(jié)果:
$num == 3;
$objects[0] == nurbsPlane1;
$objects[1] == directionalLight1;
$objects[2] == pSphere1;

--------------------------------------------
string $objNameSheet;
for($i=0; $i<$num; $i++)
{
$objNameSheet += $i+1;
$objNameSheet += ")";
$objNameSheet += $objects&i;;
$objNameSheet += "\n";
}


繼續(xù)用代數(shù)的方法:
//當(dāng)$i=0時(shí):
$objNameSheet += 0+1;
//這時(shí):$objNameSheet == "1"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)"
$objNameSheet += $objects[0];
//這時(shí):$objNameSheet == "1)nurbsPlane1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n"

//當(dāng)$i=1時(shí):
$objNameSheet += 1+1;
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)"
$objNameSheet += $objects[1];
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n"

//當(dāng)$i=2時(shí):
$objNameSheet += 2+1;
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)"
$objNameSheet += $objects[2];
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1\n"

//當(dāng)$i=3時(shí):
// $i = $num 結(jié)束循環(huán)


--------------------------------------------
因?yàn)閙el不能設(shè)斷點(diǎn)進(jìn)行調(diào)試分析,我只好用這種笨辦法來(lái)分析了,但愿你能看懂。

注意for語(yǔ)句分號(hào)的位置,初學(xué)者常會(huì)在這里出錯(cuò),不要把分號(hào)寫在那個(gè)小括號(hào)的后面。大括號(hào)后面也不要寫分號(hào)。

關(guān)于獲取選中物體的名稱,再舉一個(gè)例子。例如,你想把所有選中的物體沿x軸移動(dòng)5:最簡(jiǎn)單的方法當(dāng)然是: move -r -x 5;
不過(guò),為了演示ls -sl的用法,請(qǐng)看下面的代碼:
string $objects[] = `ls -sl`; // 獲取選擇物體名稱
int $num = `size $objects`; // 獲得物體的數(shù)量
for($i=0; $i<$num; $i++)
{
select -r $object;
move -r -x 5;
}

in
還有一種方法可以達(dá)到同樣的效果:
string $objects[] = `ls -sl`; // 獲取選擇物體名稱
for($object in $objects)
{
select -r $object;
move -r -x 5;
}

"filterExpand"命令的用法:
不過(guò)"ls -sl"是獲得所有選擇物體的名稱,如果你只想對(duì)選擇物體中的多邊形物體進(jìn)行操作,最好的方法是不用"ls",而用"filterExpand"。
// -sm 12是多邊形物體, -sm 10是Nurbs表面,其它的請(qǐng)
// 參看filterExpand命令的幫助文檔(help -doc filterExpand;)。
string $polygons[] = `filterExpand -sm 12`;
for($polygon in $polygons)
{
select -r $polygon;
move -r -x 5;
}

--------------------------------------------
[注]
用"ls"命令也有辦法達(dá)到與"filterExpand"類似的效果,為了減輕你們的學(xué)習(xí)復(fù)擔(dān),我就不多講了。用"filterExpand"更簡(jiǎn)便一些。

選中剛才那個(gè)場(chǎng)景的全部物體,下面的代碼分類輸出選擇物體的名稱:

global proc printObjNameSheet()
{
int $num;
string $polygons[] = `filterExpand -sm 12`;
string $nurbs[] = `filterExpand -sm 10`;
string $polyNNurbs[] = `filterExpand -sm 10 -sm 12`;

string $output = "\n*******************\n";
$output += "一共選擇了";
$num = `size $polygons`;
$output += $num + "個(gè)多邊形物體\n它們是:\n";

print $output;
print $polygons;

$output = "\n一共選擇了";
$num = `size $nurbs`;
$output += $num + "個(gè)Nurbs物體\n它們是:\n";

print $output;
print $nurbs;

$output = "\n選擇的物體中Nurbs物體和多邊形物體共有";
$num = `size $polyNNurbs`;
$output += $num + "個(gè)\n它們是:\n";

print $output;
print $polyNNurbs;
}
printObjNameSheet;

如何判斷選擇的是面,還是點(diǎn),還是邊呢?如下:

// 多邊形點(diǎn)
string $vertices[] = `filterExpand -ex 1 -sm 31`;
// 多邊形邊
string $edges[] = `filterExpand -ex 1 -sm 32`;
// 多邊形面
string $faces[] = `filterExpand -ex 1 -sm 34`;

// 如果框選很多,要想獲取其中的nurbs和polygon物體,-sm可以出現(xiàn)不止一次。
string $polygons[] = `filterExpand -sm 10 -sm 12`;

選擇一些多邊形物體的面,下面的代碼輸出面的名稱:
global proc printObjNameSheet()
{
int $num;
string $faces[] = `filterExpand -sm 34`;

string $output = "\n*******************\n";
$output += "一共選擇了";
$num = `size $faces`;
$output += $num + "個(gè)面\n它們是:\n";

print $output;
print $faces;
}
printObjNameSheet;

"filterExpand -ex/expand"的用法
關(guān)于filterExpand -ex/expand的用法,如果懶得看help,看下面的吧:
Object Type / Mask
Handle 0
Nurbs Curves 9
Nurbs Surfaces 10
Nurbs Curves On Surface 11
Polygon 12
Locator XYZ 22
Orientation Locator 23
Locator UV 24
Control Vertices (CVs) 28
Edit Points 30
Polygon Vertices 31
Polygon Edges 32
Polygon Face 34
Polygon UVs 35
Subdivision Mesh Points 36
Subdivision Mesh Edges 37
Subdivision Mesh Faces 38
Curve Parameter Points 39
Curve Knot 40
Surface Parameter Points 41
Surface Knot 42
Surface Range 43
Trim Surface Edge 44
Surface Isoparms 45
Lattice Points 46
Particles 47
Scale Pivots 49
Rotate Pivots 50
Select Handles 51
Subdivision Surface 68
Polygon Vertex Face 70
NURBS Surface Face 72
Subdivision Mesh UVs 73

前面的準(zhǔn)備就緒,現(xiàn)在來(lái)繼續(xù)myFullMoon的新版。

實(shí)例6:myFullMoon3.0
前面提到過(guò)升級(jí)"myFullMoon"的時(shí)候圖標(biāo)命令依舊,只要改"myFullMoon.mel"文件就行了。
現(xiàn)在打開"myFullMoon.mel"文件,用下面的代碼替換掉原來(lái)的代碼:

// myFullMoon3.0
global proc myFullMoon()
{
string $polygons[] = `filterExpand -sm 12`;
// 如果選擇了多個(gè)多邊形物體,只對(duì)第一個(gè)進(jìn)行操作
string $polygon = $polygons[0];

select -r $polygon;
ConvertSelectionToFaces; // 轉(zhuǎn)換為選擇面模式

polyExtrudeFacet -ch 1 -kft 1
-pvx -3.926295877 -pvy -1.118658066 -pvz 4.649739981
-translateX -7.5 -ty 0 -tz 0
-rx 0 -ry 0 -rz 0
-scaleX -1 -sy 1 -sz 1
-ran 0 -divisions 1 -off 0 -ltz 0 -ws 0
-ltx 0 -lty 0
-lrx 0 -lry 0 -lrz 0
-lsx 1 -lsy 1 -lsz 1
-ldx 1 -ldy 0 -ldz 0
-w 0
-gx 0 -gy -1 -gz 0
-att 0
-mx 0 -my 0 -mz 0;

polyNormal -normalMode 0 -ch 1;

polySmooth -mth 0 -dv 1 -c 1
-kb 1 -ksb 1 -khe 0 -kt 1
-sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
select -cl ;
}

現(xiàn)在這些代碼還不會(huì)生效,直到你關(guān)閉再重新打開Maya。要想讓mel文件里的代碼立即生效,需要Source Script。有三種方法可以Source Script:
1. 選擇mel編輯器菜單File->Source Script...,打開"myFullMoon.mel"文件。
2. 把"myFullMoon.mel"文件直接拖放到Maya視圖窗口中。
3. 使用"source"命令。

"source"命令的用法:
通過(guò)"source"命令可以執(zhí)行mel文件中的代碼。例如:
source "c:/temp/myFullMoon.mel";
或:
source "c:\\temp\\myFullMoon.mel";

如果你的mel文件是放在Maya的Script目錄(我的文檔\e:\My Documents\maya\4.5(5.0)\scripts),"source"命令可以不指定路徑:
source "myFullMoon.mel";

Source了"myFullMoon.mel"之后,就可以試試了。
選中以前那個(gè)半邊臉模型,給它改個(gè)名字,再按"myFullMoon"命令的Shelf圖標(biāo),可以看到新代碼起作用了。

當(dāng)然現(xiàn)在又來(lái)了新的問(wèn)題,還記得以前用的模型寬度是7.5吧,每個(gè)模型的寬度是不同的,模型寬度也應(yīng)該是個(gè)變量。要想獲得模型寬度,需要用到邊界框(Bounding Box),獲取邊界框是以后要做的事情,我把它放到建模部分講。

前面講了很多東西,你可能還要慢慢消化。不過(guò)如果你真的能把前面講的都理解了,相信你的mel已經(jīng)入門了。從下一課開始,我來(lái)講用mel編寫界面的方法。

Maya幫助文檔中把編寫界面的mel命令稱為ELF命令。
"Most ELF commands create and modify UI elements. " [Maya Help docs]
大部分ELF命令創(chuàng)建和修改UI元素。

"ELF","UI"這么多縮寫真的很讓人感到厭煩。
"ELF" - Extended Layer Framework(擴(kuò)展層框架)
這個(gè)詞匯有點(diǎn)多余,我會(huì)盡可能少提到它。

"UI" - User Interface(用戶界面)
用戶界面的含義相信大多數(shù)人都知道,用戶界面又稱人機(jī)界面,實(shí)現(xiàn)用戶與計(jì)算機(jī)之間得通信,以控制計(jì)算機(jī)或進(jìn)行用戶和計(jì)算機(jī)之間得數(shù)據(jù)傳送得系統(tǒng)部件。具體的說(shuō),我們平常使用的窗口、菜單、按鈕等都是用戶界面的元素。
"界面"
我們平常所說(shuō)的界面都是指“用戶界面”,因?yàn)槌绦騿T是少數(shù)派,用戶才是上帝,所以用戶們從來(lái)不怕直接說(shuō)界面會(huì)被別人誤解為“應(yīng)用程序設(shè)計(jì)界面”。我后面也把用戶界面簡(jiǎn)稱為界面,希望不要給我糾正。

[注]
"API" - Application Programming Interface
有幾種不同譯法:應(yīng)用程序界面,應(yīng)用程序設(shè)計(jì)界面,應(yīng)用程序接口。這是一種專門給程序員使用的界面或接口,例如Maya API。

現(xiàn)在來(lái)編寫一個(gè)窗口。用mel編寫一個(gè)窗口就像創(chuàng)建一個(gè)球或者方塊那么簡(jiǎn)單。

"window"命令 (創(chuàng)建窗口)
在命令行輸入"window"(打字的候要小心,不要讓視窗變成寡婦window-widow)然后回車,一個(gè)窗口就創(chuàng)建好了。不要因?yàn)闆](méi)看到有什么變化而認(rèn)為我在欺騙你,"window"命令創(chuàng)建的窗口在默認(rèn)情況下是不可見的,換句話說(shuō),"window"命令的"-vis/-visible"的默認(rèn)參數(shù)值為0(或false),也就是說(shuō)直接輸入"window"命令和輸入"window -visible false"是等效的。

"showWindow"命令 (顯示窗口)
要想創(chuàng)建可以看得到的窗口,有兩種方法。一種方法是在創(chuàng)建窗口時(shí)用"window -visible true",另一種方法是創(chuàng)建窗口后執(zhí)行"showWindow"命令。這時(shí)我會(huì)推薦你用第二種方法,"showWindow"的好處是既顯示窗口,又把這個(gè)窗口推到所有窗口的最前面。

好,現(xiàn)在就在命令行輸入"showWindow"并回車,一個(gè)窗口便顯示了出來(lái)。

唯一的命名
因?yàn)槟憧梢詣?chuàng)建很多個(gè)窗口,因此如果想完全控制每個(gè)窗口,就必須給每個(gè)窗口指定一個(gè)唯一的命名。執(zhí)行下面兩句命令:
-----------------------------------------
window -t "我的測(cè)試窗" myTestWin;
showWindow myTestWin;
-----------------------------------------
這里"myTestWin"就是窗口的名字。
"-t/-title"的用途想必不用我多作解釋了吧?

當(dāng)一個(gè)窗口創(chuàng)建時(shí),會(huì)另人想到另一個(gè)問(wèn)題,就是怎么把它銷毀(刪除)。點(diǎn)窗口右上角標(biāo)題欄上的那個(gè)"×"可以關(guān)閉窗口,然而關(guān)閉窗口卻蘊(yùn)含著兩層意思。在大多數(shù)情況下,關(guān)閉窗口可以銷毀窗口,有少數(shù)情況,關(guān)閉窗口以后窗口只是處于不可見狀態(tài),窗口并沒(méi)被銷毀,你隨時(shí)可以用"showWindow"命令來(lái)顯示它。用"-ret/-retain"標(biāo)志創(chuàng)建的窗口就屬于這種少數(shù)情況。

"deleteUI"命令 (銷毀界面元素)
要想讓徹底銷毀窗口,使用"deleteUI"命令。"deleteUI"可以銷毀任何界面元素,包括布局、控件和菜單。在命令行輸入"deleteUI myTestWin"并回車,"myTestWin"就被銷毀了。

為方便以后對(duì)于這個(gè)窗口代碼的調(diào)用,我們來(lái)編寫一個(gè)函數(shù)。
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) // 如果myTestWin窗口已經(jīng)存在了
deleteUI myTestWin; // 就把myTestWin銷毀

window -t "我的測(cè)試窗" myTestWin;
showWindow myTestWin;
}
myTest;

"if"語(yǔ)句
這里用到了if語(yǔ)句,我覺(jué)得if語(yǔ)句是最容易理解的語(yǔ)句,把"if"直譯成"如果"就可以理解。if后面那個(gè)小括號(hào)里的代碼表示的只能是一個(gè)布爾值,是(1, true)或否(0, false)。當(dāng)表示否時(shí),可以在前面加一個(gè)嘆號(hào),"!"可以直譯成"不"。例如:
if(!`window -ex myTestWin`) // 表示如果myTestWin窗口不存在
也就是:
if(`window -ex myTestWin` == false) // `window -ex myTestWin`的返回值為0

現(xiàn)在只是編寫了一個(gè)空的窗口,要是想往窗口中添加一些按鈕或者文本框什么的怎么辦呢?

控件,布局
按鈕或者文本框這些東東統(tǒng)稱控件(control),mel擺放控件的特色是使用布局(layout)。在不同的布局中,控件擺放的方法不同,比如豎布局(columnLayout)中的控件都是一個(gè)挨一個(gè)豎著擺放的,而橫布局(rowLayout)中的控件都是橫著排列的。

"window"命令之后必須有一個(gè)布局,這個(gè)布局作為窗口的主布局,其它控件或布局都放置在這個(gè)主布局之中。

層級(jí)關(guān)系
由于布局之中既可以放布局又可以放控件,因此布局與控件,布局與布局之間構(gòu)成了一種層級(jí)關(guān)系(父子關(guān)系)。例如,布局columnLayout2在布局columnLayout1之中,columnLayout1稱為columnLayout2的父布局(Parents),columnLayout2稱為columnLayout1的子布局(Children)。

"setParent"命令 (指定當(dāng)前布局)
默認(rèn)的,剛剛創(chuàng)建的布局為當(dāng)前布局,新建的布局或控件都建在當(dāng)前布局中。要想使以前創(chuàng)建的布局成為當(dāng)前布局,使用setParent命令:"setParent 布局名"。要想使上一級(jí)布局(父布局)成為當(dāng)前布局,使用"setParent .."。

"columnLayout"命令 (豎布局)
對(duì)于不在乎界面美觀的人來(lái)說(shuō),學(xué)會(huì)一個(gè)豎布局差不多就足夠了。
豎布局中的控件都是一個(gè)挨一個(gè)豎著擺放的,請(qǐng)看下面的代碼:
-------------------------------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`)
deleteUI myTestWin;

window -t "我的測(cè)試窗" myTestWin;
columnLayout -adj 1; // 主布局
text -l "圓錐名稱";
// 和控制窗口一樣,要想控制控件,也要給控件一個(gè)唯一的命名。
// 這里文本框(textField)控件的名字為"myConeNameFld"
textField -tx "cone" myConeNameFld;
button -l "創(chuàng)建圓錐" -c "cone";
button -l "刪除" -c "delete";

showWindow myTestWin;
}
myTest;
-------------------------------------------------------------
執(zhí)行這段代碼,不要關(guān)掉生成的窗口。
"text"命令 (靜態(tài)文本)
"textField"命令 (文本框)
"button"命令 (按鈕)

這里用到三個(gè)關(guān)于界面的mel命令:"text","textField","button"。
根據(jù)生成的窗口你就可以猜到這三個(gè)命令的意思。
"text"為靜態(tài)文本,"textField"為文本框,"button"為按鈕。
"-l/-label"可能是界面命令中最明顯、最容易理解的標(biāo)志了,意思是界面元素的標(biāo)簽。
"-tx/-text"是文本框中的文字。
"-c/-command"是要執(zhí)行的mel命令,注意這個(gè)命令是一個(gè)字符串,一般要用引號(hào)引起來(lái)。
"-adj"決定是否自動(dòng)調(diào)整布局內(nèi)控件的寬度。

"-q/-query"(查詢)和"-e/-edit"(編輯)標(biāo)志
這是兩個(gè)非常特殊又非常有用的標(biāo)志,所有的界面命令都用到這兩個(gè)標(biāo)志。
"-q/-query" 表示查詢的意思,你可以通過(guò)它獲得某一標(biāo)志的數(shù)值。
"-e/-edit" 表示編輯的意思,你可以通過(guò)它修改某一標(biāo)志的數(shù)值。

下面舉例說(shuō)明它們的用法:
在剛才創(chuàng)建的窗口的文本框中隨便輸入幾個(gè)字,在命令行輸入"textField -q -tx myConeNameFld"并回車,可以在輸出窗口中看到文本框中的字。
在命令行輸入"textField -e -tx "change" myConeNameFld"并回車,文本框中的字就變成了"change"。前面說(shuō)過(guò)"deleteUI"可以銷毀任何界面元素,在命令行輸入"deleteUI myConeNameFld"并回車,文本框消失了。

獲取本框中的文字
編寫按鈕命令

要想創(chuàng)建的圓錐根據(jù)本框中的文字來(lái)命名,使用下面的代碼:
-----------------------------------------
// 先編寫一個(gè)函數(shù)(createCone),然后在按鈕命令中調(diào)用這個(gè)函數(shù)。
global proc createCone()
{
string $name = `textField -q -tx myConeNameFld`; // 獲取文本框中的文字
cone -name $name; // 用文本框中的文字為名稱創(chuàng)建圓錐
}

global proc myTest()
{
if(`window -ex myTestWin`)
deleteUI myTestWin;

window -t "豎布局(columnLayout)測(cè)試窗" myTestWin;
columnLayout -adj 1;
text -l "圓錐名稱";
textField -tx "cone" myConeNameFld;
button -l "創(chuàng)建圓錐" -c "createCone"; // 按鈕命令中調(diào)用createCone函數(shù)
button -l "刪除" -c "delete";

showWindow myTestWin;
}
myTest;
-----------------------------------------
改一下文本框中的字,按"創(chuàng)建圓錐"按鈕,這時(shí)創(chuàng)建的圓錐是按照文本框中的文字命名的。注意,對(duì)物體命名時(shí)不能使用標(biāo)點(diǎn)符號(hào),不能使用大多數(shù)的中文字,具體原因在后面講到如何用mel判斷物體名稱是否合法時(shí)再解釋。

下面講幾個(gè)常用布局:

"rowColumnLayout"命令 (橫豎布局)
控件橫豎排列的布局:
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "橫豎布局(rowColumnLayout)測(cè)試窗" myTestWin;
rowColumnLayout -nc 3 -cw 1 60 -cw 2 80 -cw 3 100; // 橫豎布局
button; button; textField;
button; textField; button;
button;

showWindow myTestWin;
}
myTest;
-----------------------------------------
"-nc/numberOfColumns"指定一共有幾列。
"-cw/columnWidth"指定某一列的寬度。
"-cw 1 60"第一列的寬度為60像素。
"-cw 2 80"第二列的寬度為80像素。以此類推。

"scrollLayout"命令 (滾動(dòng)布局)
滾動(dòng)布局中只能放布局,不能放控件。
滾動(dòng)布局可以給它的子布局加上滾動(dòng)條。
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "滾動(dòng)布局(scrollLayout)測(cè)試窗" myTestWin;
scrollLayout;
columnLayout;
button;button;button;button;button;
button;button;button;button;button;

showWindow myTestWin;
}
myTest;

"frameLayout"命令 (邊框布局)
邊框布局中只能放布局,不能放控件。
下面的代碼提供幾種不同風(fēng)格的邊框:
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "邊框布局(frameLayout)測(cè)試窗" myTestWin;
columnLayout -adjustableColumn true;
// 第一種:可折疊邊框
// 你熟悉的Attribute Editor和Tool Settings等窗口就是用的這種邊框
frameLayout -label "Collapsable" -collapsable on -borderStyle "etchedIn"; // 可折疊
columnLayout;
text -l "-cl/collapse 0 -折疊";
text -l "-cl/collapse 1 -展開";
setParent ..;
setParent ..;
// 其它幾種標(biāo)簽在邊框線的位置不同,邊框線的風(fēng)格不同,如圖。
// 第二種:
frameLayout -label "Buttons" -labelAlign "top" -borderStyle "in";
columnLayout;
button; button;
setParent ..;
setParent ..;
// 第三種:
frameLayout -label "Scroll Bars" -labelAlign "center" -borderStyle "out";
columnLayout;
intSlider; intSlider;
setParent ..;
setParent ..;
// 第四種:
frameLayout -label "Fields" -labelAlign "center" -borderStyle "etchedIn";
columnLayout;
intField; intField;
setParent ..;
setParent ..;
// 第五種:
frameLayout -label "Check Boxes" -labelAlign "bottom" -borderStyle "etchedOut";
columnLayout;
checkBox; checkBox;
setParent ..;
setParent ..;

showWindow myTestWin;
}
myTest;
-----------------------------------------
"-cll/collapsable"邊框是否可折疊。
"-cl/collapse"如果邊框可折疊,現(xiàn)在是否折疊。
"-bs/borderStyle"邊框線的風(fēng)格,可用值為:"in", "out", "etchedIn", 或 "etchedOut"。
"labelAlign"邊框標(biāo)簽的對(duì)齊方式,可用值為:are "top", "center", 或 "bottom"。

"paneLayout"命令 (窗格布局)
窗格布局一個(gè)很明顯的特點(diǎn)就是有分隔線分隔窗格面板,你可以移動(dòng)分隔線來(lái)調(diào)整窗格面板的大小。Maya的四視圖就是用了這個(gè)布局的,還有mel編輯器也是。
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "窗格布局(paneLayout)測(cè)試窗" myTestWin;
paneLayout -configuration "quad";
button;
textScrollList -append "one" -append "two" -append "three";
scrollField;
scrollLayout;
columnLayout;
button; button; button;
showWindow myTestWin;
}
myTest;
-----------------------------------------
"-cn/configuration"pane的組合方式,可用值為:"single", "horizontal2", "vertical2", "horizontal3", "vertical3", "top3", "left3", "bottom3", "right3", "horizontal4", "vertical4", "top4", "left4", "bottom4", "right4", "quad"。

"tabLayout"命令 (標(biāo)簽布局)
標(biāo)簽布局中只能放布局,不能放控件。標(biāo)簽布局中可以放多個(gè)并列的子布局,當(dāng)鼠標(biāo)點(diǎn)到某一標(biāo)簽時(shí),就顯示與此標(biāo)簽對(duì)應(yīng)的子布局。對(duì)于控件很多的面板,標(biāo)簽布局無(wú)疑是最好的選擇。
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "標(biāo)簽布局(tabLayout)測(cè)試窗" myTestWin;
string $tabs = `tabLayout`;
string $child1 = `columnLayout -adj 1`; // 標(biāo)簽1
button; button; button;
setParent ..;

string $child2 = `rowColumnLayout -numberOfColumns 2`; // "標(biāo)簽2"
button; button; button;
setParent ..;

tabLayout -edit
-tabLabel $child1 "標(biāo)簽1" -tabLabel $child2 "標(biāo)簽2"
$tabs;

showWindow myTestWin;
}
myTest;
-----------------------------------------
string $tabs = `tabLayout`;
這句的意思獲取tabLayout命令的返回值,存到變量$tabs里。
前面說(shuō)過(guò)界面元素要有一個(gè)唯一的命名,如果你沒(méi)有給它命名,Maya會(huì)自動(dòng)給它一個(gè)命名。界面命令的返回值就是界面元素的名稱,因此用獲取命令返回值的方法就可以獲得界面元素的名稱。(string $變量 = `界面命令`;)

string $child1 = `columnLayout -adj 1`;
這句也是同樣的道理。

"formLayout"命令 (表單布局)
表單布局是最強(qiáng)大、最復(fù)雜、最具有可塑性的布局。這種布局可以隨意把控件放到任何你想要的地方,也可以根據(jù)窗口的縮放即時(shí)縮放指定的控件。如果你很注重界面舒適美觀的話,它就是你必然的選擇。
-----------------------------------------
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "表單布局(formLayout)測(cè)試窗" myTestWin;

// 創(chuàng)建表單布局和布局中的控件
string $form = `formLayout`;
string $b1 = `button -label "按鈕1"`;
string $b2 = `button -label "按鈕2"`;
string $b3 = `button -label "按鈕3"`;

// 分別描述每個(gè)按鈕的上下左右位置
formLayout -edit
// 按鈕1
-attachForm $b1 "top" 5 // 頂部距離表單5個(gè)像素
-attachForm $b1 "left" 5 // 左邊距離表單5個(gè)像素
-attachForm $b1 "bottom" 5 // 底部距離表單5個(gè)像素
-attachPosition $b1 "right" 0 75 // 右邊距離表單的75%
// 按鈕2
-attachForm $b2 "top" 5 // 頂部距離表單5個(gè)像素
-attachControl $b2 "left" 5 $b1 // 左邊距離"按鈕1"5個(gè)像素
-attachNone $b2 "bottom" // 底部為默認(rèn)值
-attachForm $b2 "right" 5 // 右邊距離表單5個(gè)像素
// 按鈕3
-attachControl $b3 "top" 5 $b2 // 頂部距離"按鈕2"5個(gè)像素
-attachControl $b3 "left" 5 $b1 // 左邊距離"按鈕1"5個(gè)像素
-attachNone $b3 "bottom" // 底部為默認(rèn)值
-attachForm $b3 "right" 5 // 右邊距離表單5個(gè)像素
$form;

showWindow myTestWin;
}
myTest;
-----------------------------------------
當(dāng)你拉大或縮小這個(gè)窗口時(shí),"按鈕1"的寬度總是占整個(gè)窗口的75%。

編寫表單布局一般分為兩步:
1.創(chuàng)建表單布局和布局中的控件。
2.分別描述每個(gè)按鈕的上下左右位置。
"-af/attachForm" 距離表單多少個(gè)像素。
"-ac/attachControl" 距離控件多少個(gè)像素。
"-ap/attachPosition" 距離表單的幾(-numberOfDivisions)分之幾多少個(gè)像素。
"-nd/numberOfDivisions" 把表單分成多少份,好用于"-ap/attachPosition"。默認(rèn)值為100。

關(guān)于表單布局,再舉兩個(gè)例子:
-----------------------------------------
// 這是一種常用的按鈕擺放方法
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "表單布局1(formLayout)測(cè)試窗" myTestWin;

string $form = `formLayout -numberOfDivisions 3`; // 分3份
// "-horizontalScrollBarThickness 0"無(wú)橫向滾動(dòng)條
string $scroll = `scrollLayout -horizontalScrollBarThickness 0`;
columnLayout;
button; button; button;button; button;
button; button; button;button; button;
setParent ..;
setParent ..;

string $sep = `separator`;
string $b1 = `button -label "按鈕1"`;
string $b2 = `button -label "按鈕2"`;
string $b3 = `button -label "按鈕3"`;

formLayout -edit
// 滾動(dòng)布局
-attachForm $scroll "top" 4 // 頂部距離表單4個(gè)像素
-attachForm $scroll "left" 4 // 左邊距離表單4個(gè)像素
-attachControl $scroll "bottom" 4 $sep // 底部距離"分隔線"4個(gè)像素
-attachForm $scroll "right" 4 // 右邊距離表單4個(gè)像素
// 分隔線
-attachNone $sep "top" // 頂部為默認(rèn)值
-attachForm $sep "left" 2 // 左邊距離表單2個(gè)像素
-attachControl $sep "bottom" 4 $b1 // 底部距離"按鈕1"4個(gè)像素
-attachForm $sep "right" 2 // 右邊距離表單2個(gè)像素
// 按鈕1
-attachNone $b1 "top" // 頂部為默認(rèn)值
-attachForm $b1 "left" 4 // 左邊距離表單4個(gè)像素
-attachForm $b1 "bottom" 4 // 底部距離表單4個(gè)像素
-attachPosition $b1 "right" 2 1 // 右邊距離表單的1/3處2個(gè)像素
// 按鈕2
-attachNone $b2 "top" // 頂部為默認(rèn)值
-attachControl $b2 "left" 4 $b1 // 左邊距離"按鈕1"表單4個(gè)像素
-attachForm $b2 "bottom" 4 // 底部距離表單4個(gè)像素
-attachPosition $b2 "right" 2 2 // 右邊距離表單的2/3處2個(gè)像素
// 按鈕3
-attachNone $b3 "top" // 頂部為默認(rèn)值
-attachControl $b3 "left" 4 $b2 // 左邊距離"按鈕2"4個(gè)像素
-attachForm $b3 "bottom" 4 // 底部距離表單4個(gè)像素
-attachForm $b3 "right" 4 // 右邊距離表單4個(gè)像素
$form;

showWindow myTestWin;
}
myTest;

-----------------------------------------
// 隨意擺放控件的位置
global proc myTest()
{
if(`window -ex myTestWin`) deleteUI myTestWin;

window -t "表單布局2(formLayout)測(cè)試窗" myTestWin;

string $form = `formLayout`;
string $b1 = `button -l "按鈕1"`;
string $b2 = `button -l "按鈕2"`;
string $b3 = `button -l "按鈕3"`;

formLayout -e
-af $b1 "top" 1
-af $b1 "left" 5
-af $b2 "top" 19
-af $b2 "left" 132
-af $b3 "top" 46
-af $b3 "left" 40
$form;

showWindow myTestWin;
}
myTest;

"rowLayout"命令 (橫布局)
橫布局與橫豎布局有些相似,只不過(guò)控件只能橫著擺而已。
-----------------------------------------
window;
rowLayout -numberOfColumns 3
-columnWidth3 80 75 150
-adjustableColumn 2
-columnAlign 1 "right"
-columnAttach 1 "both" 0
-columnAttach 2 "both" 0
-columnAttach 3 "both" 0;
text;
intField;
intSlider;
showWindow;
-----------------------------------------

"gridLayout"命令 (格子布局)
格子布局與橫豎布局有些相似,受格子的影響,每個(gè)的控件大小相同。
-----------------------------------------
window;
gridLayout -numberOfColumns 2 -cellWidthHeight 50 50;
button; button; button; button;
button; button; button;
showWindow;
-----------------------------------------

"menuBarLayout"命令 (菜單條布局)
用于一個(gè)窗口放多個(gè)菜單條的情況。
-----------------------------------------
string $window = `window`;
columnLayout -adjustableColumn true;
// Create first menu bar layout.
string $menuBarLayout = `menuBarLayout`;
menu -label "File";
menuItem -label "New";
menuItem -label "Open";
menuItem -label "Close";
menu -label "Help" -helpMenu true;
menuItem -label "About...";
columnLayout;
button -label "Add Menu"
-command ("menu -parent " + $menuBarLayout + "; menuItem");
setParent ..;
setParent ..;

separator -height 10 -style "none";

// Create a second menu bar layout.
//
menuBarLayout;
menu -label "Edit";
menuItem -label "Cut";
menuItem -label "Copy";
menuItem -label "Paste";
menu -label "View";
menuItem -label "Fonts...";
menuItem -label "Colors...";
columnLayout;
text -label "Add some controls here.";
setParent ..;
setParent ..;

showWindow $window;
-----------------------------------------

"shelfLayout"命令 (工具架布局)
放置shelf按鈕的布局,支持鼠標(biāo)中鍵拖放代碼。
-----------------------------------------
window;
tabLayout;
shelfLayout Anim;
setParent ..;
shelfLayout Render;
setParent ..;
shelfLayout Misc;
setParent ..;
showWindow;
-----------------------------------------

"shelfTabLayout"命令 (工具架標(biāo)簽布局)
-----------------------------------------
可以使工具架上多一個(gè)垃圾桶圖標(biāo),以便刪除不用的shelf按鈕。
window;
shelfTabLayout
-image "smallTrash.xpm"
-imageVisible true mainShelfTab;
shelfLayout Dynamics;
setParent ..;
shelfLayout Rendering;
setParent ..;
shelfLayout Animation;
setParent ..;
showWindow;

共有的標(biāo)志(一):
如果你讀過(guò)mel命令的幫助文檔,你會(huì)發(fā)現(xiàn)所有的界面命令都具有一些共同的標(biāo)志。比如,"-q"、"-e"就是所有界面命令都具有的標(biāo)志。我把這些標(biāo)志介紹一下,這樣無(wú)論任何界面(布局或控件)命令,只要用到這些標(biāo)志時(shí),你們就都知道怎么去用了。

"-q/-query"(查詢)
表示查詢的意思,你可以通過(guò)它獲得某一標(biāo)志的數(shù)值。(前面講過(guò)了)

"-e/-edit"(編輯)
表示編輯的意思,你可以通過(guò)它修改某一標(biāo)志的數(shù)值。(前面講過(guò)了)

"-ex/exists"(是否存在)
通過(guò)"-ex"可以得知一個(gè)界面元素是否存在。
例如前面講過(guò)的"if(`window -ex myTestWin`)"。

"-dt/defineTemplate" (定義模板)
"-ut/useTemplate" (使用模板)
一般我們沒(méi)必要定義模板,不過(guò)有幾個(gè)Maya已經(jīng)定義好的模板有時(shí)會(huì)用到,我以后再講。

"-p/parent" (指定父級(jí)界面元素)
指定父級(jí)界面元素(布局或菜單),平常我們用"setParent"命令來(lái)解決這個(gè)問(wèn)題,所以"-p"很少用到。

"-en/enable" (是否激活)
我們經(jīng)?吹揭恍┎藛位虬粹o上的字是灰色的,表示它們現(xiàn)在不能用。
使用"-en"就可以讓你的界面元素上的字變灰,使它們不能用。
例如"button -e -en off myButton1"就是讓按鈕myButton1變得不能用。
而"button -e -en on myButton1"就是讓按鈕myButton1恢復(fù)活力。

"-w/width" (寬度)
界面元素的寬度為多少像素。
你會(huì)發(fā)現(xiàn)使用這個(gè)標(biāo)志時(shí)經(jīng)常不起作用。
比如如果在布局命令中指定了里面控件的寬度,再給布局中這些控件指定寬度就不起作用了。
窗口的寬度只在第一次創(chuàng)建時(shí)有用,以后創(chuàng)建會(huì)使用預(yù)置中的尺寸。預(yù)置中的尺寸就是窗口關(guān)閉時(shí)的大小,這個(gè)尺寸記錄在預(yù)置文件(windowPrefs.mel)中,可以通過(guò)"windowPref"命令去除窗口的預(yù)置尺寸,方法是"windowPref -remove 窗口名;"

"-h/height" (高度)
界面元素的高度為多少像素。
用法同"-w/width",例如"button -w 32 -h 32;"。

"-vis/visible" (是否可見)
指定界面元素是否可見。
前面講過(guò)"window -visible off"的問(wèn)題。其它界面元素也可以通過(guò)"-visible off"暫時(shí)隱藏,想要顯示出來(lái),就用"-visible on"。

"-io/isObscured" (是否看不到)
查詢界面元素是否不可見。你肯定會(huì)問(wèn)"-io"和"-vis"的區(qū)別。"-io"只能用于查詢(-q)模式,般查詢結(jié)果正好與"-vis"的查詢結(jié)果相反。不過(guò)"-io"的不可見包括窗口最小化、父級(jí)界面元素隱藏等造成的不可見因素。

"-m/manage" (可控制)
指定界面元素是否可見。跟"-vis"沒(méi)什么區(qū)別。

"-ann/annotation" (注釋)
給界面元素注釋。注釋可以在幫助欄顯示,也可以讓鼠標(biāo)在界面元素上停一會(huì),在彈出式的淡黃底色注釋條看到。

"-bgc/backgroundColor" (底色)
要想編寫彩色窗口就要用到這個(gè)標(biāo)志。

還有一些共有標(biāo)志留到以后講。

布局到此已經(jīng)全講完了,接下來(lái)講控件。
前面提到過(guò)一些控件:
"text"命令 (靜態(tài)文本)
"textField"命令 (文本框)
"button"命令 (按鈕)
"separator"命令 (分隔線)

這些控件雖然已經(jīng)講過(guò)了,但由于十分重要,現(xiàn)在在強(qiáng)調(diào)一下,一定要熟練掌握。

另外,先隨便講幾個(gè):
"picture"命令 (圖片)
靜態(tài)圖片。
---------------------------------------------------
picture -w 80 -h 60 -image "sphere.xpm" -tile on;
---------------------------------------------------
"-i/image"指定圖片。
"-tl/tile"指定圖片是否重復(fù)排疊顯示。

"iconTextButton"命令 (圖標(biāo)文本按鈕)
既有字又有圖標(biāo)的按鈕,你可以只顯示字或圖標(biāo)。
---------------------------------------------------
string $window = `window`;
columnLayout -adj 1;
iconTextButton -style "textOnly"
-image1 "sphere.xpm" -label "sphere";
iconTextButton -style "iconOnly"
-image1 "spotlight.xpm" -label "spotlight";
iconTextButton -style "iconAndTextHorizontal"
-image1 "cone.xpm" -label "cone";
iconTextButton -style "iconAndTextVertical"
-image1 "cube.xpm" -label "cube";
showWindow $window;

"symbolButton"命令 (符號(hào)按鈕)
有圖片的按鈕。
---------------------------------------------------
symbolButton -image "cone.xpm" -c "cone";
---------------------------------------------------

"intSlider"命令 (整數(shù)型滑動(dòng)條)
---------------------------------------------------
intSlider -min -100 -max 100 -value 0;
---------------------------------------------------
"-min"最小值
"-max"最大值
"-value"當(dāng)前值

一直這么講下去難免有些枯燥乏味,還是來(lái)點(diǎn)實(shí)戰(zhàn)輕松一下吧。
下面介紹一下賭牌游戲myFourUp的編寫方法。
------------------------------
實(shí)例7:賭牌游戲myFourUp
myFourUp程序很像一個(gè)撲克機(jī),它的原版是Stephen D. Gilbert的Visual C++ 6編程藍(lán)皮書中的一個(gè)實(shí)例(FourUp),我認(rèn)為這個(gè)程序用于Mel也同樣很能說(shuō)明問(wèn)題,就擅自把它移植了過(guò)來(lái),不過(guò)我在界面和算法部分都作了較大改動(dòng)。

說(shuō)到打賭,myFourUp程序與拉斯韋加斯和亞特蘭大城中賭場(chǎng)工作人員特別喜愛(ài)的撲克游戲相似。但myFourUp更簡(jiǎn)單,因此你可以集中精力學(xué)習(xí)程序設(shè)計(jì)和界面編寫方法。
myFourUp并非技巧游戲。當(dāng)游戲開始時(shí),給玩者1000美元。每一輪(需花一定賭注,比如2美元)玩者接到4張牌。牌值無(wú)關(guān)緊要-我們關(guān)心的只是花色。如果玩者得到兩對(duì)(例如,兩張紅心和兩張方片),將得4美元。如果玩者得到三個(gè)單張,將得到6美元。如果發(fā)牌者擺出四張同一花色,將得8美元。

當(dāng)然,游戲并非使用真錢。如果你想編寫程序以便能撥入玩者的銀行帳戶來(lái)取出贏利(或彌補(bǔ)虧空),那是你自己的事。

在我們編寫代碼之前,讓我們先花一點(diǎn)時(shí)間來(lái)計(jì)劃一下程序的外觀以及它將如何工作。最好是用紙和筆畫出該布局,畢竟修訂一個(gè)計(jì)劃比改變一個(gè)完成的程序要容易。

現(xiàn)在可以根據(jù)草圖來(lái)編寫代碼,不過(guò)編寫代碼之前最好先講一下什么是全局變量。
全局變量(Global Variable)
我們以前用到的變量都是局部變量。局部變量只能在函數(shù)里面用,當(dāng)函數(shù)運(yùn)行時(shí)局部變量被創(chuàng)建,函數(shù)運(yùn)行結(jié)束后,局部變量就被刪除了。

如果用戶需要在一個(gè)函數(shù)中創(chuàng)建的變量,其它的函數(shù)也可用,則用戶可以通過(guò)全局變量來(lái)實(shí)現(xiàn)。如果你創(chuàng)建了一個(gè)全局變量,你可以通過(guò)函數(shù),也可以通過(guò)命令行不斷修改它的值。全局變量將一直保留在內(nèi)存中,直到你退出Maya時(shí)才會(huì)被刪除。

在變量聲明前加上"global"表示為全局變量。(在命令行聲明全局變量可以不寫"global")
例如:
global float $counter;

跟椐Maya幫助文檔的說(shuō)法應(yīng)當(dāng)盡量少用全局變量,否則很容易會(huì)因?yàn)榇中亩鲥e(cuò)。比如你聲明了一個(gè)全局變量$counter,而Maya中卻碰巧已經(jīng)有了一個(gè)全局變量$counter,此時(shí)你對(duì)$counter變量值所作的任何修改都將影響以前就存在的全局變量$counter,這將會(huì)產(chǎn)生錯(cuò)誤。
為避免碰巧同名變量的存在,請(qǐng)用較為獨(dú)特的名稱來(lái)命名全局變量。Maya中的全局變量都是以小寫字母"g"開頭(例如$gMainWindow),你可以用除"g"以外的你喜歡的字母開頭,本教程中用到的全局變量一般都以"mg"開頭。

下面開始我們的程序。程序雖然簡(jiǎn)單,但這個(gè)是一個(gè)完善的游戲程序,對(duì)于某些初學(xué)者來(lái)說(shuō)可能有些難度,如果你實(shí)在看不懂,就索性照抄一遍,借此體驗(yàn)一個(gè)編程的感覺(jué)。

在myFourUp程序中,用一個(gè)全局變量$mgMoneyRemaining來(lái)記錄你擁有的總錢數(shù),當(dāng)你贏錢時(shí)總錢數(shù)會(huì)增加,反之則會(huì)減少。
----------------------------------
//global proc myFourUp(){以下的代碼寫在括號(hào)中}

// 初始化總錢數(shù)為1000美元
global int $mgMoneyRemaining;
$mgMoneyRemaining = 1000;

界面代碼:
首先創(chuàng)建窗口:
----------------------------------
if(`window -ex myFourUpWin`) deleteUI myFourUpWin;
window -t "Four Up"
-widthHeight 293 440
-sizeable false
myFourUpWin;
----------------------------------
"-wh/widthHeight"指定窗口的長(zhǎng)度和寬度分別為多少像素。也可用"-w"和"-h"分別來(lái)指定。
"-s/sizeable"指定窗口是否可以拉大縮小(變化尺寸)。

為了能夠隨意擺放控件,用一個(gè)表單布局作為窗口的主布局。
----------------------------------
string $form = `formLayout -backgroundColor 0.353 0.353 0.259`;
----------------------------------
創(chuàng)建布局$form中的元素:
----------------------------------
// 標(biāo)題圖片
string $pTitle_f = `picture -image "title_f.bmp" fourUpTitle`;
// 邊框圖片
string $pFrame_l = `picture -image "frame_l.bmp"`;
string $pFrame_r = `picture -image "frame_r.bmp"`;
string $pFrame_b = `picture -image "frame_b.bmp"`;

// 位圖按鈕(圖標(biāo)文本按鈕)
string $bBtn_1 = `iconTextButton -style "iconOnly"
-backgroundColor 0.353 0.353 0.259
-w 106 -h 41 -image1 "btn_deal.bmp"
-c "dealCards"`;
string $bBtn_2 = `iconTextButton -style "iconOnly"
-backgroundColor 0.353 0.353 0.259
-w 106 -h 41 -image1 "btn_Exit.bmp"
-c "deleteUI myFourUpWin;"`;

// 橫布局
// 包括一個(gè)靜態(tài)圖片,一個(gè)文本框和一個(gè)符號(hào)按鈕
string $row = `rowLayout -numberOfColumns 3
-backgroundColor 0.353 0.353 0.259
-columnWidth3 82 60 80`;
picture -image "deposit.bmp";
textField -ed false -tx "$2" placeBetField;
symbolButton -image "max.bmp" -c "placeBetMax";
setParent ..;

// 整數(shù)型滑動(dòng)條
string $slider = `intSlider
-backgroundColor 0.568 0.588 0.463
-min 2 -max 100 -value 2 -step 20
-dragCommand "placeBet" placeBetSlider`;

// 兩個(gè)邊框布局
string $frame_1 = `frameLayout -backgroundColor 0.863 0.729 0.435
-label "你還剩:$1000 "
-labelAlign "bottom" -borderStyle "etchedIn"
-h 65 MoneyRemainingFrame`;
// @@@A 創(chuàng)建布局$frame_1中元素的代碼寫在這里:

setParent ..;

string $frame_2 = `frameLayout -backgroundColor 0.863 0.729 0.435
-label "贏錢規(guī)則:"
-labelAlign "bottom" -borderStyle "etchedIn"
-h 110`;
// @@@B 創(chuàng)建布局$frame_2中元素的代碼寫在這里:

setParent ..;
----------------------------------

指定布局$form中每個(gè)界面元素的位置,
注意每張圖片所放置的位置。
----------------------------------
formLayout -e
// frame_l.bmp直接放在布局$form的左上角
-af $pFrame_l "top" 0
-af $pFrame_l "left" 0

// title_f.bmp
-af $pTitle_f "top" 0 // 上邊緊靠布局的上邊
-ac $pTitle_f "left" 0 $pFrame_l // 左邊緊靠frame_l.bmp

// frame_r.bmp
-af $pFrame_r "top" 0 // 上邊緊靠布局的上邊
-ac $pFrame_r "left" 0 $pTitle_f // 左邊緊靠title_f.bmp

// frame_b.bmp
-af $pFrame_b "bottom" 0 // 底邊緊靠布局的底邊
-ac $pFrame_b "left" 0 $pFrame_l // 左邊緊靠frame_l.bmp

-ac $frame_1 "top" 5 $pTitle_f
-ac $frame_1 "left" 5 $pFrame_l
-ac $frame_1 "right" 2 $pFrame_r

-ac $frame_2 "top" 12 $frame_1
-ac $frame_2 "left" 5 $pFrame_l
-ac $frame_2 "right" 2 $pFrame_r

-ac $row "top" 12 $frame_2
-ac $row "left" 5 $pFrame_l

-ac $slider "top" 8 $row
-ac $slider "left" 5 $pFrame_l
-ac $slider "right" 2 $pFrame_r

// btn_deal.bmp
-ac $bBtn_1 "bottom" 0 $pFrame_b // 底邊緊靠frame_b.bmp
-ac $bBtn_1 "left" 0 $pFrame_l // 左邊緊靠frame_l.bmp

// btn_exit.bmp
-ac $bBtn_2 "bottom" 0 $pFrame_b // 底邊緊靠frame_b.bmp
-ac $bBtn_2 "right" 0 $pFrame_r // 右邊緊靠frame_r.bmp
$form;
----------------------------------
顯示窗口:
----------------------------------
showWindow myFourUpWin;
----------------------------------

界面和主要部分編好了,下面讓我們來(lái)填補(bǔ)兩個(gè)邊框布局。

在前面代碼的"@@@A..."這句注釋之后填寫如下代碼:
----------------------------------
// 布局$form_1中的布局分兩層
string $form_1 = `formLayout`;
// 先寫的為第一層,第一層放置底紋圖片"back_1.bmp"
// "-tl"圖片重疊擺放
string $pBack_1 = `picture -tl 1 -image "back_1.bmp"`;

// 放置四種花色圖片
// spade - 黑桃,club - 梅花,diamond - 方片,heart - 紅心。
string $card_s = `picture -image "card_spade.bmp" cardImg_0`;
string $card_c = `picture -image "card_club.bmp" cardImg_1`;
string $card_d = `picture -image "card_diamond.bmp" cardImg_2`;
string $card_h = `picture -image "card_heart.bmp" cardImg_3`;

// 指定位置
formLayout -e
-af $pBack_1 "top" 0
-af $pBack_1 "bottom" 0
-af $pBack_1 "left" 0
-af $pBack_1 "right" 0

-af $card_s "top" 6
-ap $card_s "left" 8 0

-af $card_c "top" 6
-ap $card_c "left" 8 25

-af $card_d "top" 6
-ap $card_d "left" 8 50

-af $card_h "top" 6
-ap $card_h "left" 8 75
$form_1;

setParent ..;

布局$form_2編寫的方法類似布局$form_1,我就不做解釋了。
在"@@@B..."這句注釋之后填寫如下代碼:
----------------------------------
string $form_2 = `formLayout`;
string $pBack_2 = `picture -tl 1 -image "back_1.bmp"`;
string $pT1 = `text -l " 兩對(duì)同花 $4"
-backgroundColor 0.568 0.588 0.463 placeBetText1`;
string $pT2 = `text -l " 三個(gè)同花 $6"
-backgroundColor 0.568 0.588 0.463 placeBetText2`;
string $pT3 = `text -l " 全部同花 $8"
-backgroundColor 0.568 0.588 0.463 placeBetText3`;

formLayout -e
-af $pBack_2 "top" 0
-af $pBack_2 "bottom" 0
-af $pBack_2 "left" 0
-af $pBack_2 "right" 0

-ap $pT1 "top" 10 0
-af $pT1 "left" 15
-af $pT1 "right" 15

-ap $pT2 "top" 10 30
-af $pT2 "left" 15
-af $pT2 "right" 15

-ap $pT3 "top" 10 60
-af $pT3 "left" 15
-af $pT3 "right" 15
$form_2;

// 因?yàn)?form_2之后不再創(chuàng)建界面元素了,所以可以不寫"setParent ..;"

界面部分編完了,現(xiàn)在來(lái)編寫代碼讓這個(gè)游戲運(yùn)轉(zhuǎn)起來(lái)。
在前面的代碼中,有三處需要調(diào)用自定義的命令,分別是:

1)位圖按鈕(btn_deal.bmp)。
string $bBtn_1 = `iconTextButton ... -c "dealCards"`;

2)"-dragCommand"拉動(dòng)滑動(dòng)條時(shí)執(zhí)行的命令。
string $slider = `intSlider ... -dragCommand "placeBet" placeBetSlider`;

3)橫布局中的符號(hào)按鈕(max.bmp)。
symbolButton ... -c "placeBetMax";

// 按下"Max"(max.bmp)按鈕執(zhí)行的命令
global proc placeBetMax()
{
// 把滑動(dòng)條撥到最右邊
intSlider -e -v 100 placeBetSlider;
// 文本框中填入相應(yīng)的值$100
textField -e -tx "$100" placeBetField;

// 修改贏錢規(guī)則
text -e -l (" 兩對(duì)同花 $200") placeBetText1;
text -e -l (" 三個(gè)同花 $300") placeBetText2;
text -e -l (" 全部同花 $400") placeBetText3;
}

// 拉動(dòng)滑動(dòng)條時(shí)執(zhí)行的命令
global proc placeBet()
{
// 獲得滑動(dòng)條上的數(shù)值
int $deposit = `intSlider -q -v placeBetSlider`;
// 文本框中填入滑動(dòng)條的數(shù)值
string $text = "$" + $deposit;
textField -e -tx $text placeBetField;

// 修改贏錢規(guī)則
int $m1 = $deposit * 2;
int $m2 = $deposit * 3;
int $m3 = $deposit * 4;

text -e -l (" 兩對(duì)同花 $" + $m1) placeBetText1;
text -e -l (" 三個(gè)同花 $" + $m2) placeBetText2;
text -e -l (" 全部同花 $" + $m3) placeBetText3;
}

現(xiàn)在來(lái)對(duì)付關(guān)鍵部分,相對(duì)比較復(fù)雜。
我們可以先來(lái)考慮一下,當(dāng)玩家點(diǎn)擊了"deal"按鈕時(shí),我們希望發(fā)生什么?
1)隨機(jī)選擇4張牌作為一付牌。
2)更新每張牌的圖像以指示該付牌的花色。
3)統(tǒng)計(jì)每種花色牌的張數(shù)。
4)統(tǒng)計(jì)同種花色的牌一共有幾對(duì)。
5)從總錢數(shù)扣去賭注。
6)計(jì)算輸贏,如果贏錢加入總錢數(shù)中。
7)贏錢后加亮贏錢規(guī)則字樣的底色。
8)修改標(biāo)題圖片,如果是贏錢顯示"Congratulations",否則顯示"Misfortune"。
8)顯示剩余金額。
----------------------------------
// 位圖按鈕(btn_deal.bmp)命令
global proc dealCards()
{
global int $mgMoneyRemaining;

// 分別用四個(gè)變量記錄每種花色牌的張數(shù)
int $num_spade = 0;
int $num_club = 0;
int $num_diamond = 0;
int $num_heart = 0;
// 用$pairs記錄同種花色的牌一共有幾對(duì)
int $pairs = 0;

for($i=0; $i<4; $i++)
{
// 隨機(jī)選擇4張牌中的一張
int $num = `rand 4`;
if($num == 0) {
// 更新花色牌的圖片
picture -e -image "card_spade.bmp" ("cardImg_"+$i);
// 統(tǒng)計(jì)每種花色牌的張數(shù)
$num_spade++; // $num_spade = $num_spade + 1
}
if($num == 1) {
picture -e -image "card_club.bmp" ("cardImg_"+$i);
$num_club++;
}
if($num == 2) {
picture -e -image "card_diamond.bmp" ("cardImg_"+$i);
$num_diamond++;
}
if($num == 3) {
picture -e -image "card_heart.bmp" ("cardImg_"+$i);
$num_heart++;
}
}

// 統(tǒng)計(jì)同種花色的牌一共有幾對(duì)
if($num_spade == 2)
$pairs++;
if($num_club == 2)
$pairs++;
if($num_diamond == 2)
$pairs++;
if($num_heart == 2)
$pairs++;

//----------------------------------------------
// 從滑動(dòng)條上得到賭注數(shù)額
$deposit = `intSlider -q -v placeBetSlider`;
int $m1 = $deposit * 2;
int $m2 = $deposit * 3;
int $m3 = $deposit * 4;

// 先用總錢數(shù)減去賭注
$mgMoneyRemaining -= $deposit;

// 調(diào)整文字,為的是保證文本框底色的刷新
text -e -l "" -backgroundColor 0.568 0.588 0.463 placeBetText1;
text -e -l "" -backgroundColor 0.568 0.588 0.463 placeBetText2;
text -e -l "" -backgroundColor 0.568 0.588 0.463 placeBetText3;
// 修改標(biāo)題圖片為"Misfortune"
picture -e -image "title_m.bmp" fourUpTitle;

// 兩對(duì)同花
if($pairs == 2) {
// 贏的錢加入總錢數(shù)中
$mgMoneyRemaining += $m1;
// 加亮文本底色,變?yōu)榱咙S色
text -e -backgroundColor 1 1 0.463 placeBetText1;
// 修改標(biāo)題圖片為"Congratulations"
picture -e -image "title_c.bmp" fourUpTitle;
}

// 三個(gè)同花
if( $num_spade == 3 || $num_club == 3 ||
$num_diamond == 3 || $num_heart == 3 ) {
$mgMoneyRemaining += $m2;
text -e -backgroundColor 1 1 0.463 placeBetText2;
picture -e -image "title_c.bmp" fourUpTitle;
}

// 全部同花
if( $num_spade == 4 || $num_club == 4 ||
$num_diamond == 4 || $num_heart == 4 ) {
$mgMoneyRemaining += $m3;
text -e -backgroundColor 1 1 0.463 placeBetText3;
picture -e -image "title_c.bmp" fourUpTitle;
}

// 刷新
text -e -l (" 兩對(duì)同花 $" + $m1) placeBetText1;
text -e -l (" 三個(gè)同花 $" + $m2) placeBetText2;
text -e -l (" 全部同花 $" + $m3) placeBetText3;

// 顯示剩余金額
frameLayout -e -label ("你還剩:$" + $mgMoneyRemaining) MoneyRemainingFrame;
}

全部代碼編寫完畢,現(xiàn)在你可以體驗(yàn)賭牌的樂(lè)趣了。

我把全部范例代碼和圖片放到附件中,供你們參考。

1515133-myFourUp.rar (56.52k)

"if"語(yǔ)句 (如果)
關(guān)于"if"語(yǔ)句以前講的不夠詳細(xì),現(xiàn)在做一點(diǎn)簡(jiǎn)要補(bǔ)充。小括號(hào)里的雙豎線"||"表示"或"的意思,而"&&"表示"并且"的意思。

"if"后面的小括號(hào)里的代碼表示的只能是一個(gè)布爾值,1或0。
因此要表示相等要寫雙等號(hào)。

"雙等號(hào)的用法"
----------------------------------
int $test = 4;
int $bool = $test == 5; // 如果$test等于5,$bool = 1(true)
----------------------------------
這里因?yàn)?test = 4,不等于5,所以$bool = 0(false)。

"rand"命令 (隨機(jī))
前面用到"rand"命令,"rand"是隨機(jī)的意思,就是從指定的范圍內(nèi)隨便取出一個(gè)數(shù)值。mel里的"rand"同C語(yǔ)言的"rand"有一個(gè)很明顯的差別,mel是浮點(diǎn)數(shù)的隨機(jī),C語(yǔ)言是整數(shù)的隨機(jī)。

我在myFourUp程序中寫的"int $num = `rand 4`;" 實(shí)際上是一種浮點(diǎn)數(shù)轉(zhuǎn)整數(shù)的方法,還有一種寫法更容易看明白一些:
float $floatNum = `rand 4`;
int $num = (int)$floatNum;

學(xué)習(xí) · 提示

  • 一定要打開PS,跟著教程做一遍,做完的圖到這交作業(yè):提交作業(yè)
  • 建議練習(xí)時(shí),大家自己找素材,盡量不要用教程提供的素材。
  • 教程有看不懂的地方,可以到論壇發(fā)帖提問(wèn):新手求助
  • 加官方微信,隨時(shí)隨地,想學(xué)就能學(xué):ps_bbs,或掃右側(cè)二維碼!
  • 關(guān)注我們學(xué)更多,每天都有新教程:新浪微博 抖音視頻 微信小程序
- 發(fā)評(píng)論 | 交作業(yè) -
最新評(píng)論
42017-01-13 04:08
42017-01-13 03:52
挺牛逼的
2016-03-14 07:30
超贊的文章
陳軍波2015-12-14 12:59
竟然沒(méi)人評(píng)論

關(guān)注大神微博加入>>

網(wǎng)友求助,請(qǐng)回答!