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