Java手机游戏开发简明教程 (SunJava开发者认证程序员 郎锐)
原文發(fā)布時間為:2008-07-30 —— 來源于本人的百度文章 [由搬家工具導入]
Java手機游戲開發(fā)實例簡明教程(SunJava開發(fā)者認證程序員 郎銳)
一、手機游戲編寫基礎
1.手機游戲設計的基本原則
目前,市面上的手機無論在處理能力還是在存儲容量上都不足與PC機相提并論,但也足以支持一個設計優(yōu)化的微型游戲程序的運行。加上它的網(wǎng)絡通信能力,甚至還可以支持有聯(lián)機對戰(zhàn)能力的網(wǎng)絡游戲。正是由于硬件設備的極大差異,才直接導致了手機游戲開發(fā)與傳統(tǒng)游戲開發(fā)的極大差別。
鑒于手機游戲與傳統(tǒng)游戲開發(fā)的巨大差別,并考慮到作為其運行載體的手機的實際局限性,在進行手機游戲的設計時也有必須遵循的原則,即有限的游戲時間;縮短等待時間;精干的程序;尋求最大的兼容性。
手機作為一種典型的MIDP設備,其能量供應是有限度的,在設計游戲時應當為用戶提供一個有限的游戲時間,以免游戲時間過長而大量消耗有限的能源。例如,可以把游戲時間限定在幾分種之內(nèi)完成或是將其劃分為若干階段分次進行。
鑒于手機游戲的處理速度不可能太快的客觀事實,為保持游戲的順暢進行,就必須盡量縮短游戲中的等待時間,尤其是在設計多人聯(lián)機游戲時一定要注意這個問題。而且由于存儲空間的限制,也要求設計精干的程序,否則將導致開發(fā)的游戲因過于臃腫而無法在手機執(zhí)行。
為手機游戲尋求最大的兼容性也是有必要的。由于不同型號,不同款式的手機不僅支持的J2ME SDK(Java 2 Micro Edition SDK)不同,屏幕尺寸及按鍵等也都存在差異。一款好的游戲如果因為底層的不兼容而局限于某一款機型顯然是一種浪費,其實游戲的劇本、流程設計等完全不用更改,只需針對其他系列的手機更換必要的低層處理就可以把游戲的市場拓展到其他機型。
2.手機游戲的實現(xiàn)技術
雖然J2ME對手機游戲的開發(fā)已經(jīng)成為主流,但并不是說只有J2ME能夠開發(fā)手機游戲,除此之外還有嵌入式和短信息等其他幾種手機游戲實現(xiàn)技術:
嵌入式游戲是指在手機出廠時就已經(jīng)固化在芯片中的游戲。早期手機提供的游戲大多是這一類游戲。由于這種技術不允許用戶自由更新游戲,所以這類游戲很快便被淘汰了。
短信息游戲是基于手機短信息服務(SMS)的手機游戲,通過向游戲服務商的服務器發(fā)送簡短的文字信息來獲取從游戲服務器反饋的結果信息。由于這種游戲是純文本交互形式,因此通常較乏味且輸入煩瑣,游戲成本較高(通常1條短信0.1元)。
隨著Java技術的發(fā)展和Java手機的推廣應用,使手機游戲進入J2ME時代。這種簡化版本的Java極大地提高了手機對游戲的支持能力,它擁有比嵌入式和短信息手機游戲更為完美的界面,而且允許使用子圖形動畫。J2ME手機程序已經(jīng)成為目前最佳的移動游戲開發(fā)環(huán)境,本文也正是圍繞著J2ME技術展開對手機游戲開發(fā)過程的介紹。
3.《賽車》游戲的劇本設計
本文將向大家介紹一款賽車游戲的制作過程。這是一款典型的體育競技類游戲,它以公路作為賽車場地,選手為一輛賽車,障礙物為在公路放置的炸彈。由于只安排了一輛賽車,所以制定的游戲規(guī)則不以速度取勝,而是按玩家規(guī)避障礙物的靈巧程度來積分。這可用玩家安全駕車的時長來度量,因為玩家玩得越熟練,其規(guī)避障礙物的手法也就更靈巧,安全駕駛的時間也就越長。
由于手機屏幕狹小,表現(xiàn)能力有限,而且在手機上也沒有提供任何軟硬件圖像處理加速,所以在手機游戲中不可能追求PC機的表現(xiàn)效果。在追求視覺效果的同時,應盡量做到簡單。
本游戲實例采用的是二維圖形表現(xiàn)形式,以筆直無轉彎的公路作為賽道。玩家將可以通過手機方向鍵控制賽車的左右移動,以規(guī)避隨機布置在賽道上的炸彈,炸彈在隨機布置后將不再移動。如果賽車的任意部分與炸彈相接觸即被判定為觸彈爆炸,本局游戲結束。
二、配置Eclipse開發(fā)環(huán)境
在使用任何一種語言進行編程時都離不開開發(fā)環(huán)境,Java語言也不例外,這里將向大家介紹一種非常著名的開發(fā)環(huán)境——Eclipse。
1.Eclipse基礎
(1)認識Eclipse
Eclipse是一個開放源代碼的、與NetBeans、Sun ONE Studio和Borland Jbuilder類似的一種基于Java的整合型可擴展開發(fā)平臺。就其本身而言,它只是一個框架和一組服務,用于通過插件組件構建開發(fā)環(huán)境。幸運的是,Eclipse 附帶了一個標準的插件集,包括Java開發(fā)工具(JDT)。其未來的目標不僅僅是成為專門開發(fā)Java程序的IDE環(huán)境,根據(jù)Eclipse的體系結構,通過開發(fā)插件,它能擴展到任何語言的開發(fā),甚至能成為圖片繪制的工具。
難能可貴的是,Eclipse是一個開放源代碼的項目,任何人都可以下載Eclipse的源代碼,并且在此基礎上開發(fā)自己的功能插件。也就是說未來只要有人需要,就會有建立在Eclipse之上的COBOL、Perl、Python等語言的開發(fā)插件出現(xiàn)。同時可以通過開發(fā)新的插件擴展現(xiàn)有插件的功能,例如,為了進行手機應用程序的開發(fā),本文所涉及到的《賽車》游戲就是通過J2ME插件的擴展來加以實現(xiàn)的。
(2)Eclipse的組織結構
Eclipse是一個開放源代碼的軟件開發(fā)項目,它專注于為高度集成的工具開發(fā)提供一個全功能的、具有商業(yè)品質的工業(yè)平臺。它主要由Eclipse項目、Eclipse工具項目和Eclipse技術項目等組成,具體包括Eclipse Platform、JDT、CDT和PDE等4個部分。JDT支持Java開發(fā)、CDT支持C開發(fā)、PDE用來支持插件開發(fā),Eclipse Platform則是一個開放的可擴展IDE,提供了一個通用的開發(fā)平臺。它提供建造塊和構造并運行集成軟件開發(fā)工具的基礎。Eclipse Platform允許工具建造者獨立開發(fā)與他人工具無縫集成的工具從而無須分辨一個工具功能在哪里結束,而另一個工具功能在哪里開始。
Eclipse SDK(軟件開發(fā)者包)是Eclipse Platform、JDT和PDE所生產(chǎn)的組件合并,提供了一個具有豐富特性的開發(fā)環(huán)境,允許開發(fā)者有效地建造可以無縫集成到Eclipse Platform中的工具。Eclipse SDK由Eclipse項目生產(chǎn)的工具和來自其他開放源代碼的第三方軟件組合而成。Eclipse項目生產(chǎn)的軟件以CPL發(fā)布,第三方組件有各自自身的許可協(xié)議。
2.Eclipse的下載與安裝
通過前面的介紹,我們了解到Eclipse是一款非常出色和著名的開源項目。你只需登陸Eclipse官方網(wǎng)站(www.eclipse.org)就可以免費獲得這款優(yōu)秀的開發(fā)環(huán)境。
進入主頁后單擊“Downloads”鏈接,將出現(xiàn)鏡像列表頁面,從中選擇較近的鏡像點并進入下載頁面,目前最新版本為3.0.1)。一般情況下,Eclipse同時提供了Release、Stable Build、Integration Build和Nightly Build等多個下載版本,建議下載Release或Stable版本。這里選擇Release版本。
進入該版本的下載頁面,單擊“eclipse-SDK-3.0.1-win32.zip”鏈接進行安裝包下載(針對Windows平臺)。同時,單擊“eclipse3.0.1-SDK-win-LanguagePackFeature.zip”鏈接下載對應的多國語言包插件以實現(xiàn)軟件的本地化。
安裝Eclipse的步驟非常簡單:你只需將下載的安裝壓縮包按原路徑直接解壓即可。之后將多國語言包解壓縮,并將解壓得到的“plugins”和“features”文件夾去覆蓋解壓到Eclipse安裝目錄下“eclipse”文件夾下的同名文件夾即可。如果當前操作系統(tǒng)的JRE環(huán)境安裝正確無誤,運行Eclipse.exe將進入其默認界面。
注意:這里的前提是JRE環(huán)境的安裝正確無誤,由于Eclipse本身是用Java語言編寫的,而下載的安裝壓縮包中并不包含Java運行環(huán)境,因此需要用戶自己另行安裝JRE,并且需要在操作系統(tǒng)的環(huán)境變量中指明JRE中bin的路徑。如果上述設置不正確,Eclipse將無法正常運行。另外,由于Eclipse版本升級較快,如果有更新版本,需先刪除舊版本重新安裝,而不能直接解壓到原來的路徑覆蓋舊版本。
3.一些必要的配置
(1)配置JRE
為了保證Eclipse的正常運行,我們需要配置JRE。你可以安裝Sun的JDK或IBM的JDK,推薦使用1.4以上版本。因為只有使用1.4以上版本的JDK才可以享受到新增的HotSwap功能對于調(diào)試帶來的方便。這里,我們使用Sun公司的1.5.0版本JDK,你可以從Sun公司官方網(wǎng)站http://java.sun.com免費下載。
(2)安裝J2ME SDK
為能夠保證手機應用程序的開發(fā),你還必須安裝J2ME SDK。Sun公司的J2ME Wireless Toolkit(WTK)便是常用的一款J2ME SDK,它提供了運行J2ME應用程序所需要的庫以及模擬器等,通過它可以進行程序的編譯、校驗、運行。有關WTK的信息可查詢http://java.sun.com/products/j2mewtoolkit。
目前,J2ME Wireless Toolkit共分3個版本:1.0.4、2.0和2.1。其中,1.0.4版只能開發(fā)MIDP 1.0程序,2.0版可以開發(fā)MIDP 2.0應用程序,2.1版則可以同時開發(fā)MIDP 1.0、JTWI、自定義等3種環(huán)境。需要注意的是,并非版本越高越好,必須視需求不同而選擇適當?shù)陌姹?#xff0c;才能開發(fā)出可以在真機上運行的MIDP應用程序。這里選用的是WTK 2.1,你可從Sun公司官方網(wǎng)站免費下載,按默認方式安裝該工具包并記下其安裝路徑以便以后在安裝EclipseMe插件時使用。
這里之所以選用Sun公司的J2ME Wireless Toolkit產(chǎn)品,是因為這樣開發(fā)出來的手機軟件可以具有更大的通用性。如果你只是出于為自己的愛機DIY應用軟件的目的,則完全可以根據(jù)自己使用手機的型號從相應廠商網(wǎng)站下載與之對應的J2ME SDK,這樣開發(fā)出來的手機軟件能夠以更優(yōu)的方式在真機運行。目前一些大的手機廠商開發(fā)的特定J2ME SDK主要有:Nokia的Nokia DEveloper's Suite與Nokia各款手機專屬SDK;SonyEricsson的SonyEricsson J2ME SDK;Siemens的Siemens Mobility Toolkits等。
4.J2ME插件EclipseMe的安裝
通過上面的介紹,你現(xiàn)在應當理解:對手機程序的開發(fā)實際也就是等于對J2ME項目的開發(fā)。雖然上面我們對環(huán)境進行了配置,使其能夠支持J2ME開發(fā),而且Ecilpse使用起來非常方便,但這對J2ME開發(fā)的支持還是遠遠不夠。下面,我們將通過為Eclipse安裝一個開發(fā)J2ME程序的插件EclipseMe來完善手機應用程序開發(fā)的最后一項準備工作。
目前,EclipseMe的最新版本為0.5.5(eclipseme.feature_0.5.5_site.zip),你可以登陸SourceForge網(wǎng)站http://eclipseme.sourceforge.net/免費下載。
進入SourceForge網(wǎng)站后單擊“Downloads”鏈接進入產(chǎn)品下載頁面,該頁面列有全部版本的EclipseMe插件及部分版本的源程序代碼。單擊需要下載的eclipseme.feature_0.5.5_site.zip,將出現(xiàn)下載鏡像列表頁面,你可以從中選取距離較近的鏡像站點進行下載。
對于EclipseMe 0.5.0版本及更早版本的安裝,可以下載后直接將其解壓到Eclipse安裝目錄下的“plugin”文件夾下即可很方便地完成對插件的安裝。但是到了0.5.5版本以后,EclipseMe的安裝方式發(fā)生了較大變化,再用以前的方法將不能成功安裝插件。下面將給出EclipseMe這一版本插件的具體安裝過程:
啟動Eclipse,單擊“幫助→軟件更新→查找并安裝……”菜單命令,打開“安裝/更新”對話框,選中“搜索要安裝的新功能部件”選項。單擊“下一步”按鈕。
在出現(xiàn)的對話框中單擊“新建本地站點……”按鈕,在打開的對話框中指定EclipseMe壓縮包的當前解壓路徑,然后將會在“要包括在搜索中的站點”列表中出現(xiàn)以當前指定目錄為名稱的站點項目。選中該項目,展開其樹型結構,可以看見其子項EclipseME也被同時選中。單擊“下一步”按鈕。
提示:最好將EclipseMe壓縮包解壓到一個路徑名中不包含漢字的文件夾下,例如,E:\EclipsMe\下,否則可能會在安裝過程中出現(xiàn)一些奇怪現(xiàn)象而妨礙安裝過程的順利的進行。
在出現(xiàn)的對話框中選中“EclipseME”按鈕。單擊“下一步”按鈕。在出現(xiàn)的對話框中單擊“我接受許可協(xié)議中的條款”選項。單擊“下一步”按鈕。在出現(xiàn)的對話框中指定Eclipse插件要安裝到的路徑,你可以單擊“添加站點”按鈕,在出現(xiàn)的對話框中選擇其他路徑(最好還是安裝到Eclipse的安裝目錄下),單擊“確定”按鈕完成即可。
為查看EclipseMe插件是否成功安裝,你可以在重啟Eclipse后單擊“窗口→首選項”菜單命令,打開“首選項”對話框。在左側窗口看到J2ME項即標明EclipseMe插件已經(jīng)成功安裝。
在“首選項”對話框中進行配置
5.對EclipseMe插件的配置
為了使新安裝的EclipseMe插件能夠正常工作,需要對其進行配置。展開J2ME項,選擇“Platform Components”子項,在右側窗口中將同步顯示其詳細配置。右鍵單擊“Wireless Toolkits”選項,選擇“Add Wireless Toolkit”命令,在打開的對話框中單擊“瀏覽”按鈕,在出現(xiàn)的對話框中指定先前安裝的Wireless Toolkit路徑。如果路徑指定正確且Wireless Toolkit也安裝正確,此時EclipseMe將自動檢測出該目錄所安裝的Wireless Toolkit的版本,并顯示在編輯框的下方。單擊“完成”按鈕,在“首選項”對話框右側的配置窗口中將顯示該Wireless Toolkit所支持的一些特性。如果你是針對某一機型的手機進行開發(fā),可以重復上面的步驟將其他廠商的無線開發(fā)工具包添加其中。
三、搭建游戲框架
1.創(chuàng)建J2ME項目
在Eclipse中首先創(chuàng)建J2ME MIDlet Suite項目“Racing”,所有后續(xù)的編碼、調(diào)試和運行都是在這個工程中進行。
啟動Eclipse,單擊“文件→新建→項目”菜單命令,在打開的對話框中展開“J2ME”選項,選中“J2ME Midlet Suite”子項后單擊“下一步”按鈕。在出現(xiàn)的對話框中設置項目名稱和項目存放路徑,一般保持默認路徑即可。單擊“下一步”按鈕。
在出現(xiàn)的對話框中對應用程序所支持的MIDP版本進行指定。如果考慮兼容性可以選擇“J2ME Wireless Toolkit 2.1 MIDP 1.0 platform”選項。當然,你也可以選擇“MIDP 2.0”選項。單擊“下一步”按鈕。
在出現(xiàn)的對話框中對Java構建設置進行定義,通常保持默認值即可。單擊“完成”按鈕,EclipseMe將自動設置好項目的編輯及運行環(huán)境。你可以在導航器視圖中單擊剛才創(chuàng)建的項目,在右側編輯視圖中將可以查看EclipseMe生成的項目結構。
查看創(chuàng)建的項目
2.創(chuàng)建J2ME應用程序
上面創(chuàng)建的MIDlet Suite,一般也稱作MIDlet應用程序套件,它可以包含一個或多個MIDlet,只是在發(fā)布時是以MIDlet Suite為單位進行,我們的一些實質性的工作都是在MIDlet中完成的。因此,需要繼續(xù)添加J2ME MIDlet項“RacingMIDlet”到項目中。
在導航器上單擊鼠標右鍵,選擇“新建→其他”菜單命令,在打開的對話框中展開“J2ME”選項,選中“J2ME Midlet”子項后單擊“下一步”按鈕。在出現(xiàn)的對話框中指定包(也可以保持默認值)和名稱,單擊“完成”按鈕后,EclipseMe將自動生成框架代碼,并將新創(chuàng)建的RacingMIDlet類按如下代碼進行編輯:
public class RacingMIDlet extends MIDlet {
public Display display;
public GameCtrl game;
public RacingMIDlet() {
super();
}
protected void startApp() throws MIDletStateChangeException {
// 獲得Display
display = Display.getDisplay(this);
// 獲得Displayable
Displayable current = display.getCurrent();
if (current == null) {
// 裝載logo圖像
Image logo = null;
try{
logo = Image.createImage("/logo.png");
}catch (IOException e) { }
// 顯示logo
Alert splashScreen = new Alert(null, "郎銳2005年作\n版權所有(c)\n2005--2006", logo, AlertType.INFO);
// 延遲4秒
splashScreen.setTimeout(2000);
//新建ChooseDemo對象
game = new GameCtrl(this);
// 顯示閃屏界面
display.setCurrent(splashScreen, game);
}else {
// 顯示當前界面
display.setCurrent(current);
}
}
protected void pauseApp() {
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
public void quit() throws MIDletStateChangeException {
// 退出程序
destroyApp(false);
notifyDestroyed();
}
}
這里通過一個Alert信息框完成對閃屏界面的顯示,所使用的位圖logo.png在開始可以暫用臨時圖像代替,最后再由美工完成的正式圖像替換。
因為游戲主題為賽車,因此本例使用的logo位圖最好顯示一些賽車的圖標,并輔以具有藝術字效果的游戲名稱。圖標可以很方便地下載得到,而游戲名稱的藝術字效果通常要由開發(fā)人員自己完成。除了可以使用專業(yè)的設計軟件外,還可使用兩種不同顏色書寫同字體、同大小的游戲名稱,然后將深色文字置后,淺色文字錯位少許后放置在前臺的方法通過視覺錯覺來實現(xiàn)立體字的效果。最后再與圖標合成到一張PNG格式的位圖,即可完成一個簡單logo位圖的制作。
Logo制作過程示意
編輯完畢后,Eclipse將提示有多處錯誤存在,這主要是由GameCtrl類還沒有添加造成的。接下來,向工程添加從Canvas類繼承的GameCtrl類,并編輯其類為如下代碼,以保存從RacingMIDlet類傳入的MIDlet對象和對命令按鍵、方向按鍵的添加與響應:
public class GameCtrl extends Canvas implements CommandListener{
private final Command startCommand;
private final Command quitCommand;
private final RacingMIDlet midlet;
public GameCtrl(RacingMIDlet midlet) {
super();
// 保存MIDlet類對象
this.midlet = midlet;
// 添加命令按鍵
quitCommand = new Command("退出", Command.EXIT, 2);
addCommand(quitCommand);
startCommand = new Command("開始", Command.OK, 1);
addCommand(startCommand);
// 偵聽按鍵響應
setCommandListener(this);
}
protected void paint(Graphics g) {
}
public void commandAction(Command arg0, Displayable arg1) {
if (arg0 == startCommand){
// 用戶開始游戲
initialize();
}
if (arg0 == quitCommand){
// 用戶退出游戲
try{
midlet.quit();
}
catch(MIDletStateChangeException e){}
}
}
private void initialize() {
}
protected void keyPressed(int keyCode) {
// 得到按鍵動作
int gameAction = getGameAction(keyCode);
switch (gameAction) {
case RIGHT:
break;
case LEFT:
break;
default:
break;
}
}
}
這里除了新增的keyPressed()方法外,與以前介紹過的程序框架并沒有太大的差別。這個keyPressed()方法主要用來捕獲用戶的手機按鍵,由于在賽車駕駛時只需控制其左右移動方向即可,因此這里只對getGameAction ()方法返回的鍵值與RIGHT和LEFT進行比較。稍后將完成這兩個分支的功能實現(xiàn)。
四、實現(xiàn)游戲界面
由于將賽車游戲抽象為場地、選手和障礙物,因此在游戲的界面實現(xiàn)時也主要圍繞這3個中心展開。
1.實現(xiàn)場地界面
由于這里的公路是平直無轉彎無路口的,因此展現(xiàn)到二維平面上就是一個矩形??梢韵胂?#xff0c;如果只在手機屏幕顯示一個矩形,無論填充什么顏色,都很難令人聯(lián)想到是一條公路。為了表現(xiàn)出公路的特征,不妨在公路中間繪制一條隔離車道用的斑點線。由于在比賽進行時,賽車與公路之間是相互運動的,而作為游戲的主角,賽車一定是不能超出玩家視線的。也就是說,賽車應當始終處于屏幕顯示范圍之內(nèi),這樣一來,為了表現(xiàn)賽車的運動,就必須讓公路動起來。一個簡單的辦法是,在繪制公路中間的斑點線時對同一位置的斑點進行交替繪制。
簡單展示公路特征
可能從紙面上很難理解這樣簡單的處理怎么能夠產(chǎn)生公路想后移動的效果,不妨將上圖的公路中線看作13段連續(xù)的LED燈管,開始時為奇數(shù)的燈管點亮,為偶數(shù)的熄滅。接下來點亮的燈管熄滅,熄滅的點亮,如此反復,正如街頭的霓虹燈,可以通過對燈管點亮、熄滅的控制來實現(xiàn)一種移動的視覺錯覺。在代碼實現(xiàn)上可在paint()方法中添加如下代碼來實現(xiàn)對公路中線的繪制:
// 繪制動態(tài)公路中線
g.setColor(0, 0, 255);
if (lineMode == true){
lineMode = false;
for (int i = 0; i < height; i += 20)
g.drawLine(width / 2, i, width / 2, i + 10);
}else{
lineMode = true;
for (int i = 10; i < height; i += 20)
g.drawLine(width / 2, i, width / 2, i + 10);
}
其中,通過lineMode變量對虛線的繪制模式進行控制,width和height分別為屏幕的寬度和高度。在構造函數(shù)中分別通過getWidth()和getHeight()方法獲得。為了能夠以固定時間間隔周期性地調(diào)用paint()函數(shù),可在程序初始化方法initialize()中創(chuàng)建一個定時器,并在定時器的執(zhí)行方法run()中添加repaint()方法以完成對paint()函數(shù)的周期性調(diào)用。有關定時器的創(chuàng)建,可先向工程添加一個基于TimerTask類的新類NextFrame,用于周期性定時執(zhí)行任務。并在GameCtrl類添加其類聲明和另外一個Timer類的對象:
private Timer timer = new Timer();
private NextFrame nextFrame;
在需要開啟定時器時,以nextFrame對象為參數(shù)去調(diào)用Timer類的schedule ()方法并指定時間間隔即可:
nextFrame = new NextFrame(this);
timer.schedule(nextFrame, 300, 300);
2.實現(xiàn)炸彈與賽車界面
炸彈與賽車的界面實現(xiàn),可以通過調(diào)用低級類Graphics中的相關繪圖方法來繪制,也可以通過顯示位圖的方式來實現(xiàn)。前者幾乎不占用內(nèi)存,但繪制過程煩瑣,后者的顯示方法相比之下要簡單許多但卻要占用少量的內(nèi)存。這里,我們選用后者。
炸彈與賽車示意
首先準備上圖所示的兩張PNG格式位圖并將其添加到工程中。炸彈和賽車作為本游戲的主角,其圖像在游戲過程中將被頻繁使用,因此,為方便使用可將與這兩位圖相關的Image對象定義為公有型的類成員變量。并在類構造函數(shù)中完成對位圖文件的裝載:
try{
// 裝載炸彈圖像
bombImage = Image.createImage("/bomb.png");
// 裝載賽車圖像
carImage = Image.createImage("/car.png");
}catch(Exception e) {}
對于這種Image對象的繪制,可使用Graphics類成員函數(shù)drawImage()方法,該方法的使用方法在前文已有過詳細介紹。由于賽車需要左右移動,炸彈也要在被隨機放置后不斷從屏幕滑過,因此在繪制Image對象時,其位置最好能通過公有型的類成員變量來設置。這樣就可以在一個專門的控制方法中對賽車和炸彈的顯示位置進行調(diào)整,而在paint()方法中只負責對圖形進行繪制,從而實現(xiàn)對游戲功能的模塊化劃分。下面這段賽車和炸彈圖像的繪制代碼將以各自圖像的中心位置為基準點進行繪制,共完成一輛賽車和四棵炸彈的屏幕繪制:
// 賽車水平位置
public int carPos = 0;
// 炸彈位置
public int[] bombPosX = {0, 0, 0, 0};
public int[] bombPosY = {0, 0, 0, 0};
// 炸彈是否出界
public boolean[] bombCanUse = {false, false, false, false};
……
// 繪制賽車
g.drawImage(carImage, carPos, height - carImage.getHeight(), Graphics.HCENTER | Graphics.VCENTER);
// 繪制炸彈
for (int i = 0; i < 4; i++){
if (bombCanUse[i] == true)
g.drawImage(bombImage, bombPosX[i], bombPosY[i], Graphics.HCENTER | Graphics.VCENTER);
}
這里的bombCanUse數(shù)組用來對當前炸彈是否出界予以標識,這里所說的炸彈出界并不是指炸彈當前位置超出屏幕范圍,而是在真實屏幕上方另設一連續(xù)的與真實屏幕等大的、可用來隨機放置炸彈的虛擬屏幕。此虛擬屏幕和真實屏幕的并集才是炸彈的有效區(qū)域。凡是落在此區(qū)域內(nèi)的炸彈均不予銷毀,如果有炸彈移出有效區(qū)域,則在炸彈放置區(qū)重新隨機放置一枚,始終保持炸彈有效區(qū)域內(nèi)的炸彈總數(shù)為4個。
炸彈有效區(qū)域示意
最后,一定要記得在paint()方法開始繪制下一場景之前通過下面的清屏語句擦除當前場景的顯示。否則,在游戲開始后隨著各種角色的移動,屏幕將變成一個“大花臉”。
// 白色清空畫布
g.setColor(255, 255, 255);
g.fillRect(0, 0, width, height);
五、角色移動與碰撞檢測
前面對游戲的骨架和界面都已經(jīng)實現(xiàn),但此時的游戲仍然毫無生氣,因為我們還沒有實現(xiàn)其靈魂。接下來將要進行的角色移動與碰撞檢測將能夠使游戲中的主角動起來,并能夠通過對當前游戲狀態(tài)的檢測來自行判斷游戲是否結束。
1.角色移動
(1)移動賽車
由于道路的移動是通過交替繪制公路中線所引起的錯覺來實現(xiàn)的。因此,實際真正需要移動的角色只有炸彈和賽車。本例將以賽車為基準,它始終處于屏幕下方,玩家可以通過手機左右方向鍵實現(xiàn)對賽車的左右移動。顯然,對賽車的移動控制全部由玩家掌握,其控制代碼只能在keyPressed()方法對左、右按鍵的分支處理中實現(xiàn)。由于在先前的設計中實現(xiàn)了顯示與控制的分離,因此在這里只需對表示賽車水平位置的carPos變量取值進行修改即可。為防止賽車移出屏幕,需要添加必要的越界保護代碼:
// 得到按鍵動作
int gameAction = getGameAction(keyCode) switch (gameAction) {
case RIGHT:
// 右移賽車
carPos += 5;
// 防止越界
if (carPos > width - carImage.getWidth() / 2)
carPos = width - carImage.getWidth() / 2;
break;
case LEFT:
// 左移賽車
carPos -= 5;
// 防止越界
if (carPos < carImage.getWidth() / 2)
carPos = carImage.getWidth() / 2;
break;
default:
break;
}
// 重繪屏幕
repaint();
(2)移動炸彈
與賽車不同,炸彈的移動控制由手機全權負責。只要游戲在運行,炸彈就不停的從屏幕上方滑落,對于類似的處理應當交由定時器任務類完成相關操作。NextFrame類成員方法run()將在定時器每次被觸發(fā)時調(diào)用。
在處理炸彈移動時,首先對炸彈是否超出有效區(qū)域進行檢測。由于初始運行時屏幕沒有炸彈,所以可以將其當作超出有效區(qū)域進行處理。對于這種情況,首先通過Random類的nextLong()方法得到兩個隨機數(shù),然后分別以屏幕寬度和高度為模進行取模運算,其結果經(jīng)越界限制后將作為炸彈的初始設置坐標。在每設置一棵炸彈后要及時對該炸彈所對應的bombCanUse元素設置炸彈有效值,以在后續(xù)的處理中執(zhí)行下落顯示。
與賽車的左右移動類似,炸彈的下落可以通過不斷增加其縱坐標來實現(xiàn)。只是在下落過程中不必進行越界保護處理,如果炸彈越過有效區(qū)域就通過bombCanUse將其標記為無效。將在下一定時周期重復前面的過程:
for (int i = 0; i < 4; i++){
// 炸彈沒顯示時設置初始位置,顯示后水平位置固定
if (gameCtrl.bombCanUse[i] == false){
// 隨機設置炸彈初始位置
int x = (int)(rand.nextLong());
x = (int)(x % gameCtrl.width);
gameCtrl.bombPosX[i] = x;
int y = (int)(rand.nextLong());
y = (int)(y % gameCtrl.height);
// 將炸彈設置在虛擬屏幕
gameCtrl.bombPosY[i] = -y;
// 限制炸彈水平位置
if (x < bombWidth)
x = bombWidth;
if (x > gameCtrl.width - bombWidth)
x = gameCtrl.width - bombWidth;
// 標志第i個炸彈進入可視區(qū)
gameCtrl.bombCanUse[i] = true;
}else{
// 炸彈下移
gameCtrl.bombPosY[i] += 3;
// 炸彈出界檢測
if (gameCtrl.bombPosY[i] > gameCtrl.height + bombHeight / 2)
gameCtrl.bombCanUse[i] = false;
}
}
如果此時運行程序,雖然可以實現(xiàn)賽車在布有炸彈的公路上行駛的效果,而且玩家也可以控制賽車的前進方向,但卻存在一個致命的缺陷——當賽車和炸彈相撞時,炸彈依舊下落,賽車依舊行駛,好像什么都沒有發(fā)生一樣。這是由于沒有為游戲添加碰撞檢測代碼所致。
2.碰撞檢測
碰撞檢測是游戲中經(jīng)常使用的一種重要算法。用于檢測游戲中的兩物體是否發(fā)生表面接觸,例如,子彈是否命中歹徒,炮彈是否擊中目標等等。只有進行了碰撞檢測才有能在出現(xiàn)上述情況后實現(xiàn)歹徒被擊斃、目標被摧毀等結果。
炸彈與賽車發(fā)生碰撞示意
上圖展示了炸彈與賽車發(fā)生碰撞時的所有可能情形。從圖中可以看出,只要炸彈完全進入圖中的虛線矩形框就必然與賽車發(fā)生了碰撞。對本游戲而言,發(fā)生了碰撞即意味著賽車被炸毀,游戲結束。所以,在炸彈下落過程中不難寫出如下碰撞檢測代碼:
// 碰撞檢測
if (gameCtrl.bombPosY[i] + bombHeight / 2 >= gameCtrl.height - carHeight * 3 / 2 && gameCtrl.bombPosY[i] - bombHeight / 2 <= gameCtrl.height - carHeight / 2 && gameCtrl.bombPosX[i] + bombWidth / 2 >= gameCtrl.carPos - carWidth / 2 && gameCtrl.bombPosX[i] - bombWidth / 2 <= gameCtrl.carPos + carWidth / 2){
// 結束游戲
gameCtrl.isGameOver = true;
// 關閉定時器
cancel();
}
其中,carWidth、carHeight、bombWidth和bombHeight變量分別是通過carImage和bombImage對象調(diào)用各自的getWidth()和getHeight()方法而返回得到的賽車圖像尺寸和炸彈圖像尺寸。如果發(fā)生碰撞,將通過公有型的boolean類型變量isGameOver來指示游戲的結束。同時調(diào)用TimerTask類成員方法cancel()關閉先前設置的定時器。
對于非勝負類游戲,由于在游戲結束時并沒有勝出方,所以一般都是以積分的形式反饋給玩家當前局所取得的分數(shù)。對于本例,分數(shù)顯然是與安全駕駛時間成正比的,在程序實現(xiàn)時,可以在定時器每次觸發(fā)run()方法時對積分進行累加,并在游戲結束時通過下述代碼以信息框的形式將當前積分反饋給玩家:
isGameRun = false;
// 顯示logo
Alert result = new Alert("本局積分", String.valueOf(score), null, AlertType.INFO);
// 延遲4秒
result.setTimeout(2000);
// 顯示閃屏界面
midlet.display.setCurrent(result, this);
經(jīng)過上述辛勤工作,一款真正的J2ME手機游戲程序已經(jīng)完成!
六、測試與發(fā)布游戲
單擊“運行→運行”菜單命令,在打開的對話框左側配置窗口中右鍵單擊“Wireless Toolkit Emulator”選項,選擇“新建”命令,在對話框右側將顯示相應的運行配置選項。一般可保持默認設置,也可以在“Emulation”選項卡中對默認設備進行指定。通常選擇“DefaultClolorPhone”選項即可,其模擬的是在彩屏手機上的運行效果。由于目前支持Java的手機一般配置都不是很低,絕大多數(shù)也都是彩屏配置,因此“DefaultClolorPhone”選項應該是比較大眾。當然,你也可以設置“DefaultGrayPhone”等其他選項以模擬在單色或其他配置的手機上的運行效果。
最后,單擊“運行”按鈕執(zhí)行我們創(chuàng)建的賽車游戲。
當然,本例作為一款教學性質的游戲實例,沒有做太多的完善與優(yōu)化。給你留下了較大的游戲擴展空間。你可以在本游戲基礎上嘗試進一步的擴展和修改,例如,增加前后方向鍵以模擬加大油門和剎車;另外增加一些參賽車輛;根據(jù)玩家游戲進行時間的長短動態(tài)調(diào)整游戲難度,包括加快車速、增加障礙物等等。代碼編寫無誤后可以先在PC上的模擬器中運行調(diào)試,并對出現(xiàn)的問題進行修改,一切無誤后再打包發(fā)布。
轉載于:https://www.cnblogs.com/handboy/p/7141571.html
總結
以上是生活随笔為你收集整理的Java手机游戏开发简明教程 (SunJava开发者认证程序员 郎锐)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 坐席排序java_坐席排队功能 - os
- 下一篇: java美元兑换,(Java实现) 美元