游戲是移動(dòng)應(yīng)用中最令人興奮的部分,無論是玩游戲,還是做游戲。最近紅極一時(shí)“憤怒的小鳥”,根據(jù)開發(fā)者Rovio公司稱,第一年下載量達(dá)50萬次,同時(shí)每天運(yùn)行的人時(shí)數(shù)超過一百萬小時(shí)。(甚至有人說要把它拍成故事片?。┪覀兛蔁o法保證電影的成功,但可以讓您用App Inventor創(chuàng)建自己的游戲“瓢蟲快跑”,里面的瓢蟲要吃蚜蟲,同時(shí)要避免被青蛙吃掉。
如圖5-1所示的“瓢蟲快跑”應(yīng)用,用戶可以:
通過傾斜設(shè)備來控制瓢蟲移動(dòng);
查看屏幕上的能量指示條,能量會(huì)隨時(shí)間減少,并引起瓢蟲的饑餓;
讓瓢蟲追逐并吃掉蚜蟲來獲得能量,抵御饑餓;
圖 5-1 瓢蟲快跑游戲手機(jī)截屏
在開始探索本章之前,我們假設(shè)你已經(jīng)完成了第3章MoleMash的學(xué)習(xí),并熟悉了過程創(chuàng)建、隨機(jī)數(shù)生成、Ifelse塊以及ImageSprite、Canvas、Sound和Clock組件。
本章在復(fù)習(xí)MoleMash以及前幾章內(nèi)容的基礎(chǔ)上,主要介紹以下內(nèi)容:
使用多個(gè)ImageSprite組件,并檢測(cè)它們之間的碰撞;
使用OrientationSensor(方向傳感器)組件檢測(cè)設(shè)備的傾斜,并用它來控制ImageSprite;
改變ImageSprite的顯示圖片;
在Canvas組件上畫線;
用Clock組件控制多個(gè)事件;
用變量來記錄數(shù)值(瓢蟲的能量水平);
創(chuàng)建和使用帶參數(shù)的過程;
在應(yīng)用中,使用一個(gè)Canvas組件作為三個(gè)ImageSprite組件的活動(dòng)場(chǎng)地,三個(gè)ImageSprite組件分別代表瓢蟲、蚜蟲和青蛙,此外,還要為青蛙配一個(gè)聲音組件。OrientationSensor(方向傳感器)通過測(cè)量設(shè)備的傾斜來移動(dòng)瓢蟲,Clock組件用來改變蚜蟲的運(yùn)動(dòng)方向。另有一個(gè)顯示瓢蟲能量水平的Canvas組件;一個(gè)重新啟動(dòng)按鈕,當(dāng)瓢蟲餓死或被吃掉時(shí),用來重新啟動(dòng)游戲。表5-1提供了本應(yīng)用中使用的全部組件列表。
表5-1 瓢蟲快跑游戲中的所有組件
組件類型 | 面板中分組 | 命名 | 作用 |
---|---|---|---|
Canvas | Drawing and Amination | FieldCanvas | 運(yùn)動(dòng)場(chǎng)地 |
ImageSprite | Drawing and Amination | Ladybug | 用戶控制的角色 |
OrientationSensor | Sensor | OrientationSensor1 | 測(cè)試手機(jī)的傾斜,控制瓢蟲移動(dòng) |
Clock | User Interface | Clock1 | 決定何時(shí)改變Imagesprite的方向 |
ImageSprite | Drawing and Amination | Aphid | 蚜蟲:瓢蟲的捕食對(duì)象 |
ImageSprite | Drawing and Amination | Frog | 青蛙:瓢蟲的捕食者 |
Canvas | Drawing and Amination | EnergyCanvas | 顯示瓢蟲的能量水平 |
Button | User Interface | RestartButton | 重啟游戲 |
Sound | Media | Sound1 | 青蛙吃瓢蟲時(shí)發(fā)出的聲音 |
下載瓢蟲、蚜蟲、死瓢蟲及青蛙的圖像,此外還有青蛙的聲音文件。
登陸App Inventor網(wǎng)站,建一個(gè)名為“LadybugChase”新項(xiàng)目,屏幕標(biāo)題設(shè)置為“瓢蟲快跑”。打開塊編輯器并連接到測(cè)試設(shè)備,將下載的圖片及聲音文件上載(Upload file)到媒體面板。
如果使用設(shè)備而不是模擬器,你需要禁用“屏幕自動(dòng)旋轉(zhuǎn)”功能,否則當(dāng)設(shè)備旋轉(zhuǎn)時(shí),會(huì)改變?cè)O(shè)備的顯示方向。在大多數(shù)設(shè)備上,可以點(diǎn)擊設(shè)置->顯示,然后取消選中的“屏幕自動(dòng)旋轉(zhuǎn)”復(fù)選框即可。
在這個(gè)“第一人稱”的游戲中,瓢蟲代表玩家,玩家通過傾斜手機(jī)來控制瓢蟲的運(yùn)動(dòng)。與MoleMash不同,這里玩家被帶入游戲,而不是在設(shè)備以外用手觸碰。
在前幾章,我們一次性地創(chuàng)建了所有的組件,但這不是開發(fā)人員的習(xí)慣做法。相反,通常每次只創(chuàng)建一部分組件,編寫相應(yīng)的程序,并進(jìn)行測(cè)試,然后在進(jìn)入到下一部分。在本節(jié)中,我們先來創(chuàng)建瓢蟲并控制它的運(yùn)動(dòng)。
在組件設(shè)計(jì)器中創(chuàng)建一個(gè)Canvas,命名為FieldCanvas,并設(shè)置其寬度為“Fill parent”,高度為300像素;
也許你已經(jīng)注意到,ImageSprites還有Interval、Heading以及speed屬性,而這些都是在本程序中要用到的:
Interval屬性:在本游戲中可以設(shè)置為10(毫秒),來設(shè)定ImageSprite自身的移動(dòng)頻率(而不是像MoleMash中那樣,運(yùn)動(dòng)被MoveTo過程所控制);
Heading屬性:指示ImageSprite將要移動(dòng)的方向。例如:0表示向右,90表示向上,180表示向左,等等?,F(xiàn)在就讓它取默認(rèn)值——向右,我們將在塊編輯器中改變它;
瓢蟲的運(yùn)動(dòng)由OrientationSensor通過檢測(cè)設(shè)備的傾斜程度來進(jìn)行控制;Clock組件用來每隔10毫秒(每秒100次)檢測(cè)一次設(shè)備的方向,并相應(yīng)地改變瓢蟲的Heading(方向)屬性 。我們將在塊編輯器中做如下設(shè)置:
1. 添加OrientationSensor組件,它將出現(xiàn)在“不可見組件”區(qū)域;
2. 添加Clock組件,它也將出現(xiàn)在“不可見組件”區(qū)域,并設(shè)置其TimerInterval屬性為10毫秒。對(duì)照?qǐng)D5-2檢查添加的組件。
圖 5-2 在組件設(shè)計(jì)器中為動(dòng)畫瓢蟲設(shè)置用戶界面
切換到塊編輯器,創(chuàng)建名為UpdateLadybug的過程(procedure)及Clock1.Timer塊,如圖5-3所示。嘗試不使用抽屜,直接輸入塊的名字(如“when Clock1.Timer”)來生成塊。(請(qǐng)注意,對(duì)數(shù)字100的乘法操作使用的是星號(hào)(*),但圖中看不到。)雖然可以單擊右鍵選擇添加注釋,但這不是必須的。
圖 5-3 每隔10毫秒改變一次瓢蟲的方向及速度
在UpdateLadybug過程里用到了兩個(gè)OrientationSensor最有用的屬性:
Angle(角度):表示設(shè)備傾斜的方向;
Magnitude乘以100是告訴瓢蟲,在每個(gè)時(shí)間間隔(TimerInterval)內(nèi),在某個(gè)特定的方向,移動(dòng)的距離在0到100像素之間。時(shí)間間隔為之前在組件設(shè)計(jì)器中設(shè)定的10毫秒。
雖然在連接設(shè)備上可以測(cè)試瓢蟲的移動(dòng),但與打包下載到設(shè)備上的運(yùn)行效果相比,瓢蟲的速度要么太慢,要么太快。對(duì)于安裝運(yùn)行的應(yīng)用,如果太慢,可以增加速度;相反,則減小速度。
在第二個(gè)Canvas組件上用一個(gè)紅色線條來顯示瓢蟲的能量水平。線條高度為1個(gè)像素,寬度為瓢蟲的能量值,取值范圍從200(健康)到0(死)。
在組件設(shè)計(jì)器中,在FieldCanvas下方創(chuàng)建一個(gè)新的Canvas組件,命名為EnergyCanvas;設(shè)置Width屬性為“Fill parent”,Height屬性為1個(gè)像素。
在塊編輯器中,創(chuàng)建一個(gè)初始值為200的變量來記錄瓢蟲的能量水平。(還記得吧,在第2章PaintPot中,第一次使用變量dotSize)以下是具體步驟:
1. 在塊編輯器中,拖出一個(gè)initialize global name to塊,將name改為energy;
2. 如果energy塊的右側(cè)插槽內(nèi)有其他塊,刪掉它:選中并按Delete鍵或直接拖到垃圾桶;
3. 創(chuàng)建一個(gè)數(shù)組塊200(直接輸入數(shù)字200或拖動(dòng)Math抽屜中的0塊),然后插入initialize global energy to塊,如圖5-4所示。
圖 5-4 將變量energy初始化為200
圖5-5中顯示了當(dāng)鼠標(biāo)懸浮在初始化變量塊的“energy”文本上時(shí),呼出了全局變量energy的“get”及“set”塊;
圖 5-5 從初始化變量塊中獲得set及get塊
我們要在變量energy與紅色線條之間建立通信,使線條長度(像素)與能量值相等。為此創(chuàng)建如下兩個(gè)類似的組塊:
1. 在EnergyCanvas上從(0, 0)點(diǎn)到(energy, 0)點(diǎn)畫一條紅線,以顯示當(dāng)前的能量水平;
2. 在EnergyCanvas上從(0, 0)點(diǎn)到(EnergyCanvas.Width, 0)點(diǎn)畫一條白線,在畫新能量水平線之前,清除當(dāng)前的能量水平線。(記得前面設(shè)置EnergyCanvas.Width為“Fill parent”。)
然而,最好能創(chuàng)建一個(gè)過程,能用任何顏色在EnergyCanvas上畫任意長度的線。為此,需要定義兩個(gè)參數(shù):length(長度)和color(顏色),當(dāng)程序被調(diào)用時(shí),我們只需要指定參數(shù)值,就像在MoleMash一章中調(diào)用random integer內(nèi)置過程一樣。下面是創(chuàng)建DrawEnergyLine過程的步驟,如圖5-6所示。
1. 進(jìn)入Procedures抽屜,拖出一個(gè)to procedure塊;
2. 點(diǎn)擊過程名(可能是“procedure” ),改為“DrawEnergyLine”;
3. 點(diǎn)擊過程塊左上角的藍(lán)色方塊,呼出兩個(gè)塊:input及input x;
4. 將input x塊插入到input塊內(nèi),將x修改為color;
5. 重復(fù)步驟4:插入第二塊input x并命名為“l(fā)ength”;
6. 按照?qǐng)D5-6所示,為該過程添加的其余的塊:將鼠標(biāo)懸停在to DrawEnergyLine塊的參數(shù)color及l(fā)ength文本上,獲得get color及get length塊;或者從Variables抽屜中直接拖出get塊,插入到to DrawEnergyLine內(nèi)部的塊中,點(diǎn)擊下拉菜單選擇color或length。
圖 5-5a 為DrawEnergyLine過程添加輸入(參數(shù))
圖 5-6 定義過程DrawEnergyLine
現(xiàn)在,你已經(jīng)掌握了創(chuàng)建過程的竅門,讓我們?cè)賹懸粋€(gè)DisplayEnergy的過程,兩次調(diào)用DrawEnergyLine過程:第一次用來擦除舊線(覆蓋整個(gè)EnergyCanvas的白線),第二次用來顯示新的能量線,如圖5-7所示。
圖 5-7 定義過程DisplayEnergy
DisplayEnergy過程由以下四行命令組成:
1. 設(shè)定畫筆顏色為白色;
2. 畫一條貫穿EnergyCanvas的橫線(1個(gè)像素高);
3. 設(shè)定畫筆顏色為紅色;
4. 畫一條長度等于energy值的線。
提示:將若干行代碼規(guī)整到一個(gè)過程中,通過調(diào)用這個(gè)過程來取代逐行地執(zhí)行這些代碼,這個(gè)過程被稱作重構(gòu),這種強(qiáng)大的技術(shù)使得程序更易于維護(hù),也更可靠。在這種情況下,如果我們想改變能量線的高度或位置,我們只需對(duì)DrawEnergyLine過程做一次修改,而不必分兩次來完成這一修改。
不同于前幾章的應(yīng)用,本游戲設(shè)定了結(jié)束環(huán)節(jié):如果瓢蟲吃不到足夠的蚜蟲,或者被青蛙吃掉,則游戲結(jié)束。此時(shí)我們希望瓢蟲不再移動(dòng)(設(shè)置Ladybug.Enabled為false),并將活瓢蟲圖片換成死瓢蟲(將Ladybug.Picture設(shè)置為已上傳的圖片文件名)。GameOver過程的創(chuàng)建如圖5-8所示。
圖 5-8 定義GameOver過程
再按圖5-9所示向UpdateLadybug(由Clock.Timer每10毫秒調(diào)用一次)添加紅框內(nèi)的代碼:
減少瓢蟲的能量(energy = energy - 1);
顯示新的能量水平(call DisplayEnergy);
測(cè)試:你可以在設(shè)備上測(cè)試這段代碼,并驗(yàn)證能量水平隨時(shí)間的減少,并最終導(dǎo)致瓢蟲死亡。重啟應(yīng)用可以點(diǎn)擊“Reset Connection->AI Companion”。
圖 5-9 UpdateLadybug過程的第二個(gè)版本
下面來添加蚜蟲,即讓蚜蟲在FieldCanvas上浮動(dòng)。如果瓢蟲撞上蚜蟲(視同“吃”掉它),則瓢蟲的能量水平升高,而蚜蟲消失,且稍后會(huì)再次出現(xiàn)。(在用戶看來,這完全是另一只蚜蟲,但實(shí)際上是同一個(gè)ImageSprite組件。)
添加蚜蟲首先要回到組件設(shè)計(jì)器,創(chuàng)建另一個(gè)ImageSprite,要確保它不落在瓢蟲上,命名為Aphid,其屬性設(shè)置如下:
1. Picture屬性:設(shè)置為已上傳的蚜蟲圖像文件;
2. Interval屬性:設(shè)置為10,即:像瓢蟲一樣,每10毫秒移動(dòng)一次;
3. Speed屬性:設(shè)置為2,因此蚜蟲移動(dòng)不會(huì)太快,以便讓瓢蟲能抓住它。
不必在意它的x、y屬性(只要不是在瓢蟲上)或title屬性,這些可以在塊編輯器中設(shè)置。
實(shí)驗(yàn)發(fā)現(xiàn),蚜蟲每隔50毫秒(Clock1跳動(dòng)5次)改變一次方向的效果最好。可以通過創(chuàng)建第二個(gè)Clock組件,并設(shè)定其TimerInterval屬性為50毫秒來實(shí)現(xiàn)這一效果。但是,我們希望能夠嘗試不同的技術(shù):使用random fraction(隨機(jī)分?jǐn)?shù))塊,每次調(diào)用,它都將返回一個(gè)≥0但<1的隨機(jī)數(shù)。創(chuàng)建UpdateAphid過程,并用Clock1.Timer來調(diào)用它,如圖5-10所示。
圖 5-10 添加UpdateAphid過程
定時(shí)器每次跳動(dòng)(每秒100次)都將調(diào)用UpdateLadybug及UpdateAphid過程。UpdateAphid過程首先生成一個(gè)介于0到1之間的隨機(jī)數(shù),例如0.15,如果該數(shù)<0.20(在20%的時(shí)間里),蚜蟲將改變方向,改變的角度為0到360之間的隨機(jī)數(shù);如果該數(shù)≥0.20(在其余80%的時(shí)間里),蚜蟲方向保持不變。
下一步,當(dāng)他們碰撞時(shí),讓瓢蟲“吃掉”蚜蟲。幸運(yùn)的是,App Inventor提供了ImageSprite組件之間的碰撞檢測(cè)。問題是:當(dāng)瓢蟲與蚜蟲碰撞時(shí),會(huì)發(fā)生哪些事情?在繼續(xù)閱讀之前,請(qǐng)你停下來想想這個(gè)問題。
為了處理瓢蟲與蚜蟲的碰撞,創(chuàng)建EatAphid過程,其具體步驟如下:
瓢蟲的能量水平上升50,來模擬享受美食;
讓蚜蟲消失(設(shè)置其Visible屬性為false);
讓蚜蟲停止移動(dòng)(設(shè)置其Enabled屬性為false);
請(qǐng)對(duì)照?qǐng)D5-11檢查您的塊。如果你還能想到發(fā)生其他事情,比如音效,可以自行添加。
圖 5-11 創(chuàng)建EatAphid過程
每次調(diào)用EatAphid,變量energy增加50,緩解了瓢蟲的饑餓。然后,蚜蟲的Visible及Enabled屬性都被設(shè)置為false,看上去像是消失了。最后,產(chǎn)生隨機(jī)的x、y坐標(biāo),并調(diào)用Aphid.MoveTo,這樣,蚜蟲會(huì)在一個(gè)新位置再次出現(xiàn)(否則,它一出現(xiàn)便會(huì)被立即吃掉)。
圖5-12顯示了在瓢蟲與蚜蟲之間做碰撞檢測(cè)的代碼。
圖 5-12 檢測(cè)并處理瓢蟲與蚜蟲之間的碰撞
當(dāng)瓢蟲與另一個(gè)ImageSprite碰撞時(shí),將調(diào)用Ladybug.CollidedWith,參數(shù)“other”指向任何與瓢蟲發(fā)生相撞的ImageSprite。此時(shí),只有蚜蟲可以碰撞,但稍后會(huì)有青蛙加入進(jìn)來。我們采用防御性編程方式,即在調(diào)用EatAphid之前,要確認(rèn)碰撞的對(duì)象就是蚜蟲;此外還要確認(rèn)蚜蟲可見,否則,蚜蟲在被吃掉之后而重新出現(xiàn)之前,還會(huì)與瓢蟲再次碰撞。如果缺少這項(xiàng)確認(rèn),隱形的蚜蟲會(huì)被再次吃掉,并引起能量水平的再次增加,這會(huì)讓用戶感到費(fèi)解。
測(cè)試:重新啟動(dòng)游戲,并確信瓢蟲出現(xiàn)在一個(gè)新的任意位置。
測(cè)試游戲時(shí),你可能注意到:當(dāng)蚜蟲或瓢蟲被吃掉時(shí),缺少良好的反饋。要添加音效及觸覺反饋,請(qǐng)執(zhí)行以下操作:
1. 在組件設(shè)計(jì)器中添加一個(gè)Sound組件。設(shè)置其Source屬性為已上傳的聲音文件;
2. 進(jìn)入塊編輯器,進(jìn)行如下操作:
在EatAphid過程中添加Sound1.Vibrate塊,參數(shù)為100毫秒,以便在蚜蟲被吃掉時(shí),設(shè)備產(chǎn)生振動(dòng);
下面這些想法目的是改進(jìn)游戲,或者讓游戲更個(gè)性化:
目前,當(dāng)游戲結(jié)束時(shí),青蛙和蚜蟲還在移動(dòng),這與其Enabled屬性有關(guān):在GameOver中將其設(shè)置為false,并在RestartButton.Click中重新設(shè)置為true;
設(shè)置并顯示一個(gè)分?jǐn)?shù),來表示瓢蟲的存活時(shí)間。你可以用Label來顯示一個(gè)數(shù)值,該數(shù)值在Clock1.Timer內(nèi)不斷遞增;
將EnergyCanvas的Height屬性增加為2,以便使能量條更加明顯,并在DrawEnergyLine內(nèi)畫兩條線,一個(gè)在另一個(gè)之上。(使用一個(gè)過程,而不是復(fù)制代碼先擦除再重繪能量線,這樣做的另一個(gè)好處是:如果你需要修改線的粗細(xì)、顏色或位置時(shí),只需要修改一處的代碼。)
添加背景圖和更多音效來渲染氣氛,比如用真聲或預(yù)警聲來提示瓢蟲能量水平的降低;
讓游戲隨時(shí)間推移而變得越來越難,如增加青蛙的速度,或降低Interval屬性值;
從技術(shù)上來說,被青蛙吃掉的瓢蟲應(yīng)該消失。改變游戲規(guī)則:如果瓢蟲被吃,則隱形;如果是餓死,則顯示死瓢蟲圖;
已經(jīng)有兩個(gè)游戲被你收入囊中(假設(shè)你學(xué)習(xí)了MoleMash),現(xiàn)在你該知道如何創(chuàng)建自己的游戲了,這是許多新程序員或有志者的目標(biāo)!具體來說,您學(xué)習(xí)了:
可以創(chuàng)建多個(gè)ImageSprite組件(瓢蟲,蚜蟲和青蛙),并在它們之間做碰撞檢測(cè);
用OrientationSensor可以檢測(cè)設(shè)備的傾斜,而測(cè)得的值可用于控制sprite(或你能想到的任何其他對(duì)象)的移動(dòng);
一個(gè)Clock組件可以控制多個(gè)發(fā)生頻率相同(改變瓢蟲和青蛙的方向),或通過使用random fraction塊來控制頻率不同的事件。例如,如果你想在一個(gè)周期中,有大約1/4(25%)的時(shí)間里會(huì)發(fā)生某事件,只要將它放在if塊中,并設(shè)定條件為random fraction的結(jié)果<0.25即可;
一個(gè)應(yīng)用中可以使用多個(gè)Canvas組件,我們的例子中有兩個(gè),一個(gè)用于游戲場(chǎng)地,另一個(gè)用于變量的圖形化顯示(而不是用Label顯示);
另一個(gè)游戲中常用的組件是Ball,與ImageSprite唯一不同的是,它的外觀是一個(gè)被填充的圓形,而不是一張任意的圖片。
orientation: 方向
field: 場(chǎng)地
ladybug: 瓢蟲
aphid: 蚜蟲
frog: 青蛙
energy: 能量
restart: 重新開始
chase: 追逐,奔跑
upload: 上載,上傳
file: 文件
interval: 間隔
heading: 前進(jìn)方向
speed: 速度
timer: 計(jì)時(shí)器
updat: 更新
angle: 角度
magnitude: 幅度
delete: 刪除
procedure: 過程
input: 輸入
display: 顯示
enable: 使有效
reset: 重置
visible: 可見的
eat: 吃
collide: 碰撞
with: 與...
else: 否則
fraction: 分?jǐn)?shù)
更多建議: