手机游戏毕业设计论文
1? 緒論
1.1 手機軟件現狀
在信息社會中,手機及其他無線設備越來越多的走進普通百姓的工作和生活,隨著信息網絡化的不斷進展,手機及其他無線設備上網絡勢在必行。但是傳統手機存在以下弊端:
1.? 傳統手機出廠時均由硬件廠商固化程序,程序不能增加、刪除,有了錯誤也不能更新、修改,若要增加新功能必須另換一部手機。
2.? 傳統手機訪問互聯網是通過WAP(Wireless Application Protocal),所有網絡資源必須接通網絡才能在線訪問,非常耗時、費用亦很高。
而Java技術在無線應用方面的優勢非常明顯:
1.? 應用程序可按需下載,而不是購買由硬件商提供的套件,可升級空間大。
2.? Java技術提供了一個類庫,它使的應用開發商可以創建更為直覺、豐富的用戶界面(GUI);
3.? Java技術使網絡帶寬的應用更為有效,因為應用程序可以下載到器件上,并在本地運行,僅僅是在連接到服務器時才會占用網絡帶寬。
基于以上分析,Java手機將是未來手機的發展方向,是業界的熱點。
1.2 J2ME介紹
雖然 Java 已經被用到許多企業級軟體上,可是其實骨子里面還是非常適合用在嵌入式系統之中。Java平臺演進到Java2后,Java平臺分別針對不同領域的需求被分成四個版本,亦即J2EE、J2SE、J2ME以及JavaCard。其中J2ME定位在消費性電子產品的應用上。這個版本針對資源有限的電子消費產品的需求精簡核心類庫,并提供了模塊化的架構讓不同類型產品能夠隨時增加支持的能力。這個版本的應用層面相當廣泛,會是未來Java平臺發展的重點項目。
J2ME在1999年的JavaOne開發人員大會上初次亮相,它的目標是面向智能無線設備和小型計算機設備的開發人員。J2ME的一個關鍵優點是,J2ME與所有支持Java的設備都是兼容的。支持Java的設備就是任何運行Java虛擬機器的計算機。Motorola、Nokia等生產廠商都生產支持Java的設備。、
J2ME平臺是由配置(Configuration)和簡表(Profile)構成的。配置是提供給最大范圍設備使用的最小類庫集合,在配置中同時包含Java虛擬機。簡表是針對一系列設備
提供的開發包集合。在J2ME中還有一個重要的概念是可選包(Optional Package),它是針對特定設備提供的類庫,比如某些設備是支持藍牙的,針對此功能J2ME中制定了JSR82(Bluetooth API)提供了對藍牙的支持。
目前,J2ME中有兩個最主要的配置,分別是Connected Limited Devices Configuration(CLDC)和Connected Devices Configuration(CDC)。
作為第一個面對小型設備的Java應用開發規范,CLDC是由包括Nokia,Motorola和Siemens在內的18家全球知名公司共同協商完成的。CLDC是J2ME核心配置中的一個,可以支持一個或多個profile。其目標主要面向小型的、網絡連接速度慢、能源有限(主要是電池供電)且資源有限的設備,如手機、PDA等。
而CDC則是主要用于運算能力相對較佳、在電力供應上相對比較充足的嵌入式裝置 (比方說冷氣機、電冰箱、電視機機頂盒 (set-top box))
1.3 手機游戲應具有的特征
??? 一個手機游戲應該具有以下特征:
易于學習: 既然手機游戲面向的是普通消費者而不是計算機專家,那么他們不可能深入的學習游戲技巧。消費者不會花幾個小時去研究一個3元的手動操作的游戲。保持游戲的簡單是最基本的要求。
可中斷性: 多任務處理是手機生活方式的基本特征。手機用戶常常在任務(如等一個電子郵件或者等車)之間有一小段時間。而游戲、日歷管理、通訊和工作數據訪問使用的是同一個設備。所以一個好的手機游戲應該提供短時間的娛樂功能,并且允許用戶在游戲和工作模式之間順利切換。
基于訂閱:手機游戲的盈利成功取決于他們巨大的使用量。一開始開發和設計每個游戲都是昂貴的。如果一個手機游戲開發者要贏利的話,重要的是:同一個游戲引擎,多個標題,基本的故事情節類似。基于訂閱的游戲是不斷產生收入的最好方法。
豐富的社會交互: 不管一個游戲設計得多好,只要玩家找到了它的根本模式或者玩完了所有的游戲路徑很快就會厭煩這個游戲。對于一個基于訂閱的游戲,重要的是與別的玩家合作以增強所玩游戲的智力和隨機性。在今天紛繁復雜的多玩家游戲中具有豐富社會交互的游戲證明是成功的。
利用手機技術的優點: 巨額的手機技術研發費用都花在提高設備和網絡的可用性和可靠性上面。因此,手機設備硬件和網絡協議與桌面/控制臺世界(如全球定位系統(GPS)擴展、條形碼掃描儀、和短消息服務(SMS)/多媒體信息服務(MMS)通訊)有著非常大的差別。好的手機游戲應該利用那些更新的設備特征和網絡基礎設備的優點。
1.4 本游戲背景介紹
在抗戰中,由國民政府領導的中國空軍是所有國民黨軍隊中抗戰最為徹底,也最為英勇的部隊,雖然開戰之初力量懸殊,但是面對窮兇極惡的日本侵略者,他們毫不畏懼,視死如歸,全力以赴投身到民族救亡的偉業中去,用自己的鮮血和生命譜寫了中華民族最為豪邁的詩篇。自一九三二年二月五日“一·二八”事件始,至一九四五年八月十四日止,抗戰期間,共出動飛機一千一百二十八批,八千八百四十七架次,擊落敵機五百二十九架,擊傷敵機一百一十架,炸毀敵機二百二十七架。同時,中國空軍空戰中一共犧牲空勤人員六百六十一名。
我至今仍然清楚的記得,在抗日戰爭即世界反法西斯戰爭勝利50周年的時候,我在一本描述抗戰空軍的書里第一次看到閻海文烈士那年青的面孔時所帶來的震撼,第一次看到高志航、沈崇海等空軍烈士的事跡時所帶來的感動,第一次聽說碧山空戰時的無奈。
時至今日,已經很少有人能夠記得在中國的天空獻身的抗日英雄們,我只能引用下面這句話來表達我的心情:“你們的名字無人知曉,你們的業績與世長存! ”
我的這款游戲取名為《覽橋風光》,以紀念從覽橋中央航校走出的英雄們。
1.5 本章小結
引言和第一章中介紹了手機在無線應用方向的當今概況,J2ME的相關內容,分析了J2ME在手機軟件開發中起的重要作用,描述了本論文的相關背景。
?
?
?
?
?
?
?
?
?
?
2? 開發環境及相關技術的介紹
2.1? 開發環境
操作系統:Microsoft Windows XP
程序語言:Java 2
開 發 包:Java(TM) 2 Standard Edition (5.0)
??????? Sun Micro. J2ME?? Wireless Tool Kit 2.2
IDE:??? Eclipse 3.01
2.2? Java語言特點
1. 平臺無關性
Java引進虛擬機原理,并運行于虛擬機,實現不同平臺之間的Java接口。Java的數據類型與機器無關。
2. 安全性
Java的編程類似C++,但舍棄了C++的指針對存儲器地址的直接操作,程序運行時,內存由操作系統分配,這樣可以避免病毒通過指針入侵系統。它提供了安全管理器,防止程序的非法訪問。
3. 面向對象
??? Java吸收了C++面向對象的概念,將數據封裝于類中,實現了程序的簡潔性和便于維護性,使程序代碼可以只需一次編譯就可反復利用。
4. 分布式
Java建立在TCP/IP網絡平臺上,提供了用HTTP和FTP協議傳送和接收信息的庫函數,使用其相關技術可以十分方便的構建分布式應用系統。
5. 健壯性
Java致力與檢查程序在編譯和運行時的錯誤,并自動回收內存,減少了內存出錯的可能性。Java取消了C語言的結構、指針、#define語句、多重繼承、goto語句、操作符、重載等不易被掌握的特性,提供垃圾收集器自動回收不用的內存空間。
2.3? 關于ECLIPSE
??? Eclipse 是一個開放源代碼的、基于 Java 的可擴展開發平臺。就其本身而言,它只是一個框架和一組服務,用于通過插件組件構建開發環境。幸運的是,Eclipse 附帶了一個標準的插件集,包括 Java 開發工具(Java Development Tools,JDT)。
雖然大多數用戶很樂于將 Eclipse 當作 Java IDE 來使用,但 Eclipse 的目標不僅限于此。Eclipse 還包括插件開發環境(Plug-in Development Environment,PDE),這個組件主要針對希望擴展 Eclipse 的軟件開發人員,因為它允許他們構建與 Eclipse 環境無縫集成的工具。由于 Eclipse 中的每樣東西都是插件,對于給 Eclipse 提供插件,以及給用戶提供一致和統一的集成開發環境而言,所有工具開發人員都具有同等的發揮場所。
這種平等和一致性并不僅限于 Java 開發工具。盡管 Eclipse 是使用 Java 語言開發的,但它的用途并不限于 Java 語言;例如,支持諸如 C/C++、COBOL 和 Eiffel 等編程語言的插件已經可用,或預計會推出。Eclipse 框架還可用來作為與軟件開發無關的其他應用程序類型的基礎,比如內容管理系統。Eclipse 是一個開放源代碼的、基于 Java 的可擴展開發平臺。就其本身而言,它只是一個框架和一組服務,用于通過插件組件構建開發環境。
2.4 關于Wireless Tool Kit
WTK(Wireless Tool Kit)是Sun公司針對J2ME推出的用于手機和Palm等移動設備的開發包,是除手機廠商的專用開發包外唯一的手機模擬器開發包。它通用性高,開發出的應用程序可保證能運行在大部分設備上,而不像專用廠商具有一定的不兼容性。雖然它沒有強大的功能和完善的調試手段,但它提供運行模擬器的最基本組件,是其他IDE需集成采用的必備元素。
2.5 Java Appication Manager
手機中負責調配程序運行資源的管理后臺是Java Application Manager。它所使用的傳輸媒體可以是紅外線、網絡、以及其他可用來傳輸的媒體。Java Application Manager 會從網絡上下載代表該Application Suite 的JAR 檔,接著在手機上安裝此MIDlet Suite,然后在手機開始執行該應用程序。
2.6 本章小結:
第二章介紹了Java語言的特點、本程序的開發環境及其相關工具的原理和使用。
?
3? 程序結構、思想和相關技術
3.1 本程序需要解決的主要技術問題
1.? 游戲程序是一項精度要求很高的程序系統,因為其代碼利用率很高。一個實時運行的最終作品,每秒都會運行成千上萬行程序,繪圖事件、鍵盤事件都會以極高的頻率在后臺等待響應,若有絲毫的差別都將很容易導致程序在運行不久后可能出現嚴重錯誤,甚至死循環。因此,其邏輯設計應當相當嚴謹,需將所有可能發生的事件及意外情況考慮在設計中。
2.? 游戲中為了美觀,適用性強,可能需要采用外部文件引入的圖片貼圖,有關貼圖,在MIDP2.0中提供了用于增強游戲功能的game包,使得解決靜態或動態、畫面背景、屏幕刷新的雙緩沖等都有較好的解決方案。
3. 玩家飛機的運行可以通過鍵盤響應事件控制,但敵方則因為是自動運行,就需要有一定的智能性;敵人飛機的運行算法也要進行相關的設置,已免游戲過于簡單。
4.對于雙方發射的子彈應該賦予不同的速度,同時,程序應該設定敵人飛機的子彈不與敵人的飛機進行碰撞檢測,已增加游戲的可玩性。
5. 雙方的飛機在前進時也需要考慮到是否碰撞到對方飛機,以免重疊運行,造成許多物理上不可能的情況,缺乏真實感。每一次刷新頁面、每前進一步都需要進行相關的碰撞檢測。
6.為了增加界面的美觀,在程序中添加了白云。由于手機屏幕大小有限,所以白云的數量和出現的位置要經過相關的設置,才能實現白云不規則出現的效果。
7.? 游戲的地圖不可能通過繪圖來解決。否則,不僅難于控制和處理過多的元素,也會因過多的大型圖片而不能限制程序的大小,失去手機上程序的原則和Java的優勢。
8.? Java是基于虛擬機的半解釋型編譯系統,其執行效率較C++等完全編譯后的程序會低很多,程序如果不進行精簡和優化,將可能導致運行的不流暢。除開發過程中對結構上的控制、變量的使用、算法的優化等優化外,還可以使用混淆器(Obfuscator)進行程序打包后的優化。
9.? 游戲的結束、開始、動態信息畫面作為構成一個程序都是必不可少的重要部分。良好的用戶界面更是吸引用戶的硬指標,相關的美術構圖和人性化設置也需要有一定的考慮。
以上相關技術細節和整體流程將分別在以下小節闡述。
3.2? 程序流程
| 消減狀態 (Destroyed) |
| 停止狀態 (Paused) |
| 運行狀態 (Active) |
| StartApp() |
| DestroyApp() |
| 呼叫MIDlet的構造函數 |
| DestroyApp() |
| PauseApp() |
| 圖3-1? MIDlet的流程 |
每個MIDlet都必須繼承javax.microedition.midlet.MIDlet這個抽象類。在MIDP規范中定義了MIDlet的生命周期,以及可以存在的三種狀態,包括Paused、Active以及Destroyed,每一個MIDlet在任何時刻只可能處于其中的一個狀態。這三種狀態的轉換關系如圖3-1所示:MIDlet有三個狀態,分別是pause、active和destroyed。在啟動一個MIDlet的時
候,應用管理軟件會首先創建一個MIDlet實例并使得他處于pause狀態,當startApp()方法被調用的時候MIDlet進入active狀態,也就是所說的運行狀態。在active狀態調用destroyApp(boolean unconditional)或者pauseApp()方法可以使得MIDlet進入destroyed或者pause狀態。值得一提的是destroyApp(boolean unconditional)方法,事實上,當destroyApp()方法被調用的時候,AMS通知MIDlet進入destroyed狀態。在destroyed狀態的MIDlet必須釋放了所有的資源,并且保存了數據。如果unconditional為false的時候,MIDlet可以在接到通知后拋出MIDletStateChangeException而保持在當前狀態,如果設置為true的話,則必須立即進入destroyed狀態。
本程序采用面向對象的設計模式,對游戲中的所有物體賦予對象的概念和屬性。運行程序后允許用戶選擇執行選項菜單,在開始游戲后將先從外部文件載入地圖文件,對背景的所有物體進行繪圖。在主程序運行的線程中,畫面刷新將以一定的頻率采用雙緩沖技術對屏幕重繪,實時反映整個游戲的進行狀態。
游戲開始后先繪制地圖,并將各個對象實例化。在主程序運行的線程中,游戲中所有的對象都應該運行在同一個線程下。當敵人或者用戶的子彈達到射程范圍后,并不刪除子彈對象,而是使用setVisable(false)使其不能顯示,當用戶或敵人在次發射子彈時,只需使用setVisable(true)設置成可以顯示即可。在屏幕重繪的主程序中,將在每次的循環中判斷若干事件,以便程序進入相關的分支執行相關的反應代碼。如:玩家剩余飛機數是為0、敵人、玩家飛機是否被擊中、屏幕上相關信息的繪制等。
程序為需要完成獨立功能的模塊設置了單獨的類。lzhhdm類繼承自Midlet,gameScrenn類、MenuScreen類繼承自GameCanvas,mybullets繼承自Sprite類。載入程序后首先啟動的是程序介紹的信息畫面。點擊ok后調用MenuScreen類實現菜單。
如果選擇進入游戲,則調用gameScreen類,并且中止MenuScreen類中的線程運行,已提高運行速度。
Mybullets類為玩家子彈類。
3.3 Canvas類
為了能有程序開發人員控制接口的外觀和行為,需要使用大量的初級用戶接口類,尤其在游戲程序中,幾乎完全依賴的就是Canvas抽象類進行繪圖。從程序開發的觀點看,Canvas類可與高級Screen類交互,程序可在需要時在Canvas中摻入高級類的組件。Canvas提供了鍵盤事件、指點桿事件(如果設備支持),并定義了允許將鍵盤按鍵映射為游戲控制鍵的函數。鍵盤事件由鍵代碼指定,但這樣控制游戲會導致缺乏通用性,并不是每個設備的鍵盤布局都適合游戲的操作。應當將鍵代碼轉換為游戲鍵的代碼,以便硬件開發商能定義他們自己的游戲鍵布局。
3.4 Graphics類
Graphics類提供了簡單的2D繪圖功能。它具有24位深度色彩的繪制能力,以三原色分別各占一個字節表示其顏色。程序只能在paint()函數中使用Graphics繪制,GameCanvas可調用getGraphics()函數直接繪制在緩沖區上,可以在任何時間請求傳輸到前臺。其對象會被傳給Canvas的paint()函數,以便最終顯示。
3.5 MIDP1.0技術下的繪制背景技術
在沒有MIDP2.0前,進行游戲繪圖一般需要手動編程使用雙緩沖。需要在paint()方法內將所想要畫的圖形畫在一張預先準備好的背景上,等所有繪圖操作都完成后再將背景的數據拷貝到實際的屏幕上。Image類提供了一個建立背景的靜態方法createImage(int width, int height),再利用getGraphics()方法取得屬于這個背景的Graphics對象,所進行的繪圖操作都會作用在背景上,等到全部的繪圖操作完成后,再調用drawImage()方法將背景的數據復制到實際顯示的屏幕上。
這樣的技術在繪制動畫時特別有用。繪制動畫時經常需要不斷地更新畫面,而更新畫面的操作就是先將屏幕以fillRect()的方式清除,再將下一張圖片畫在屏幕上,然而反復的清除及重繪會造成屏幕的閃爍現象(flicker),因此使用雙重緩沖的好處就是在背景進行這個清除及重繪的操作,再將完成的繪圖拷貝到屏幕上,由于用戶看不到清除的操作,因此就不會出現閃爍的現象了。不過在某些MIDP的實現上已經加上了雙重緩沖的支持,因此在處理前應先利用Canvas類的isDoubleBuffer()方法來判斷。
3.6 MIDP2.0新增的GameCanvas包
??? J2ME的流行促進幾個運營商和制造商開發了一些支持游戲的類,但是,這卻造成了游戲缺乏可移植性的問題,例如,很難將使用Siemens的Sprite類的游戲移植到Nokia上。
??? 在MIDP2.0版本發布后,這些游戲移植性問題初步得到了解決。MIDP2.0新加入了
GameCanvas、Sprite、Layer、LayerManager、TiledLayer五個與游戲開發相關的類。其中 Layer類一般不會直接用到。
??? Game類的出現不僅降低了錯誤出現的幾率,也使游戲代碼變的更小,因為開發者不需要自己編寫象Sprite這種例子。下面將簡要介紹Game類。
?? ?GameCanvas類繼承自Canvas,所以具有Canvas所具有的功能,還額外增加了一些便于游戲設計的功能。比如: GameCanvas類直接提供了getKeyStates(),使程序員可以在同一個線程自己偵測按鍵的狀態。GameCanvas類提供了flushGraphics()的功能,實現了雙緩沖技術。
??? 所謂的Sprite,就是畫面上獨立移動的圖形。
Sprite類是繼承自Layer的用于存儲多楨的基本可視元素。不同的frame可交相顯示,構成動態的效果。圖片可翻轉、顛倒、由一個主角圖片就可以方便的得到所有方向的顯示狀態,相比原先只能使用Canvas繪圖,需要將所有方向的主角圖象都繪制在png圖象中簡化了許多。Sprite也可以從整合的圖象中讀圖,讀圖時將把大圖分解為若干等寬等高的小圖。每個小圖按照其排列順序有相應的序號,在程序中調用其序號,就可以繪制出相應的圖片。本程序中的雙方飛機、子彈、白云都由Sprite繼承得到。
LayerManager提供控制整體畫面層的控制。它包括了一系列自動獲取了代號和位置的層,簡化了各層加入游戲畫面的過程,提供了自動排序和繪制的能力。
LayerManager存儲了一個層的列表,新的層可以用函數附加、刪除和插入。層的序號相當于坐標的Z軸,0層表示最接近用戶視覺,層數越高,離用戶越遠。層號總是連續的,即使有中間的層被移除,其他層的序號會作相應的調整以保持整體的完整性。LM中的View Window控制著與LM相對坐標的可視區域。改變View Window的位置可以制造出滾動屏幕的效果。
TiledLayer是有一組圖象格元素組成的整塊虛擬圖象。該類使不需要高分辨率的圖象就能創建大幅圖面成為可能。這項技術通常應用在2D游戲平臺的滾動背景的繪圖。一塊整圖可被分割成等大小的圖象格,每塊格有其對應的序號,按照行列遞增。多塊小格可由大塊同時替換組合而模擬動態的背景,這不需要逐塊替換所有的靜態圖象格而顯得非常方便。
3.7 PNG圖片格式
PNG(Portable Network Graphics)格式是MIDlet唯一支持的圖象格式,PNG具體格式由PNG Specification,Version 1.0定義的。PNG格式提供透明背景的圖象,這對繪制游戲畫面和被操縱主角極有幫助。飛機之間或與白云碰撞時就不會因為背景有特定的顏色,顯示出的效果像貼上的圖片而缺乏真實感,物體之間輕微重疊時最上層圖片也不會覆蓋超過其有效象素外的部分。
PNG格式圖片中包含許多定義其圖片特性的冗余部分(Chunks)。這些代碼包含在每一個單獨的png格式圖象中,然而如果將多個png圖象合并在一張幅面稍大一些的整圖中,多個chunks就可以得到精簡,圖片的大小可以得到控制。使用Image類中的createImage函數可從整圖中分割出所需要的元素。在Game包中的TiledLayer和Sprite類都整合了這樣的功能。本程序中的地圖元素都集成在一張beijing.png圖片中,實現了方便的管理和程序體積的精簡。
3.8 玩家飛機的控制方式和敵人方的智能運行
??? GameCanvas提供getKeyStates函數可獲取當前鍵盤上的信息。將以位的形式返回鍵盤上所有鍵的按與釋放的狀態,當bit為1時,按鍵就是被按下的狀態,為0時則為釋放狀態。只需要此一個函數的返回值就可以返回所有鍵的狀態。這保證了快速的按鍵和釋放也會被循環所捕捉。同時,這樣的機制也可檢測到幾個鍵同時按下的狀態,從而提供斜向運行等相應功能(本程序沒有實現斜上運行功能)。
??? 程序運行時應該對玩家飛機是否飛出屏幕的范圍進行檢測,如果飛出屏幕,就應該重新設定玩家飛機的位置。
??? 玩家飛機被擊中后,為了平衡游戲的可玩性,玩家飛機將有短暫時間無敵,即不進行碰撞檢測,同時在屏幕右上角顯示無敵時間。
??? 根據游戲設定,敵人飛機。不能與玩家飛機重合,則他每走一步都需要檢測一下是否與玩家飛機碰撞。Sprite類中提供了collidesWith函數,用于判斷是否與某個Sprite、TiledLayer、Image的對象有圖象上的重合(即游戲中的碰撞)。同理,還需要檢測玩家子彈與敵機、敵機與玩家子彈是否碰撞。如果發生碰撞,將相關精靈圖片替換為爆炸圖片。
敵人飛機需要具有一定的智能性,以便對玩家攻擊,使游戲具有一定的可玩性。敵人可以在適當時候轉向或者開炮火,同時,程序應該檢測敵機是否飛出了界外。
在普通敵機中,有一組敵機的其中一架具有跟蹤功能,其原理為:當其進入屏幕后,根據玩家飛機的X、Y坐標不斷調整自己的X、Y坐標,已達成跟蹤的效果。由于線程的關系,敵機器的改變方向有時并不是實時的,這就可以使玩家有躲開撞擊的可能,增強了游戲的可玩性。
在游戲進行中出現的大型飛機,由于其不可能立即被擊落,所以應該設置其的運行方法,理論上講還是根據玩家飛機的坐標,但是,在此設置一個標志位,使得敵人在取的玩家位置后即開始玩家方向運動,這期間,將不執行取得玩家飛機位置重設飛行方向的步驟。這樣做,即防止了大飛機變成跟蹤飛機,又使得大飛機的運行具有不確定性。
在關尾出現的BOSS,其在屏幕上方左右移動并發射子彈。實際上,此時BOSS應該通過玩家在游戲運行中的習慣性的運行方向,使用遺傳算法,來動態判斷玩家下一步的運行方向,并且指揮普通飛機出現在預測的位置上。可惜由于時間關系沒有實現。
3.9 子彈的運行和控制
??? 玩家的子彈是個精靈數組,有9個元素,表示玩家一次最多可以發射3組9發子彈,對于一個完整的游戲來講,應該根據關卡的不同而給予玩家不同的飛機,飛機性能的差別在于子彈的射程不同。由于本游戲僅有一關,所以子彈速度設定的差別沒有體現出來。
??? 當玩家一次發射了3組子彈,而這3組子彈并沒有消失時,玩家將無法發射子彈。
??? 使用每組子彈的第一發作為與敵人進行碰撞檢測的精靈,同時相關的標志位也設在第一發子彈中。如果玩家子彈與敵機相撞,則敵機消失時,子彈精靈的圖片替換為爆炸圖片,直到第二次發射該組子彈時,才將圖片替換為子彈圖片。
3.10 內存的優化
手機內存空間小,所以在程序設計時應該注意以下幾點,以盡量減少內存的使用:
??? (1)盡量縮短命名的長度。在應用程序內,對于所建立的類、接口、方法及變量名而言,都需要賦予一個識別的名稱,所命名的名稱每多一個字符就會在類文件內多產生一個字節,對于一個較復雜的應用程序而言就會增加為數不小的數據量。所有這些可以借助混淆器來幫助實現
??? (2)所有代碼寫為一個類。
??? (3)只使用一個線程。
??? (4)盡量不使用靜態變量。
??? (5)將PNG圖片合并成一張,減少圖形數據的大小。
將PNG格式的小分辨率圖象合并在一張大的高分辨率圖象中,由于減少了頭文件的大小,將比合并前的總大小減少許多。
3.11 內存檢測器
Wireless Tool Kit提供了許多在運行時監視運行狀態的工具。 包括內存狀況的檢測(手機上的內存空間十分有限,必須時刻關注機載內存是否大于程序所能使用到的最大可能的內存空間),網絡狀況的檢測,運行函數的跟蹤等。內存檢測器是內存跟蹤測試隨時間變化的調試器。其中,允許強制垃圾回收(Garbage Collection)。由于Java語言中,不像許多其他的如C++語言,不需要指定回收函數中特定不使用的資源,資源回收機制將自動清空無效變量占用的空間。在程序運行中也可以調用System類的gc()函數手動收回廢棄的內存。
3.12 關于混淆器
Java 語言并沒有完全編譯成二進制可執行文件,編譯出的.class文件是一種介于源程序和二進制之間的一中基于半解釋的字節碼,需要虛擬機來執行。它包括了所有的信息。然而這樣會導致.class很容易被反編譯為源代碼,從而不能保護作者的知識成果。目前流行的如decode,JAD等反編譯工具可以以很快的速度生成源文件。如果不加以施行有效的措施,將造成嚴重的后果。
由此引入混淆器的概念。混淆器將代碼中的所有變量、函數、類的名稱變為簡短的英文字母代號,如果缺乏相應的函數名指示和程序注釋,即使被反編譯,也將難以閱讀。
??? 混淆器的作用不僅僅是保護代碼,它也有精簡編譯后程序大小的作用。由于以上介紹的減少變量、函數的命名長度的關系,編譯后也會從.class文件中減少這些冗余的信息。混淆后,體積大約能減少25%,這對當前費用較貴的無線網絡傳輸是有一定意義的。
3.13 本章小結
第三章中介紹了程序的流程、相關技術的思想及其在本程序中的應用。對游戲基本算法等做了詳細敘述。具體算法的代碼實現和詳細流程將在下章介紹。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
4? 程序分析和具體實現
4.1 游戲進入前的選擇
每個MIDlet程序都必須有一個主類,該類必須繼承自MIDlet。它控制著整個程序的運行,并且可以通過相應函數從程序描述文件中獲取相關的信息。該類中擁有可以管理程序的創建、開始、暫停(手機中很可能有正在運行程序卻突然來電的情況,這時應進入暫停狀態。)、結束的函數。本程序主類為lzhhdm,并實現接口CommandLIstener。
| 圖4-1游戲背景介紹?????????????????? |
???? 當玩家點擊ok后將調用display.setCurrent(menuscreen)??
以顯示游戲菜單menuscreen(圖4-2)。?
??? 類menuscreen繼承自Canvas類,并實現接口Runnable
和CommandListener。在類menuscreen中定義了lowColor和
highColor、highBGColor三個整型變量及布爾型變量co。其
中lowColor賦值為0x000000FF,代表蘭色,higColor賦值為
0x00FF0000,代表紅色,highBGColor賦值為0x00CCCCCC,代表
| 圖4-2 游戲的菜單 |
(int code)中的整型變量menuIndex相應的減1或加1,相應的,在paint()函數中會根據menuIndex繪制選項是否被選中。在函數run()中,如果co為真,則不停的repaint(),設置co的意義在于,當進入游戲主畫面后,co賦值為false,以終止繪制選項的repaint(),提高游戲速度。???????????????????????????????????? ?????
??? 當移動選項條到某項,并點擊ok時,在commandAction()方法中根據 menuIndex??????????????????????????????????????????????????????????
| 進入游戲 |
| y1>-1550 pzbzover==0 ? |
| 顯示敵人 |
| 玩家被擊落了嗎 ? |
| 玩家是否還有機會? |
| 繼續游戲 |
| 是否過關 |
| 返回主界面 |
| Y |
| Y |
| N |
| ? |
| Y |
| Y |
| N |
| 圖4-4 gameScreen類主要關系流程圖 |
| N |
???????????
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
????
?
???????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
?
??
?
| 圖4-3關于界面 |
?
4.2 mybullets類??
在介紹游戲主類gameScreen類之前,應該先簡要說明一下玩家子彈類mybullets類,實際上,mybullets類是應該刪除的,其要實現的功能應該放在gameScreen類中,但是由于設計游戲的過程也是一個學習的過程,而在當時,我并沒有意識到這一點。???????????????????????????????????????????
???? Mybullets類繼承自Sprite類,以實現玩家子彈的相關功能。首先,創建子彈狀態數組private int[][] bullets,其中,[i][0]代表子彈的X坐標,[i][1]代表子彈的Y坐標,[i][2]代表子彈Y方向速度,[i][3]代表子彈存活狀態(由于此類是在早期設計的,而之后子彈存活狀態使用了子彈射程作為標志位,所以其并沒有起到作用)。類中定義的方法setfirstposition()起到定義玩家子彈發射坐標的作用(此方法在設計時起到的作用是消除每按一次開火玩家子彈位置就重新定位這個BUG,但是,這個BUG完全可以用設置標志位的方法消除)。方法newposition()實現的功能為更新玩家的子彈位置,并且檢測玩家子彈與普通敵人的碰撞及記錄玩家戰果(更新子彈位置的功能可以由使用move()加設置標志位的方法取代;由于設計這個類的時候并沒有考慮到添加BOSS等,所以在此檢測碰撞,但添加BOOS等功能后,此處的檢測完全可以和飛機對飛機等的碰撞檢測封裝在同一個方法中)。
mybullets類在gameScreen中建立了對象數組huokebullet[9],代表玩家所能發射的9發子彈。
4.3 游戲邏輯及gameScreen類
??? gameScreen類是游戲的主類,決定著敵人何時出現,控制著敵人出現的方法,判斷敵人及玩家是否被擊中等。它運行在獨立的線程中,以恒定的頻率刷新畫面。本程序設置為1/20秒。其主邏輯如圖4-4所示。?????
4.3.1 gameScreen類所實現的功能
gameScreen類要實現地圖的滾動、敵人飛機的相關屬性、玩家的相關屬性等功能。
gameScreen類包括了LayerManager,這樣所有靜態和動態的圖象都不需要手動刷新,只需要在LayerManager中加入所有的需要控制的精靈,在統一由LayerManager刷新即可, 因此,在gameScreen中創建LayerManager的對象lm,并在構造函數中實例子化。
其他精靈類的對象如敵人飛機、玩家飛機、玩家飛機的子彈、敵人的子彈、BOSS及BOSS所屬的子彈都需在gameScreen()類中建立相應的對象,并在構造喊數中實例化,且由lm.appned()方法添加到LayerManager類對象lm中。
4.3.2 地圖的創建
?? 由于手機存儲空間的限制,不可能將整張地圖完整地存儲在手機中,為了節約空間,往往提出地圖中相同的圖片組成一張PNG格式的圖片,然后象拼圖一樣拼出地圖來,專業的游戲設計者往往自己寫一個地圖編輯器,以使拼圖過程不是那么痛苦。
創建地圖就需要使用TiledLayer。TiledLayer指的是由一塊一塊類似用瓷磚拼湊起來的畫面。地圖實際即為TiledLayer的一個對象。先利用TiledLayer的構造函數建立TiledLayer,根據構造函數的參數可以給定Cell數組 的大小,并且地圖圖片切割成等尺寸的畫面,并調用setCell()設置具體的圖象格內容。地圖
| 圖4-5 地圖 |
??? 因此,創建一個返回TtiledLayer的方法createBackGround(),以便在gameScreen()的構造函數中調用。在方法中,定義整型數組map1[]以存儲Cell的索引值。并使用tiledLayer.setCell(column,row,map1[i])設定TtiledLayer的內容,以形成地圖。其中i的值由循環for(int i=0;i<map1.length;i++)取得,column由語句column=i%15取得、行由row=(i-column)/15取得。
??? 畫出地圖后,由lm.append()將地圖添加到LayerManager類對象lm中。由于地圖位于Layer的最低層,即離用戶視線最遠的層,所以Tiledlayer最后一個被添加到lm中。
4.3.3地圖的移動??
?? ?根據游戲的設定,游戲中地圖是向下移動的,實現此功能的方法如下:
??? 首先,在使用createBackGround()函數創建地圖數組時,用(row+1)*16-getHeight()??????????????????????????? ????????????????????????
語句對整型變量row2賦值,其中row+1代表地圖有多少列,16為地圖片的高度,而減去getHeight()是因為要留出一個屏幕的可視區域,由于J2ME規定坐標系中下方向為正,所以使用語句y1=-row2將row2的數值變為負數。
| ?????? ? (0,y1) ?????????????????? ??????y1=y1+1; ?????????????????? View Window???????????? ??????????????????? 向下移動?????????????? ? (0,0)??? ??????????????????????????????????????????????????????????????????????? ? ???????? 圖4-6? ????????? ??? ????????圖4-6? ? ?????????????????????? ????????????????????????????????????????????? |
使用lm.paint(g,0,y1)決定
View? Window從屏幕的哪里畫起。
在run()函數中的while(conti)中,
| 屏幕 |
地圖下移1個象素。(參考圖4-6)
4.3.4 gameScreen類的構造函數
gameScreen類的構造函數要將游戲中出現的所有精靈都實例化,實際上,這種方法
嚴重的占用了內存,但在當時,我并沒有意識到這一點。
由于敵人要求不停的出現,但是不可能設置過多的精靈,解決的辦法是設定6個Sprite類對象j0、j1、j2及jbullet1、jbullet1、jbullet2,分別代表三架敵機及其配屬的子彈。所以在gameScreen類的構造函數分配這6個Sprite類的存儲空間,并且使用new Sprite(Image img, int width,int height)實例化這6個類變量。同關尾cboss與游戲進行中的大飛機其他的Sprite類對象都需要使用相同的方法實例化。同樣處于節約內存的考慮,sboss與cboss同用3個Sprite類對象bossbullet0,1,2。
??? 在構造函數中,定義boolean型變量conti=true。conti的作用在于控制是否進行游戲畫面的重繪及其他需要在畫面重繪前進行的運算。
??? 在構造函數中,將mybullets類里的no和score初始化,現在看來no的初始化沒有必要,但是score的初始化是必須的,因為這個變量存儲著玩家每次游戲的成績,如果不在此進行初始化,則玩家重新開始游戲后score并不歸0。
4.3.5 關于commandAction()方法
每個創建Command實例的J2ME的應用程序也必須創建實現CommandListener接口的實例。每當用戶通過commandAction()方法的方式與命令進行交互的時候,就會通過CommandLIstener.所以實現CommandListener的類必須實現commandAction()方法。
在commandAction()方法中,使用getabel()方法獲取命令的標簽。如果getLabel()=“暫停”時,表示玩家點擊了暫停鍵,此時,conti賦值為false,游戲畫面的繪制及游戲相關的運算暫停,并且,使用removeCommand(c)語句將“暫停”移除,使用addCommand(new Command("繼續",Command.OK,2));將”繼續“按紐”添加進來。當玩家點擊“繼續“時,conti賦值為true,并且,一定要調用start()方法,否則繼續功能不可用。必須調用start()方法的原因是:J2ME的線程已stop()方法拿掉,如果想停止線程的運做,就必須依靠一個旗標(flag),在本程序中,flag就是boolean型變量conti。所以一旦此標識變量被設為false,那么while(conti)循環就會結束,線程也會跟著結束。當用戶按下“繼續”的時候,start()將重新產生一個線程繼續執行相關的運算和畫面繪制。
當玩家通關時或者任務失敗時,將顯示相應信息,并使用上面的方法將“暫停”鍵變為“返回”鍵盤,當點擊“返回”鍵時,將返回主菜單選項,調用類lzhhdm里的方法menuscreensecond(),在此方法中,實例化一個MenuScreen類對象,并且使選項“新游戲”改變為”重新開始“(圖4-7)。完成此項功能的語句子為MenuScreen.mainmenu[0]=”重新開始”。當選擇”重新開始“時,使用gamescreen=new gameScreen(this)將使所有變量重新被初始化,如地圖的繪制、敵人出現位置的重置、敵人的數量、玩家飛機的當前位置等。使用gamescreen.start()重新開始程序的循環。
4.3.6 Sprite類對象的碰撞檢測及相關屬性
??? 游戲進行中,即在while(conti){ }中,需要進行玩家飛
機、子彈與敵機及敵機子彈與玩家飛機的碰撞檢測,即使用函
數collidesWith(Sprite,boolean)。由于設計的問題,玩家發
射的子彈與普通敵機的碰撞檢測被寫在了mybullets類中,并
且只檢測第一發子彈是否與敵人相碰撞,如果碰撞為真時,則
使用setVisible(false)函數將敵機隱藏,使用setImage()函
數將子彈精靈的三張圖片置換為爆炸圖片( 圖4-8 )。當敵人剩
| 圖4-7 |
setVisible(true)將敵機重新設置為可見。在按“開火”鍵時,使用setImage()函數將huokebullets重新設定為子彈圖片(每次擊落敵機后屏幕上的爆炸效果有3團,并且按“開火”后爆炸圖片就消失了,實際上setVisavle(false)的應該是子彈數組,而對敵人精靈使用setImage(),這樣效果會好一些)。
敵機與玩家的碰撞檢測原理同上,都是使用的collidesWith()函數,遺憾的是,我在寫這段代碼的時候,并沒有考慮設置玩家有4次機會,所以對敵人飛機setVisable(fasle)了,而將玩家的飛機換成了爆炸圖片,之后,添加了玩家4次機會這個功能,由于玩家被擊落后會重新從屏幕下方進入屏幕,所以爆炸的圖片一閃而過,效果不是很好。
4.3.7 玩家4次游戲機會的實現方法????????
?? ?根據游戲設置,玩家在每關中有共四次機會,當玩家飛機被擊中或撞擊爆炸后,程序首先檢測整型變量playerno的值,并根據playerno的值決定屏幕右上角所畫玩家飛機標志的數量(參考圖4-8),playerno的初始值設為3,因為碰撞后才減1,所以玩家共有4次機會,當playerno<0時,游戲結束,同時將變量pver賦值為1,render()或renderboss()函數中,over=1代表在屏幕上GAMEOVER等相關信息,同時,將整型變量inputno賦植為1,以使手機的方向鍵失效,以消除玩家可以控制爆炸圖像移動這個BUG。同時整型變量pzbz賦植為1,以消除玩家爆炸圖像繼續與敵人進行碰撞檢測這個BUG。
??? 當playerno>0時,碰撞后,將變量planert賦值為1,在之后的if(planert==1)判斷語句中,重新設定玩家飛機的圖片和可視狀態,同時使用setPosition()函數設定玩家非的位置在屏幕下方。設定pzbz=1,即不檢測碰撞,玩家有短暫時間無敵,無敵時間由屏幕右上角進度條表示。設定inputno=1,即飛入屏幕的過程中手機鍵盤是不可以用的。設置planert=2,即以上這些設置只執行一便。
???? 在if(planert==2)判斷語句中,使用語句move(
0,-2)使飛機自己向上運動,使用if(c1.getY()<(
planepo-24))判斷飛機是否到達屏幕最下方(planepo
是屏幕下邊緣的坐標),如條件為真,則將inputno
設置為1,表示鍵盤可用,將planert賦值為3,使
其不再執行以上各步。
4.3.8 input()
?input()函數的作用是檢測用戶的輸入。
首先使用if(inputno==0)判斷用戶的輸入是否
被禁止,如為真,則用戶輸入不被禁止。
| 圖4-8 游戲界面 |
當玩家按方向鍵時,玩家飛機就向不同的方向運行,這需要使用c1.move(int x,int y)函數,當玩家控制飛機向左或右飛時,需要使c1.setFrame()函數改變飛機的圖形(參見圖4-7,此時飛機右飛)。同時,還需要判斷飛機是否飛出屏幕,如,當飛機右飛時,用if(c1.getX()>(getWidth()-c1.getWidth()))
語句判斷(getWith()為屏幕的寬度,c1.getWidth()為玩家飛機c1的寬度),如果條件為真,則使用c1.setPosition((getWidth()-c1.getWidth()),c1.getY())語句將飛機設置在緊靠屏幕右邊的位置。上、下、左的設置原理同上。
??? 語句if((keystate&LEFT_PRESSED)==0)的作用是消除左、右飛后在上、下飛時飛機的形態不變的BUG。如果為真,則執行語句c1.setFrame(0),表示只要左鍵松開飛機的形態都是平飛。
根據游戲設定,玩家一次最多只能發三組子彈,并且子彈有射程限制(在類mybullets中使用整型變量no表示),而當玩家按下“開火“鍵時,即if((keystate&FIRE_PRESSED)!=0)中判斷條件為真時,首先執行循環語句for(int i=0;i<=6;i=i+3),即檢測3組子彈中每組的第一發,即0,3,6。其次,檢測huokebullet[i].no是否等于1,當等于1時使用語句for( int z=i;z<i+3;z++)初始化該組子彈中的3發子彈,而設置子彈位置的函數應該在if(huokebullet[i].no==1)語句外設置,因為當初設計的時候mybullets類里的函數寫成了一次設置三組子彈的形式。
huokebullet[z].no=huokebullet[z].bulletheight賦予子彈射程。當程序循環運行時no--,當一次發射了三組子彈后,只有某一組子彈消失,即no等于1后才能繼續發射子彈。
現在看來,玩家發射子彈的設置是完全失敗的,降低了效率。
4.3.9 render()和renderboss()
在方法render()過程中,除了要重繪飛機、地圖、子彈外還要在上方繪制關卡信息、戰果、玩家飛機數、及無敵狀態時的無敵時間、大飛機生命條等。
首先使用lm.setViewWindow()和lm.paint()設定可視范圍ViewWindow和從哪里畫起(見4.3.3)。
其次,使用g.drawString()繪制屏幕上方的關卡信息、戰績、玩家剩余生命標志。
drawString()中使用String.valueOf(huokebullet[0].rscore()+huokebullet[3].
rscore()+huokebullet[6].rscore())返回玩家成績score的字符串表示。
其中根據playerno的值繪出玩家的飛機標志數(應該有更好方法,但是沒有想到 )當每次刷新繪圖頁面時,應使用GameCanvas的flushGraphics()將屏幕后臺的緩沖區內的圖像刷新到前臺來(flushGraphics()應該寫在render(){ }的最后)。
renderboss()方法重繪的是關尾的精靈cboss、相關信息等,與render()的區別在與于函數lm.paint(g,0,0),起始坐標是不可變的,即,關尾的地圖背景是不可變的。實際上,renderboss()是完全不需要的,只要在render()函數中設置相關標志位就可以解決關尾的繪圖問題。
玩家飛機的生命標志使用drawImage()就可以繪制在屏幕上了。
4.4 游戲中的獎勵及相關飛機的行為
? ??根據游戲設定,當y1=-1000時,會出現如圖4-8
所示的飛機(sboss),當玩家擊落他后,屏幕會顯示“
援軍到達“,并且玩家剩余飛機數加1。
??? 使用 if((y1==-1000)&&(sbz==0)){ }設定sboss的
初始位置,根據游戲設定,sboos從屏幕上方倒飛入屏幕,
所以sboss設定的初始位置(50,planepoup-65),其中
planepoup為屏幕上邊緣的標志位。
| 圖4-9 |
??? 當sboss飛入屏幕后,將sbz賦值為2,以執行下面
的if(sbz==2)語句。
| 圖4-10 |
行。首先,根據玩家飛機的位置對sbmove賦值,當c1在sboos的上、下、左、右時,其對應的值為1、2、3、4在這4個if語句中,要設置標志位(smovebz==0)。設置這個
標志位的目的是防止sboos根據c1的位置不停的改變運行狀態,即防止sboos成為跟蹤飛機。當sboos根據c1的位置改變一次運行方向后,smovebz賦值為1,即不檢測c1
的位置。只有sboss運行到屏幕的邊緣時,才將smovebz重新賦值為0,使其可以再次通過c1的位置決定sboos的運行方向。
當玩家子彈擊中sboss后,使用sboss.setFrame(1),此時飛機變紅,在本次repaint結束前,使用sboss.setFrame(0)使飛機變為本來顏色,而程序設定每1/20秒畫一次,由此得到飛機被擊中后變色的效果。(參見圖4-10)。
??? sboos會根據玩家飛機的位置發射子彈,根據游戲設置,當玩家在其上方、左方、右方時,sboss一次發射1發子彈,而玩家飛機在其下方時,sboss一次發射3發子彈。????????????????????????
??? sboss與cboss共用3發子彈,因為當sboss出現時,離關尾還遠,所以,為了提高效率,采用這種方法。
??? 如果sboos被擊落后,使用函數setVisable(false)將bossbullet0、bossbullet1、bossbullet2設置為不見,使用sboss.setImage()函數將sboos的圖片設置為爆炸圖片。同時,玩家生命標志playerno加1,sbz賦值為-1,使得sboos無法發射子彈,sbpzbz賦值為1,使得玩家的子彈不與sboos進行碰撞檢測。
??? 同時在屏幕中使用drawString()繪制“援軍到達”四個字,隨著屏幕的運動,爆炸圖片逐漸進入屏幕下方,當sboos.getY()>palnepo,通過改變標志位的值使得drawSteing()不在執行,四字消失。
??? 如果玩家被擊落后并沒有點“返回“,而此時,背景會一直運動到關尾,考慮到其與關尾BOSS共用3發子彈,如sboos不消失,將會出現子彈亂飛的情況。所以,如果判斷語句if((sboss.getY()==getHeight()))為真,則表示離地圖的終點只有一個屏幕的距離時,sbz賦值為-1、sbpzbz賦值為1(含義上面已經說明)。同時調用sboss.move(0,-3),使sboos快速飛出屏幕,直到判斷語句if(sboss.getY()<-65)為真時,調用下面的函數setVisable(false),使得sboos不可見。
4.5 普通敵人相關屬性
?? ?普通敵人是指游戲中不斷出現的蘭色飛機。
??? 首先在程序中首先定義了aik、aip兩個Random()類對象,ai和aipp兩個整型變量。程序中使用switch(ai)語句判斷下一次的飛機出現情況,為了達到不重復出現的效果,使用語句ai=aik.nextInt()%4(同樣應該在構造函數中放置此語句和aipp=aip.nextInt() % 5,以使每次游戲開始的時候敵人飛機的出現順序是不固定的),以隨機出現0,1,2,3四個整數(代表著飛機的四種出現情況)。
? ??情況1:使用 aipp=aip.nextInt()%5取得隨機數aipp,根據下面三條語句設置飛機的出現位置:j0.setPosition(100-aipp*30,planepoup+24);
?? ???????j1.setPosition(100,planepoup);
?? ???????j2.setPosition(100+aipp*30,planepoup-24);;
將getHeight()/8賦給整型變量kkk,每次循環kkk-1,當kkk<=1時飛機轉向,當aipp>0時,飛機向左下方運行,使用語句setFrame(0)、move(-3,3)達成向左下方運動的效果。當aipp<0時,向右下方運動,實現方法同上。
??? 情況2:初始位置設置方法同情況1。當kkk〈0時,飛機掉頭向上飛,其中setFrame(3),
move(-4,0)。
??? 情況3:初始位置設置方法同情況1。當kkk〈0時,飛機只向左轉。設置情況3的原因是在更多的隨機位置出現敵機。
??? 情況4:初始位置設置方法同情況1。但其中的飛機j1具有跟蹤能力,其實現方法如下:使用2個if語句if(j1.getX()<c1.getX())、if(j1.getX()>c1.getX())判斷J1在c1的左或右側,并且實時根據判斷情況使用setFrame()和move()改變飛機的形態,使用語句
if((j1.getX()<c1.getX())&&((j1.getX()+48)>c1.getX())&&(j1.getY()<c1.getY()))判斷c1是否在j1的下方,當c1在j1的下方時,發射子彈jbullet1。
???? 以上四種情況的最后,都將使用函數nextInt()產生ai,aipp的值。
???? 設置整型數組jb[4],對應著4種出現情況的標志位。
???? 如,執行情況1,首先執行判斷語句if(jb[0]==1),在此語句中,首先使用setVisable (true)函數將敵人飛機設置為可見的,并根據上次運行的qipp的值設置敵人飛機的初始位置最后,jb[0]賦值為2。
??? 接著執行判斷語句if(jb[0]==2),在此語句中,首先使用move()函數使飛機向下運動,同時kkk減1,當kkk<=0時,飛機轉向,此時,根據aipp的正負判斷飛機向哪邊轉向。當飛機飛出屏幕時,jb[0]賦值為3。
??? 需要注意的一點是,當取得ai的數值時,一定要寫上這條語句:jb[ai]=1;因為當4種情況都出現一便的時候,標志位jb[]里的數值都將變為3,如果不將其重新賦值為1,敵人飛機將只能出現4次。
??? 其他3種情況也大致如此。
??? 普通敵人是否發射子彈由以下語句if(((j1.getX()<=c1.getX()-18)||((j2.getX() -6)>=c1.getX()))&(jbz==0)),即c1在j1左側18象素范圍內或j2左側6象素范圍時,j0、j1、j2一起發射子彈,jbz=1,表示在這組子彈消失前敵人不發射子彈。
?? ?如果jpb的值為0,則判斷語句if(jpb==0)里的move()語句將一直執行下去。
??? 之后,還需要對每發子彈于玩家飛機進行碰撞檢測,如果碰撞,則將碰撞的這發子彈設置為不可見。
4.6 白云的實現原理
???為了游戲界面更加美觀,程序中設定了精靈數組cloud[i]來表示白云,由于白云應該在所有飛機的上方,即cloud[i]應該最早被append()到LayerManager中,或者使用insert (cloud[],0)在索引數值0處插入Layer,本程序采用了第一種方法,即在gameScreen類的構造函數中按游戲設置的順序使用lm.append()加入到LayerManager之中。
??? 程序中設定白云數為5。首先設置白云的初始位置,其語句如下:
cloud[0].setPosition(25,planepoup-(65));
cloud[1].setPosition(80,planepoup-(140));
cloud[2].setPosition(112,planepoup-(90));
cloud[3].setPosition(175,planepoup-(200));
cloud[4].setPosition(223,planepoup-(70));
其原理為:將屏幕的X數軸和Y數軸各分成5份,即在X軸的5個范圍內每個范圍出現一朵白云,Y軸的每個范圍內也只能出現一朵。所以的白云的起始位置在每次游戲開始時是固定的。
白云位置設定后,使用move(0,1)使白云移動,由于白云初始位置設定在屏幕的不同區域內,故其移動出屏幕的先后順序是不同的,使用if(cloud[].getY()>planepo)判斷白云是否飛出屏幕。如果為真則使用cloud[].setPosition(cloudposition*40,planepoup)設置白云的位置,其中,cloudposition=aicloud.nextInt()%5,aicloud為Random()類對象。乘以40表示其在X軸出現的范圍是多少,cloud[0]、cloud[1]、cloud[2]、cloud[3]、 cloud[4]乘以的值分別為40,30、55、15、22。以達成白云的隨機出現效果。
4.7 關尾BOSS及相關屬性
??? 關尾處飛機在屏幕上方橫向移動,而背景地圖不動,所以使用renderboss()重繪屏幕,其中,paint(g,0,0)表示屏幕繪制點在坐標軸(0,0)處。BOSS生命進度條由以下語句繪制:
g.setColor(255,0,0);
?????????? ???????? g.fillRect(2,2,60,5);//生命進度條背靜紅
?????????? ???????? g.setColor(255,255,255);
?????????? ???????? g.fillRect(2,2,bosslife,5);//生命進度條前景白
其中bosslife記錄著BOSS的生命值,其初始值為0,當玩家每擊中一次BOSS,其值加5,,即化出白色進度條,當bosslife==60時,表示過關,除玩家飛機與子彈外的其他Sprite均使用setVisable(false)使其不在顯示,同樣的pzbz要賦予1,以消除玩家飛機還能與敵人碰撞的BUG。
??? 如果cboss.getX()<0,則表示其在屏幕左方出界,應改為右飛。同理如果cboss.getX()
>(getWidth()-cboss.getWidth()),則表示其在屏幕右方出界,應改為左飛。
在飛機橫向飛行中,使用以下語句判斷飛機是否開火:
if(((cboss.getX()<=c1.getX()-10)||(cboss.getX()<=c1.getX()+60))&&(jbsz==0))
當每發一組子彈后,jbsz=1,則飛機無法開火,知道子彈
飛出屏幕,jbsz才重新設定為0。而((cboss.getX()<=
c1.getX()-10)||(cboss.getX()<=c1.getX()+60)表示當
玩家飛機處于BOSS的左右各10個象素的范圍內時。BOSS
開火。關尾參見圖4-10。
4.8本章小結
第四章中按照相應的步驟描述了所有關鍵類的具體算
| 圖4-10關尾 |
理稍復雜的函數做了詳細的分析。對游戲有關的各運行面也做了展示。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
5? 測試
5.1 打包測試的過程
?? ?使用Eclipse完成代碼的調試之后,需要使用WTK生成包(即jar和jad文件),其過程如下:首先,使用WTK的新建項目功能建立一個新項目,要求與Eclipse工作區下的項目名稱、MIDlet類名相同(圖5-1)。
圖5-1
?? 新建項目后,將Eclipse工作區下的.java文件拷入src文件夾,將.class文件拷入class文件夾(需要新建),將pic文件夾拷入res文件夾,點擊生成,如一切正常,將如圖片5-2所示。
圖5-2
之后,選擇項目-包-生成包。如圖5-3所示。
圖5-3
生成的jar和jad文件存儲在lzhhdm/bin目錄下。
運行Motorola SDK v4.2 for J2ME,使用MOTOA760手機模擬器進行測試。參考圖5-4。點擊Lanuch按紐,進入如圖5-5的界面,即可以進行游戲測試了。
圖5-4
? ?測試的過程,實際上就是找不同的同學玩這款游戲,以期望發現BUG。實際上,幾乎每一版本都會產生很多BUG。?????????
5.2 發現的BUG及解決情況????
幾乎每一個計算機程序都會有這樣
那樣的不足,尤其是未經過精心維護的
非商業軟件。即使是作為操作系統的各
種版本的Windows也時常會發生許多類
型的錯誤和漏洞。本游戲程序對于初涉
此領域的畢業設計課題來說,尤其在開
始初期,感覺邏輯復雜,難以控制,因
此產生了大量BUG,其中一些BUG還沒有
解決,所有發現的BUG如下:
1.玩家子彈出現順序問題;
2.玩家飛機爆炸后仍然可以控制爆
炸圖片;?????????
3.當過關后仍然會發生碰撞;
| 圖5-5 |
家被擊落,并且此為玩家的最后
一架飛機,雖然顯示援軍到達,但
| 圖5-5 |
5.有某組飛機在飛機被擊中后仍能發射子彈;
6.sboos左側子彈發射后不停在原位置刷新問題;
7.? 游戲運行一段時間后變的很卡;
??? 其中,1、2、3、4條BUG已經解決(方法已在第4章相關位置進行了說明)。4、5、6沒有解決,其中,4、5、6三條如果有足夠的時間可以解決。第7條以現有水平無法解決,因為出現這種情況的原因估計是內存的問題,而由于水平的關系,現在的代碼變量過多,并且效率低下,有很多重復的地方,解決的方法只能是在水平提高的情況下重寫整個程序。
5.3 未完善的功能
經過匯總測試人員的建議,本游戲應該完善的功能如下
1. 由于每按一次開火,就會對玩家子彈的精靈數組進行一次循環檢查,使得本運行效率就不高的KVM運行異常緩慢。即使刷屏沒有間隔也不會提高速度;
??? 2. 最好有接寶物的設置,增強可玩性;
??? 3. 由于沒由合適的圖片,使得敵人設置單一;
??? 4. 地圖本應由外部文件讀入,但設計初期并沒有掌握這項技術;
??? 5. 手機游戲最好只有一個類,而我卻有4個;
??? 7. 沒有添加成績記錄,即英雄榜;
??? 6. 最大的遺憾,敵人不夠智能化。
??? 希望不遠的將來,我能夠有能力對這個游戲進行重寫,以解決BUG、完善功能。
???
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
6? 總結
6.1 本程序的總結和展望
?? ??本程序設計實現了手機上以J2ME為平臺的飛行射擊游戲的開發,敵人運行的方式由程序進行控制,具有一定的可玩性和復雜性。經過了細心的調試和排錯解決了絕大部分的問題。
?但是我的水平實在有限,在第5章列舉的眾多BUG和遺憾就可以看出這一點來,但我相信,隨著時間的推移,個人水平的增長,我一定會重寫這個程序,使其更加完善,
6.2 感想
?? 這款游戲作為我的畢業設計,是本人目前做過的最有意義的程序,這期間對J2ME的學習,使我又回到了初學PASCAL的時候。
本科期間做過很多課程設計,大多規模很小。在數據庫、各種應用軟件和游戲中,我仍覺得對游戲的設計有極大的熱情。因為其各個模塊間的聯系十分緊密,代碼重復執行率高,當經過無數次的調試、修改后,能最終看到成品,有無比自豪的心情。大學期間做過圖書館管理程序等簡單的數據庫管理系統的課程設計,思想大致相似,變化范圍有限,沒有太多自己可發揮的余地。大家作品的最終結果都離不開同一個模式。相比一些數據庫軟件,游戲的設計有很多人情色彩和藝術思想的發揮,正式商業的軟件的人性化界面和各個游戲間迥異的結構每每會讓人有去開發的沖動。
??? 學習J2ME的困難遠遠超出了想象,在設計初期,為了解決地圖的滾動、玩家飛機如何不飛出上下邊界兩個問題竟然花費了數天的時間。很多相關的技術,如需要使用到的線程、Game包的新功能、高級、低級圖形界面的使用、貼圖等,每一項都需要花一定的時間去掌握和熟悉。更為困難的是,J2ME為一種剛出現僅幾年的新技術,國內的參考資料非常少,僅有的幾本也停留在簡單的介紹階段。臺灣的王森寫了本較好的書,給了我很大的幫助,但對設計該游戲來說,仍只夠入門。
???? 幸運的是,互聯網上有那么多無私的人,由Jason Lam著,Deaboway Chou譯的電子書《J2ME&Gaming》給了我很大的幫助,作者、譯者的辛勤勞動的成果免費放在網上由大家下載,是開源精神的完美體現。
?
致??? 謝
首先感謝我的指導老師馬慧彬副教授,她在我的畢業設計過程中提出了指導性的方案和架構,并指引我閱讀相關的資料和書籍,使我在不熟悉的領域中仍能迅速掌握新興的技術。
感謝黃明旭、包明輝同學對游戲進行測試,感謝包明輝同學對游戲相關圖片的修改。
感謝答辯組對本畢業設計的考核,如果可以得到專家的認可將對我的學習和工作給予極大的鼓勵。你們客觀的評價和建議我將牢記在心,在今后的發展中揚長避短,更加努力的嚴格要求自己。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
參考文獻
[1]Joshua Bloce著. 潘愛民譯. Effective Java中文版.2004年7月第4版. 機械工業出版社.
[2]Bruce Eckel.侯捷譯.Java編程思想. 2005年3月第1版. 機械工業出版社出版社
[3]王森著.Java手機/PDA程序設計入門.2005年2月第3版.電子工業出版社.
[4]James Keogh著.潘穎王磊譯.J2ME開發大全.2004年2月第1版清華大學出版社.
[5]Ian Sommerville著.程成等譯.軟件工程.2003年1月第1版.機械工業出版社.
[6]Jason Lam著.Deabo way Chou譯 J2ME&Gaming 2004年末 www.jasonlanm604.com
[7]陳立偉 張克非 黎秀紅著.精通JAVA手機游戲與應用程序設計.中國青年出版社.
2005年5月
[8]飛思科技產品研發中心.精通Jbuilder9.電子工業出版社.2004年
[9]微型爪哇人.Java手機程序開發.中國鐵道出版社,2003年
[10]Frand M.Carrano,Janet J.Prichard?.著?韓志宏?譯.數據抽象和問題求解——
JAVA語言描述.清華大學出版社2005年4月
[11]袁海燕 王文濤著.JAVA實用程序設計100例.人民郵電出版社.2005年5月
[12]Jonathan Knudsen.What's New in the J2ME Wireless Toolkit 2. 22004年4月www.sun.com
?
?
?
?
?
?
?
?
?
?
?
?
?
附錄一? 代碼
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.lcdui.*;
public class lzhhdm extends MIDlet implements CommandListener {
??????? public Display display;
?????? private Image splashLogo;
?????? private boolean isSplash=true;
??????? public Form a;
??????? private Alert alert;
??????? int length;
??????? private MenuScreen menuscreen;
??????? private gameScreen gamescreen;
??????? private Command ok,back;
??????? private byte[] byteInputData;
?????? public lzhhdm()
?????? {
?????? }
?????? protected void startApp() throws MIDletStateChangeException {
?????? display=Display.getDisplay(this);
?????? menuscreen=new MenuScreen(this);
?????? if(isSplash)
?????? {? a=null;
????????????? a=new Form("覽橋風光V1.0");
????????????? ok=new Command("ok",Command.OK,1);
?????? ??? a.append(new StringItem(null,"....."));
????????????? a.addCommand(ok);
????????????? a.setCommandListener(this);
?????? ??? display.setCurrent(a);?
?????? }
?????? }
?????? protected void menuscreenShow()
?????? {
????????????? display.setCurrent(menuscreen);
?????? }
?????? protected void menuscreensecond() {
?????????????
????????????? menuscreen=new MenuScreen(this);
????????????? MenuScreen.mainmenu[0]="重新開始";//玩完一遍或掛了后在玩一遍 菜單第一項改為 重新開始
????????????? display.setCurrent(menuscreen);
????????????? }
?????? protected void pauseApp() {}
?????? protected void destroyApp(boolean arg0) throws MIDletStateChangeException {??
?????? }
?????? protected void helShow()
?????? {? a=null;
????????????? a=new Form("覽橋風光V1.0");
????????????? back=new Command("返回",Command.BACK,1);
?????? ??? a.append(new StringItem(null,"操作方式:上 2 下 8 左 4 右 6 開火 5"));
?????? ??? a.append(new StringItem(null,"彈藥數:一次最多打三組"));
????????????? a.addCommand(ok);
????????????? a.setCommandListener(this);
?????? ??? display.setCurrent(a);
?????? }
?????? protected void renwuShow()
?????? {
????????????? a=null;???
????????????? a=new Form("覽橋風光V1.0");
????????????? back=new Command("返回",Command.BACK,1);
?????? ??? a.append(new StringItem(null,"游戲名稱:覽橋風光"));
?????? ??? a.append(new StringItem(null,"版本號:V1.00"));
?????? ??? a.append(new StringItem(null,"制作者:信息電子技術學院01計算機5班 劉澤華 學號:7"));
????????????? a.addCommand(ok);
????????????? a.setCommandListener(this);
?????? ??? display.setCurrent(a);
?????? }
?????? protected void gameShow()
?????? {?? try{
??????
????????????? gamescreen=null;
????????????? gamescreen=new gameScreen(this);
?????????????
????????????? gamescreen.start();
???????????????????? display.setCurrent(gamescreen);
????????????? gamescreen.conti=true;
?????? }catch(Exception exp)
?????? {
?????? System.out.println("dfg");
?????? }
?????? }
??????
?????? public void commandAction(Command arg0, Displayable arg1) {
????????????? a=null;
?????????????
????????????? this.menuscreenShow();
?????? }
}
import javax.microedition.lcdui.*;
public class MenuScreen extends Canvas? implements Runnable,CommandListener
{
?Font lowfont=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font.SIZE_MEDIUM);
?????? ? Font highfont=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_BOLD,Font.SIZE_MEDIUM);
?????? ?int lowColor=0x000000FF;
?????? ?int highColor=0x00FF0000;
?????? ?int highBGColor=0x00CCCCCC;
?????? ?int width;
?????? ?boolean co;
?????? ?int height;
?????? ?int startHeight;
?????? ?int spacing=highfont.getHeight()/2;
?????? public? static String[] mainmenu={"D?ó??·","°??ú","1?óú"};
?????? ?int menuIndex;
?????? Thread menuThread;
?????? private Command ok=new Command("ok",Command.OK,1);
?????? private lzhhdm midlet;
?????? public MenuScreen(lzhhdm midlet)
?????? {???? this.midlet=midlet;
????????????? width=getWidth();
????????????? height=getHeight();
????????????? startHeight=(highfont.getHeight()*mainmenu.length)+((mainmenu.length-1)*spacing);
????????????? startHeight=(height-startHeight)/2;
????????????? menuIndex=0;
????????????? addCommand(ok);
????????????? ?setCommandListener(this);??????
????????????? menuThread =new Thread(this);
????????????? menuThread.start();
????????????? co=true;
?????? }
??????
?????? public void run()
?????? {
????????????? while(co)
????????????? {
???????????????????? repaint();
????????????? }
?????? }
??????
?????? public void paint(Graphics g)
?????? {?
????????????? g.setColor(0x00FFFFFF);
????????????? g.fillRect(0,0,width,height);
????????????? for(int i=0;i<mainmenu.length;i++)
????????????? {
???????????????????? if(i==menuIndex)
???????????????????? {?
??????????????????????????? g.setColor(highBGColor);
??????????????????????????? g.fillRect(0,startHeight+(i*highfont.getHeight())+spacing,width,highfont.getHeight());
??????????????????????????? g.setFont(highfont);
??????????????????????????? g.setColor(highColor);?????? g.drawString(mainmenu[i],(width-highfont.stringWidth(mainmenu[i]))/2,startHeight+(i*highfont.getHeight())+spacing,20);
???????????????????? }else
???????????????????? {
??????????????????????????? g.setFont(lowfont);
??????????????????????????? g.setColor(lowColor);
???????????????????? ?????? g.drawString(mainmenu[i],(width-lowfont.stringWidth(mainmenu[i]))/2,startHeight+(i*highfont.getHeight())+spacing,20);
???????????????????? }
????????????? }
?????? }
?????? public void keyPressed(int code)
?????? {
????????????? if(getGameAction(code)==Canvas.UP&&menuIndex-1>=0)
????????????? {
???????????????????? menuIndex--;
????????????? }
????????????? else if(getGameAction(code)==Canvas.DOWN&&menuIndex+1<mainmenu.length)
????????????? {
????????????? ?????? menuIndex++;
????????????? }
?????? }
?????? public void commandAction(Command c,Displayable d)
?????? {
????????????? if (c==ok)
????????????? {
???????????????????? switch(menuIndex)
???????????????????? {
???????????????????? ? case 0:
???????????????????? ? ?? ?co=false;
???????????????????? ? ?? midlet.gameShow();
???????????????????? ? ?? break;
?????????? ? case 1:
?????????? ? ? midlet.helShow();
?????????? ? ? break;
?????????? ? case 2:
?????????? ? ? midlet.renwuShow();
?????????? ? ? break;
?????????? }??
?????? }
??? }
}
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
public class mybullets extends Sprite
{?? public? int score=0;
?????? private int[][] bullets;
?????? private int bulletstotal;
??? public int width,bulletheight;
? ?? public int no=0;
?????? public mybullets(Image img,int picwidth,int picheight,int bulletstotal,int width,int height)
?????? {??????
???????????????????? super(img,picwidth,picheight);
???????????????????? this.bulletstotal=bulletstotal;
???????????????????? bullets=new int[bulletstotal][4];
???????????????????? this.width=width;
???????????????????? this.bulletheight=height/7;???
?????? }
??? public void initBullets(int i)
??? {
??? ???????????? bullets[i][3]=1;
??? ???????????? bullets[i][2]=0;
??? }
??? public void updata(int i)
??? {
??? ????? bullets[i][1]+=bullets[i][2];
??? }
??? public void setfirstposition(int x,int y,int nof,Sprite sprite[],Image img)
??? {?? ???
??? ????? sprite[nof].setVisible(true);
??????? sprite[nof+1].setVisible(true);
??????? sprite[nof+2].setVisible(true);
??? ????? bullets[nof][0]=x+10;
??????? bullets[nof][1]=y-24;
??????? sprite[nof].setImage(img,6,6);
??????? bullets[nof+1][1]=bullets[nof][1]+10;
??????? bullets[nof+1 ][0]=x+10;
??????? sprite[nof+1].setImage(img,6,6);
??????? bullets[nof+2][1]=bullets[nof+1][1]+10;
??????? bullets[nof+2 ][0]=x+10;
??????? sprite[nof+2].setImage(img,6,6);
??? }
??? public void newposition(Sprite sprite[],int i,int v,Sprite jp0,Sprite jp1,Sprite jp2,Sprite boss,Image img)
??? {? ??????
??? ????? bullets[i][2]-=5;
??? ????? sprite[i].setPosition(bullets[i][0],bullets[i][1]+bullets[i][2]);
??? ????? sprite[i+1].setPosition(bullets[i][0],bullets[i+1][1]+bullets[i][2]);
??? ????? sprite[i+2].setPosition(bullets[i][0],bullets[i+2][1]+bullets[i][2]);
??????? if (sprite[i].collidesWith(jp0,true))
??????? {
??????? ???? sprite[i].setImage(img,32,32);
??????? ???? sprite[i+1].setImage(img,32,32);
?????? ????? sprite[i+2].setImage(img,32,32);
??????? ???? sprite[i].setFrame(1);
??????? ???? sprite[i+1].setFrame(1);
??????? ???? sprite[i+2].setFrame(2);
??????? ???? bullets[i][3]=0;
??????? ???? bullets[i+1][3]=0;
??????? ???? bullets[i+2][3]=0;
??????? ???? jp0.setVisible(false);
?????? ????? no=1;????
?????????? score=score+1;
??????? }
??????? if (sprite[i].collidesWith(jp1,true))
??????? {
??????? ???? sprite[i].setImage(img,32,32);
??????? ???? sprite[i+1].setImage(img,32,32);
??????? ???? sprite[i+2].setImage(img,32,32);
??????? ???? sprite[i].setFrame(1);
??????? ???? sprite[i+1].setFrame(1);
??????? ???? sprite[i+2].setFrame(2);
??????? ???? bullets[i][3]=0;
??????? ???? bullets[i+1][3]=0;
??????? ???? bullets[i+2][3]=0;
??????? ???? jp1.setVisible(false);
??????? ???? no=1;
??????????????? score=score+1;
??????? }
??????? if (sprite[i].collidesWith(jp2,true))
??????? {
??????? ???? sprite[i].setImage(img,32,32);
??????? ???? sprite[i+1].setImage(img,32,32);
??????? ???? sprite[i+2].setImage(img,32,32);
??????? ???? sprite[i].setFrame(1);
??????? ???? sprite[i+1].setFrame(1);
??????? ???? sprite[i+2].setFrame(2);
??????? ???? bullets[i][3]=0;
??????? ???? bullets[i+1][3]=0;
??????? ???? bullets[i+2][3]=0;
??????? ???? jp2.setVisible(false);
??????? ???? no=1;
??????? score=score+1;
??????? }
??? }
??? public boolean isAlive(int i)
??? {
??? ????? if (bullets[i][3]==1) return true;
??????????? else return false;
??? }
??? public void setAlive(int i)
??? {
??? ????? for (int z=i;z<i+3;z++)
??? ????? {
??? ???????????? bullets[i][3]=0;
??? ????? }????
??? }
??? public int rscore()
??? {
??? ????? return score;
??? }
public void clean(int i,Sprite sprite[])
{
?????? for (int z=i;z<i+3;z++)
?????? {
????????????? //sprite[z].setPosition(0,-1500);
????????????? sprite[z].setVisible(false);
????????????? no=1;????
?????? }}}
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.util.*;
public class gameScreen extends GameCanvas implements Runnable,CommandListener
{?? private Form al;
??? public LayerManager lm,lm1;
??? TiledLayer b1;
??? int height=getHeight();
??? int bosscolor=0;
??? int sbosscolor=0;
??? int sbz=0;
??? int sbmove=0;
??? int sfire=0;
??? int smovebz=0;
??? int sbpzbz=0;
??? int slife=0;
??? int sbo=0;
??? int drawslife=0;
??? int lr=0;
??? int drawadd=0;
??? int pzbz=0;
??? int pzbzover=0;???
??? int? playlife=-1;
??? int bosslife=0;
??? int inputno=0;
??? int position=0;
??? int j1b=0;
??? int jbsz=-1;
??? int sbsz0=-1;
??? int sbsz1=-1;
??? int sbsz2=-1;
??? int sbsz3=-1;
??? int planepo;
??? int planepoup;
??? int kkk;
??? int gz=0;
??? int gzks=0;
??? int jiangli=0;
??? int jplaneno;
??? int cloundno=0;
??? int right=0;
??? int left=1;
??? int boss=0;
??? int over=0;
??? int ai=0;
??? int planert=-1;
??? int supermen=0;
??? int overcmd=0;
??? int bossover=0;
??? int jpb=-12;
??? int aipp=0;
??? int jbz=0;
??? int cloudposition;
??? Random aik=new Random();
??? Random aip=new Random();
??? Random aicloud=new Random();
??? int jb[]=new int[5];
??? int playerno=3;
private mybullets[] huokebullet=new mybullets[9];
privateSpritejbullet0,jbullet1,jbullet2,bossbullet0,bossbullet1,bossbullet2;
private Sprite cloud[]=new Sprite[5];
private MenuScreen ms;
privateSpritec1,sboss,cboss,j0,j1,j2,boss1; private lzhhdm midlet;
int s1=0;int s2=65;int s3=0;int row2;
int row;int planecolor=0;
int planecoco=0;public int by1;
public int y1;
public gameScreen (lzhhdm midlet)
{? super(true);this.midlet=midlet;
addCommand(new Command("暫停",Command.BACK,1));
?setCommandListener(this);
?lm=new LayerManager();
c1=new Sprite(img("/pic/MyPlaneFrames.png"),24,24);
cboss=newSprite(img("/pic/boss.png"),65,50);jbullet0=newSprite(img("/pic/bullet.png"),6,6);
jbullet1=new Sprite(img("/pic/bullet.png"),6,6);
jbullet2=new Sprite(img("/pic/bullet.png"),6,6);
bossbullet0=new Sprite(img("/pic/bullet.png"),6,6);
bossbullet1=new Sprite(img("/pic/bullet.png"),6,6);
bossbullet2=new Sprite(img("/pic/bullet.png"),6,6);
sboss=new Sprite(img("/pic/smallboss.png"),65,50);
b1=createBackGround(); c1.setPosition(getWidth()/2,row2+getHeight()-25);
System.out.println("ffffffffffff");
?planepoup=row2;
?planepo=row2+getHeight();
j0=new Sprite(img("/pic/jplane2.png"),24,22);
?j1=new Sprite(img("/pic/jplane2.png"),24,22);
?j2=new Sprite(img("/pic/jplane2.png"),24,22);
?kkk=getHeight()/8;
?lm.append(j0);
?lm.append(j1);
?lm.append(j2);
?cboss.setVisible(false);
?aipp=aip.nextInt()%3;
if(aipp==0)
{aipp=aip.nextInt()%3;
}lm.append(cboss);
?lm.append(bossbullet0);
?lm.append(bossbullet1);
?lm.append(bossbullet2);
?lm.append(jbullet0);
?lm.append(jbullet1);
lm.append(jbullet2);
?lm.append(sboss);
?jb[0]=1;jb[1]=1;jb[2]=1;jb[3]=1;
?try{for(int i=0;i<=4;i++){
?cloud[i]=new Sprite(img("/pic/cloud1.png"),16,16);
?lm.append(cloud[i]);}
?}catch(Exception e)
{System.out.println("cloud");}
try{for(int i=0;i<9;i++){
??? ??????????????????? huokebullet[i]=playerbullet("/pic/bullet.png");}}catch(Exception e){}
?try{for(int i=0;i<=8;i=i+3)
?{huokebullet[i].no=1;//ok
? huokebullet[i].score=0;}
? }catch(Exception e){System.out.println("ffffffffffffff");}
?for(int i=0;i<9;i++){
?lm.append(huokebullet[i]);}
?lm.append(c1);lm.append(b1);
}
private Image img (String pic)
{
?Image img=null;
try{ img=Image.createImage(pic);
}catch(Exception exp)
{System.out.println(exp);
}return img;
}
private mybullets playerbullet(String pic)
{Image img=null;
try{ img=Image.createImage(pic);
}catch(Exception exp)
{System.out.println(exp);
}return new mybullets(img,6,6,21,getWidth(),getHeight());}
public TiledLayer createBackGround()
{Image img=null;
try{??????? img=Image.createImage("/pic/beijing.png");
?????????????
?????? }catch(Exception exp)
{System.out.println("layer create image");
}???????????
TiledLayer tiledLayer=new TiledLayer(50,200,img,16,16);
int[] map1[]{ 地圖};
for(int i=0;i<map1.length;i++)
{ int? column=i%15;
row=(i-column)/15;?? ???? tiledLayer.setCell(column,row,map1[i]);}
row2=(row+1)*16-getHeight();
y1=-row2;
return tiledLayer;}
boolean conti=true;
int rate=50;
?????? public void run()
?????? {?? long st=0;
????????????? long et=0;
????????????? Graphics g=getGraphics();
????????????? int l=1350;
?????? ??? while(conti){?
st=System.currentTimeMillis();
???????????????????? input();
if(huokebullet[0].isAlive(0)){
huokebullet[0].no--;
if(huokebullet[0].no>0){?? ????? huokebullet[0].newposition(huokebullet,0,3,j0,j1,j2,cboss,img("/pic/explosion.png"));???? }
if(huokebullet[0].no<=0){??
huokebullet[0].setAlive(0);???????? ???? ?????huokebullet[0].clean(0,huokebullet);
?}}??????? ??? if(huokebullet[3].isAlive(3))
{huokebullet[3].no--;
if(huokebullet[3].no>0)
{? huokebullet[3].newposition(huokebullet,3,3,j0,j1,j2,cboss,img("/pic/explosion.png"));?????? }
?if(huokebullet[3].no<=0)
{huokebullet[3].setAlive(3);??????????
?huokebullet[3].clean(3,huokebullet);
}}?? ?????? if(huokebullet[6].isAlive(6))
{huokebullet[6].no--;??
if(huokebullet[6].no>0){?? ????? huokebullet[6].newposition(huokebullet,6,3,j0,j1,j2,cboss,img("/pic/explosion.png"));???? }
if(huokebullet[6].no<=0){huokebullet[6].setAlive(6);??????????
huokebullet[6].clean(6,huokebullet);} }if (huokebullet[0].collidesWith(cboss,true))
{huokebullet[0].setVisible(false);????????????? ??? huokebullet[1].setVisible(false);??????? ?? ?huokebullet[2].setVisible(false);
cboss.setFrame(1);
?if(bosslife<=55)
?{bosslife=bosslife+5;}
? huokebullet[0].setAlive(0);???????? huokebullet[0].clean(0,huokebullet);} if(huokebullet[0].collidesWith(sboss,true)&&(sbpzbz==0)){ ????? huokebullet[0].setVisible(false);
?? huokebullet[1].setVisible(false);?? ??????? huokebullet[2].setVisible(false);
?????? sboss.setFrame(1);
if(slife<=75){slife=slife+5;}
?huokebullet[0].setAlive(0);????????? ?????? huokebullet[0].clean(0,huokebullet);if(huokebullet[3].collidesWith(cboss,true)){cboss.setFrame(1);???????????? ?????? huokebullet[3].setVisible(false);
?huokebullet[4].setVisible(false);??????????????????????????? huokebullet[5].setVisible(false);
huokebullet[3].no=0;
if(bosslife<=55){
bosslife=bosslife+5;}??????????????????????? ? ?? ??????
huokebullet[3].setAlive(3);????????? huokebullet[3].clean(3,huokebullet);}
if(huokebullet[3].collidesWith(sboss,true)&&(sbpzbz==0)){sboss.setFrame(1);
huokebullet[3].setVisible(false);
huokebullet[4].setVisible(false);
huokebullet[5].setVisible(false);
huokebullet[3].no=1;
if(slife<=75){slife=slife+5;}
huokebullet[3].setAlive(3);?????????? huokebullet[3].clean(3,huokebullet);}
if(huokebullet[6].collidesWith(cboss,true)){???? huokebullet[6].setVisible(false);? ??????? huokebullet[7].setVisible(false);
huokebullet[8].setVisible(false);
cboss.setFrame(1);
if(bosslife<=55){ bosslife=bosslife+5;
}huokebullet[6].setAlive(6);????????? huokebullet[6].clean(6,huokebullet);??
}if(huokebullet[6].collidesWith(sboss,true)&&(sbpzbz==0)){sboss.setFrame(1);
?huokebullet[6].setVisible(false);????????????? ??? huokebullet[7].setVisible(false);??????? ?? huokebullet[8].setVisible(false);
if(slife<=75){slife=slife+5;}
huokebullet[6].setAlive(6);?????? ?????????????????????? ?????? huokebullet[6].clean(6,huokebullet);;}if((y1>-1350)&&(pzbzover==0))
{
?????? switch (ai){
?????? ??? ????? case 0:
?????? ?? ????????????? if(jb[0]==1){
?????? ??? ??????????????????? jbz=0;
???????????????????? ???? ??j0.setVisible(true);
?????? ????????? ????j1.setVisible(true);
?????? ????????????? j2.setVisible(true);
j1.setFrame(2);
?? ??????????????j0.setFrame(2);
?? ??????????????j2.setFrame(2);? j0.setPosition(100-aipp*30,planepoup+24);?? ???? ??????????j1.setPosition(100,planepoup); ????????????????j2.setPosition(100+aipp*30,planepoup-24);jb[0]=2;}
if (jb[0]==2){? j0.move(0,3);
j1.move(0,3);j2.move(0,3);
kkk=kkk-1;? }
if(kkk<=0){jb[0]=3;
if(aipp>=0){
j1.setFrame(0);? ??????? ??????j0.setFrame(0);j2.setFrame(0);?? ???? ????????????????????j0.move(-3,3);j1.move(-3,3);???? ?? ???????????????j2.move(-3,3);}else if(aipp<0)
{j1.setFrame(1);????????? ?????????? j0.setFrame(1);?????????? ???? j2.setFrame(1);j0.move(3,3);j1.move(3,3);
j2.move(3,3);}
if(j2.getY()>planepo)?? {
j0.setVisible(false);j1.setVisible(false);
j2.setVisible(false);jbullet0.setVisible(false);jbullet1.setVisible(false);???????? jbullet2.setVisible(false);jpb=-1;
ai=aik.nextInt()%4;????? ??? ????? ????????aipp=aip.nextInt()%5;
if(aipp==0){aipp=aip.nextInt()%5;
}if(ai<0) ai=ai*(-1);
jb[ai]=1;?????? ????????kkk=getHeight()/8;}}??????????? if((j1.getX()<=c1.getX()-18)&(jbz==0))
{ jpb=0;if(j0.isVisible()){
?jbullet0.setVisible(true);}
?if(j1.isVisible()){
? jbullet1.setVisible(true);}
? if(j2.isVisible()){
? jbullet2.setVisible(true);}????????? jbullet0.setPosition(j0.getX()+12,j0.getY()+30);jbullet1.setPosition(j1.getX()+12,j1.getY()+30);jbullet2.setPosition(j2.getX()+12,j2.getY()+30);jbz=1;}break;????? case 1:
?????? if(jb[1]==1){j0.setVisible(true);
? j1.setVisible(true);j2.setVisible(true);
?j1.setFrame(2);?? j0.setFrame(2);
j2.setFrame(2);j0.setPosition(100-aipp*30,planepoup+24);j1.setPosition(100,planepoup);j2.setPosition(100+aipp*30,planepoup-24);;jb[1]=2;}
if (jb[1]==2){? j0.move(0,3);
j1.move(0,3); j2.move(0,3);
kkk=kkk-1;}
if(kkk<0){jb[1]=3;}
if(jb[1]==3){ jpb=1;j1.setFrame(3);
j0.setFrame(3);j2.setFrame(3);
jb[1]=4;}
if(jb[1]==4){j0.move(0,-4);
j1.move(0,-4); j2.move(0,-4);??? ???
if(j2.getY()<planepoup) {j0.setVisible(false);
j1.setVisible(false);j2.setVisible(false);
jbullet0.setVisible(false);????? ? jbullet1.setVisible(false);jpb=-1;??? ?? ??jbullet2.setVisible(false);? ??? ????? ????ai=aik.nextInt()%4;???????????? ??? ????? ????????if(ai<0) ai=ai*(-1);jb[ai]=1;??
aipp=aip.nextInt()%5;???????? ??? ????? ?????if(aipp==0){ aipp=aip.nextInt()%5;}
kkk=getHeight()/8; }}break;
case 2: if(jb[2]==1){
jbz=0;j0.setVisible(true);
j1.setVisible(true);j2.setVisible(true);
j1.setFrame(2);j0.setFrame(2);j2.setFrame(2);?????? j0.setPosition(100-aipp*30,planepoup+aipp*30);j1.setPosition(100,planepoup);???? j2.setPosition(100+aipp*30,planepoup+aipp*30);;
jb[2]=2;} if (jb[2]==2){?
j0.move(0,3);j1.move(0,3);
j2.move(0,3);kkk=kkk-1;
}if(kkk<=0){jb[2]=3;
j1.setFrame(0);j0.setFrame(0);j2.setFrame(0);j0.move(-3,3);j1.move(-3,3);
j2.move(-3,3);? ? ???if(j2.getY()>planepo) {jpb=-1;
jbullet0.setVisible(false);
? jbullet1.setVisible(false);
?jbullet2.setVisible(false);
j0.setVisible(false); j1.setVisible(false);
j2.setVisible(false); ai=aik.nextInt()%4;
if(ai<0) ai=ai*(-1); jb[ai]=1;? ?? ????????aipp=aip.nextInt()%5; if(aipp==0)
{aipp=aip.nextInt()%5; }
kkk=getHeight()/8; ??? }
}??? if(((j1.getX()<=c1.getX()-18)||((j2.getX()-6)>=c1.getX()))&(jbz==0))
{if(j0.isVisible()){jbullet0.setVisible(true);} if(j1.isVisible()){
jbullet1.setVisible(true);}
if(j2.isVisible()) {
jbullet2.setVisible(true);}????
jpb=0; jbullet0.setPosition(j0.getX()+12,j0.getY()+30);?????? jbullet1.setPosition(j1.getX()+12,j1.getY()+30);
jbullet2.setPosition(j2.getX()+12,j2.getY()+30);jbz=1;}
??? ????? ??break;
???????? case 3:
?if(jb[3]==1){jbz=0;?? ??? j0.setVisible(true);j1.setVisible(true);
j2.setVisible(true);j1.setFrame(2);
j0.setFrame(2);j2.setFrame(2);?? j0.setPosition(200-aipp*50,planepoup-aipp*10);
j1.setPosition(100,planepoup);?? ??????????? j2.setPosition(100+aipp*50,planepoup-aipp*10); jb[3]=2; }
if (jb[3]==2){? j0.move(0,3);
j1.move(0,3);j2.move(0,3);
if(gzks==0){if(j1.getX()<c1.getX())
{j1.move(2,2);j1.setFrame(1);}
if(j1.getX()>c1.getX()){ j1.setFrame(0);
j1.move(-2,2);} if((j1.getX()<c1.getX())&&((j1.getX()+48)>c1.getX())&&(j1.getY()<c1.getY()))
?{j1.setFrame(2);j1.move(0,2); if(j1b==0){ jbullet1.setPosition(j1.getX()+12,j1.getY()+30);j1b=1;}}
?j0.move(0,3);jbullet1.move(0,3);
?j1.move(0,3);j2.move(0,3);} if((j2.getY()>(planepo+22))&&(j0.getY()>(planepo+22))&&((j1.getY()<(planepoup-22))||(j1.getY()>(planepo+22)))){
?jb[3]=1;
gz=0;gzks=0;jbullet1.setVisible(false);
jbullet2.setVisible(false);???? ?? ???????????????j0.setVisible(false);
???? j1.setVisible(false);
??? ????? j2.setVisible(false);
? ai=aik.nextInt()%4; if(ai<0)
?ai=ai*(-1);
jb[ai]=1;?? aipp=aip.nextInt()%5;
if(aipp==0) {aipp=aip.nextInt()%5;}
kkk=getHeight()/8;? }
if((j2.getX()<=c1.getX()-18)&(jbz==0))/
{ jpb=0; if(j0.isVisible())
{jbullet0.setVisible(true);}
if(j2.isVisible()){jbullet2.setVisible(true);
}jbullet0.setPosition(j0.getX()+12,j0.getY()+30);jbullet2.setPosition(j2.getX()+12,j2.getY()+30); jbz=1; }} break;}}if(jpb==0)
{jbullet0.move(0,5); jbullet1.move(0,5);
jbullet2.move(0,5); }
if((jbullet0.collidesWith(c1,true)||jbullet1.collidesWith(c1,true)||jbullet2.collidesWith(c1,true)||bossbullet0.collidesWith(c1,true)||bossbullet1.collidesWith(c1,true)||bossbullet2.collidesWith(c1,true))&&(pzbz==0)){
c1.setImage(img("/pic/explosion.png"),32,32); c1.setFrame(3); if((playerno>0))
{playerno=playerno-1; planert=1;
}else{pzbz=1; overcmd=1;???????
over=1;}}???? if((j0.collidesWith(c1,true)&&(pzbz==0)))????? {
?????? c1.setImage(img("/pic/explosion.png"),32,32); c1.setFrame(3); if(playerno>0)
?????? {playerno=playerno-1; planert=1;
playlife=0; }else{overcmd=1; playlife=1;
over=1;} j0.setVisible(false); pzbz=1;
}if((j1.collidesWith(c1,true)&&(pzbz==0))) {c1.setImage(img("/pic/explosion.png"),32,32); c1.setFrame(3); if(playerno>0)
{playerno=playerno-1; planert=1;
playlife=0; }else{overcmd=1;??????????
playlife=1; over=1;} j1.setVisible(false);
pzbz=1; if((j2.collidesWith(c1,true)&&(pzbz==0)))??????
{c1.setImage(img("/pic/explosion.png"),32,32); c1.setFrame(3);
if(playerno>0) {
playerno=playerno-1; planert=1;
playlife=0; }else{playlife=1;
if(overcmd==0) {}overcmd=1;
}???? over=1;} j2.setVisible(false);
pzbz=1; }if(overcmd==1)
{addCommand(new Command("返回",Command.OK,1)); overcmd=2;
if(boss==1) {cboss.setVisible(true);
if(cboss.getY()<25) {
????????????? ?? cboss.move(0,3);
????????????? ? }else lr=1;
????????????? if(lr==1)
????????????? {if(cboss.getX()<0)
???????????????????? {
??????????????????????????? right=0;
?????? left=1;? }
?????? else if(cboss.getX()>getWidth()-cboss.getWidth())
{left=0; right=1; }
if(right==0) {cboss.move(3,0); }
else if(left==0) {cboss.move(-3,0);} }
?????? if(((cboss.getX()<=c1.getX()-10)||(cboss.getX()<=c1.getX()+60))&&(jbsz==0))? {bossbullet0.setPosition(cboss.getX()+6,cboss.getY()+40); bossbullet1.setPosition(cboss.getX()+30,cboss.getY()+52);? ???bossbullet2.setPosition(cboss.getX()+54,cboss.getY()+40);? jbsz=1; }if(jbsz==1){
bossbullet0.setVisible(true);
bossbullet1.setVisible(true);
bossbullet2.setVisible(true);
bossbullet0.move(0,5);
bossbullet1.move(0,5);
bossbullet2.move(0,5); }
if(bossbullet2.getY()>getHeight()){jbsz=0;}}
if(bosslife==60){ cboss.setVisible(false);
j1.setVisible(false);j0.setVisible(false);
j2.setVisible(false);bossbullet0.setVisible(false);bossbullet1.setVisible(false);bossbullet2.setVisible(false);jbullet0.setVisible(false);jbullet1.setVisible(false);jbullet2.setVisible(false);
pzbz=1;bossover=1;boss=2;bosslife=65;
pzbzover=1; addCommand(new Command("返回",Command.OK,1));
????????????? }if(bosslife==45)
?????? {bosscolor=1; }
?????? if(slife==65)
?????? {sbosscolor=1;}
?????? if(y1<0){ render(g);
y1=y1+1;planepoup=planepoup-1;
planepo=planepo-1;c1.move(0,-1); }
if (y1>=0 ) { if(boss==0)
{jbsz=0; boss=1; planepoup=0;
planepo=getHeight();cboss.setPosition(80,-60); }renderboss(g); } if(bosscolor==0)
cboss.setFrame(0); else cboss.setFrame(1);
if(sbosscolor==0) sboss.setFrame(0);
else sboss.setFrame(1); if(cloundno==0)
{? cloud[0].setPosition(25,planepoup-(65));
?????? cloud[1].setPosition(80,planepoup-(140);
????? cloud[2].setPosition(112,planepoup-(90));?????? ????? cloud[3].setPosition(175,planepoup-(200)); cloud[4].setPosition(223,planepoup-(70));
cloundno=1; } cloud[0].move(0,1);
cloud[1].move(0,1); cloud[2].move(0,1);
?????? ?? ??????? cloud[3].move(0,1);
?????? ?? ??????? cloud[4].move(0,1);
?????? ???????? if(cloud[0].getY()>planepo){
cloudposition=aicloud.nextInt()%5;
if(cloudposition<0) {??? ?? ???????????? cloudposition=cloudposition*(-1);
?????? }???? cloudposition=cloudposition+1;
?????? cloud[0].setPosition(cloudposition*40,planepoup);? }if(cloud[1].getY()>planepo){
?????? cloudposition=aicloud.nextInt()%5;
if(cloudposition<0) {??? cloudposition=cloudposition*(-1);
}???? cloudposition=cloudposition+1;
cloud[1].setPosition(cloudposition*30,planepoup); }if(cloud[2].getY()>planepo){
cloudposition=aicloud.nextInt()%5;
if(cloudposition<0) {coudposition=cloudposition*(-1);
}
?????? cloudposition=cloudposition+1;
?????? cloud[2].setPosition(cloudposition*55,planepoup); }if(cloud[3].getY()>planepo){
cloudposition=aicloud.nextInt()%5;
if(cloudposition<0) {cloudposition=cloudposition*(-1);
}cloudposition=cloudposition+1;
cloud[03].setPosition(cloudposition*15,planepoup); } if(cloud[4].getY()>planepo){
cloudposition=aicloud.nextInt()%5;
if(cloudposition<0) {cloudposition=cloudposition*(-1); }
cloudposition=cloudposition+1; cloud[4].setPosition(cloudposition*22,planepoup); }if((y1==-1000)&&(sbz==0))
{sbsz0=0; sbsz1=0; sbsz2=0; sbsz3=0;
drawslife=1; sboss.setVisible(true);
sboss.setPosition(50,planepoup-65);
sbz=1; }if(sbz==1) {sboss.move(0,3);
if(sboss.getY()>planepoup) {sbz=2;
}}
if(sbz==2) {if(((sboss.getY()-50)<c1.getY())&&(smovebz==0)) {???? sbmove=1;//上移}
if(((sboss.getX()+30)<c1.getX())&&(smovebz==0)) {sbmove=4;//右移}
if(((sboss.getY()+50)<c1.getY())&&(smovebz==0)) {sbmove=2; }
if(((sboss.getX()-30)>c1.getX())&&(smovebz==0)) {sbmove=3; }if(sbmove==1)//上移
{ smovebz=1; sboss.move(0,-2); }
if(sbmove==2){smovebz=1; sboss.move(0,2);
}if(sbmove==3) {sboss.move(-2,0); }
if(sbmove==4)
{smovebz=1; sboss.move(2,0);? }
if(sboss.getY()<planepoup) {
?????? sboss.setPosition(sboss.getX(),planepoup); ?? smovebz=0; }
if(sboss.getY()>(planepo-65)){????? ?sboss.setPosition(sboss.getX(),planepo-65);
smovebz=0; }if(sboss.getX()<0) {sboss.setPosition(0,sboss.getY());smovebz=0; }if(sboss.getX()>(getWidth()-65)) {?????? sboss.setPosition(getWidth()-65,sboss.getY());????? smovebz=0; } if(((sboss.getX()+40)<c1.getX())&&(sboss.getY()<c1.getY())&&((sboss.getY()+65)>c1.getY())&&(sbsz0==0))
{bossbullet0.setVisible(true);
bossbullet0.setPosition(sboss.getX()+45,sbos.
getY()+35); sbsz0=1;
?????? ???????? }
?????? ???????? if(sbsz0==1)
{bossbullet0.move(3,0);???? if(bossbullet0.getX()>getWidth()) {
sbsz0=0; } }if((sboss.getX()>c1.getX())&&((sboss.getY()+65)>c1.getY())&&(sbsz1==0))
{bossbullet1.setPosition(sboss.getX()+10,sboss.getY()+35); sbsz1=1; }
if(sbsz1==1) {????? bossbullet1.move(-3,0);
if(bossbullet1.getX()<0) {
bossbullet1.setVisible(false);?????? sbsz1=0;}}?? ? if((sboss.getX()<c1.getX())&&((sboss.getX()+50)>(c1.getX()))&&(sboss.getY()>c1.getY())&&(sbsz2==0))? {
bossbullet2.setVisible(true);
bossbullet2.setPosition(sboss.getX()+25,sboss.getY());sbsz2=1; }if(sbsz2==1)
{bossbullet2.move(0,-4); if(bossbullet2.getY()<planepoup)
{bossbullet2.setVisible(false);???? sbsz2=0;
} }if((sboss.getX()<c1.getX())&&((sboss.getX()+50)>(c1.getX()))&&(sboss.getY()<c1.getY())&&(sbsz3==0))
{bossbullet0.setVisible(true); bossbullet1.setVisible(true); bossbullet2.setVisible(true);
bossbullet2.setPosition(sboss.getX()+10,sboss.getY()+25); bossbullet1.setPosition(sboss.getX()+30,sboss.getY()+50);
bossbullet0.setPosition(sboss.getX()+55,sboss.getY()+25); sbsz3=1; }
if(sbsz3==1) {bossbullet0.move(0,4);
bossbullet1.move(0,4); bossbullet2.move(0,4);
if(bossbullet0.getY()>planepo)
{
bossbullet0.setVisible(false);
bossbullet1.setVisible(false);
bossbullet2.setVisible(false); sbsz3=0;
}}} if((slife==80)) {
sboss.setImage(img("/pic/explosion.png"),32,32);sboss.setFrame(3);bossbullet0.setVisible(false); bossbullet1.setVisible(false);
bossbullet2.setVisible(false); jiangli=11;
slife=85; drawslife=0;
playerno=playerno+1; sbz=-1;//sbos ??????? sbpzbz=1; }
if((sboss.getY()==getHeight())){
sbz=-1; sbpzbz=1; drawadd=21;
}if(drawadd==21) {sboss.move(0,-3);
if(sboss.getY()<-65) {
sboss.setVisible(false); drawadd=31;
}}if(planert==1) {inputno=1;
pzbz=1; s2=65; c1.setImage(img("/pic/MyPlaneFrames.png"),24,24); c1.setFrame(0); c1.setVisible(true);?
c1.setPosition(getWidth()/2,planepo+48);
planert=2;
}if(planert==2)
{c1.move(0,-2); if(c1.getY()<(planepo-24))
{System.out.println(c1.getY());
System.out.println(planepo-24);inputno=0;
s1=1;
planert=3; }if(c1.getY()>(planepo+24))
{? c1.move(0,-2); }}
et=System.currentTimeMillis();
if((et-st)<rate){try{????? Thread.sleep(rate-(et-st));
}catch(Exception exp){} }
}}public void render(Graphics g)
{ g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
lm.setViewWindow(0,0,getWidth(),getHeight()+10000); lm.paint(g,0,y1); if(over==1)
{ g.drawString("寒在杭州覽橋上空因座機被擊中,壯烈殉國,年",c1.getWidth()-24,60,0); g.drawString("1937年 8月14日,空軍第4大隊少尉飛行員劉思",c1.getWidth()-24,40,0); g.drawString("僅21歲",c1.getWidth()-24,80,0); inputno=1;
}g.drawString("37年8月14日 杭州覽橋 戰果:"+String.valueOf(huokebullet[0].rscore()+huokebullet[3].rscore()+huokebullet[6].rscore()),c1.getWidth()-24,c1.getHeight()-20,0);//
if(drawslife==1) {g.setColor(255,0,0);
g.fillRect(2,22,80,5);g.setColor(255,255,255);
g.fillRect(2,22,slife,5); }
if(playerno==3) {g.drawImage(img("/pic/playerbiaozhi.png"),170,4,0);? g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0); g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0); }if(playerno==2)
{g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0);
g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0); }if(playerno==1) {
g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0); }if(playerno==4)
{g.drawImage(img("/pic/playerbiaozhi.png"),145,4,0);
?????? g.drawImage(img("/pic/playerbiaozhi.png"),170,4,0);
g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0);
?? g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0);g.setColor(255,0,0); }
if(jiangli==11){g.setColor(255,0,0);
g.drawString("援軍到達",100,150,0);
if(sboss.getY()>planepo) {jiangli=20;
?????? }} if(s1==1) {g.setColor(255,255,255);
g.fillRect(170,22,65,5); g.setColor(255,0,0);
g.fillRect(170,22,s2,5); g.drawString("無敵時間",124,18,0); drawadd=1; s2=s2-1;?????
if(s2==0) {pzbz=0; s1=2; }}
flushGraphics();}public void renderboss(Graphics g) {lm.setViewWindow(0,0,getWidth(),getHeight());?????? lm.paint(g,0,0); if(over==1)
{//c1.getHeight(),0); g.drawString("1937年 8月14日,空軍第4大隊少尉飛行員劉思",c1.getWidth()-24,40,0);
g.drawString("僅21歲",c1.getWidth()-24,80,0); inputno=1;
} g.setColor(255,0,0); g.fillRect(2,2,60,5);//
g.setColor(255,255,255); g.fillRect(2,2,bosslife,5);//
if((bossover==1)&&(c1.isVisible()))
{g.drawString("此處加覽橋空戰真實歷史戰果",c1.getWidth()-24,40,0); g.drawString("此處加覽橋空戰真實歷史戰果",c1.getWidth()-24,60,0); g.drawString("僅21歲",c1.getWidth()-24,80,0); }
if(playerno==4) {g.drawImage(img("/pic/playerbiaozhi.png"),145,4,0); g.drawImage(img("/pic/playerbiaozhi.png"),170,4,0);? g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0);??????? g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0);} if(playerno==3) {
g.drawImage(img("/pic/playerbiaozhi.png"),170,4,0);
g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0);???? ??????? g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0);}if(playerno==2){???? ?????? g.drawImage(img("/pic/playerbiaozhi.png"),195,4,0);
g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0);
}if(playerno==1){ g.drawImage(img("/pic/playerbiaozhi.png"),220,4,0); }
if(s1==1) {??? g.setColor(255,255,255);
g.fillRect(170,22,65,5);g.setColor(255,0,0);
g.fillRect(170,22,s2,5);g.drawString("無敵",124,18,0);s2=s2-1;if(s2==0)
{pzbz=0;s1=2;}}
flushGraphics();}
public void input(){?? if(inputno==0)
{int keystate=getKeyStates();
if((keystate&UP_PRESSED)!=0){
moveUp();}
if((keystate&DOWN_PRESSED)!=0){
moveDown();}if((keystate&LEFT_PRESSED)!=0){ moveLeft();}
if((keystate&LEFT_PRESSED)==0){
c1.setFrame(0);}if((keystate&RIGHT_PRESSED)!=0){moveRight();}
if((keystate&FIRE_PRESSED)!=0){
for(int i=0;i<=6;i=i+3){
if(huokebullet[i].no==1){??
for( int z=i;z<i+3;z++){ ?????????????????????????
huokebullet[z].initBullets(z);????????????????????? ??????? huokebullet[z].no=huokebullet[z].bulletheight
}huokebullet[i].setfirstposition(c1.getX(),c1.getY(),i,huokebullet,img("/pic/bullet.png"));//
break;}}}}}private void moveDown() {
c1.move(0,4);?????????????
if((c1.getY()+c1.getHeight())>planepo)
{
c1.setPosition(c1.getX(),planepo-c1.getHeight());}}private void moveUp() {c1.move(0,-4);
if(c1.getY()<planepoup){?? c1.setPosition(c1.getX(),planepoup);}}
?????? private void moveRight() {
????????????? ? c1.setFrame(2);
???????????????????? c1.move(3,0);
?????? if(c1.getX()>(getWidth()-c1.getWidth()))
?????? {????????????????????????? c1.setPosition((getWidth()-c1.getWidth())c1.getY());?????????????????
}???? }
private void moveLeft() {
????????????? c1.move(-3,0);
????????????? c1.setFrame(1);???
????????????? if(c1.getX()<=0)
?????? ??? {
?????? ??? ????? c1.setPosition(0,c1.getY());
?????? ??? }
?????? }
?????? public void start()
?????? {
????????????? Thread t=new Thread(this);
????????????? t.start();
?????? }
?????? public void commandAction(Command c,Displayable d)
?????? {
????????????? if(c.getLabel()=="暫停")
????????????? {?? conti=false;
????????????? ?removeCommand(c);
????????????? ?addCommand(new Command("繼續",Command.OK,1));
????????????? }
????????????? if(c.getLabel()=="繼續")
????????????? {?? conti=true;
????????????? start();//
????????????? ?removeCommand(c);
????????????? ?addCommand(new Command("暫停",Command.OK,2));
????????????? }
if(c.getLabel()=="返回")
????????????? {?? conti=false;
midlet.menuscreensecond();
?????? }
?????? }?
}
?
?
?
?
?
????????????????????
?????? ?? ?????
??????
附錄二? 操作說明
在電腦中使用模擬器的步驟如下:
1?? 使用WTK的新建項目功能建立一個新項目,要求與Eclipse工作區下的項目名稱MIDlet類名相同。
2?? 新建項目后,將Eclipse工作區下的.java文件拷入src文件夾,將.class文件拷入class文件夾(需要新建),將pic文件夾拷入res文件夾,點擊生成,如一切正常。
3?? 選擇項目-包-生成包。
4?? 生成的jar和jad文件存儲在lzhhdm/bin目錄下。
?? 5??? 運行Motorola SDK v4.2 for J2ME,使用MOTOA760手機模擬器進行測試。點擊Lanuc按紐,即可以進行游戲了。
電腦鍵盤的方向鍵上、下、左、右可以控制玩家飛機的運動,回車可以發射子彈。
可以將鼠標移動到相應的按紐處單擊,以測試相應的按紐。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
附錄三? 英文文獻及其譯文
What's New in the J2ME Wireless Toolkit 2.2
by Jonathan Knudsen
June 2004
The award-winning J2ME Wireless Toolkit has become the de facto standard toolkit for developing applications for Java 2, Micro Edition (J2ME). Since its debut in 2000, the toolkit has evolved to keep pace with the rapidly changing face of mobile Java technology. Don't be misled by the small change in version number from 2.1. The new toolkit supports new optional APIs specified through the Java Community Process (JCP) in four vital areas: 3D graphics, multimedia messaging, Bluetooth networking, and data management. In this article I'll describe these new APIs and show you how they're implemented in the toolkit.
Before I do, take a moment to admire the updated DefaultColorPhone emulator skin. Since version 2.1, this skin has gotten a larger screen (320 x 240, or QVGA) and far more colors (4096 instead of 256).
Mobile 3D Graphics
JSR 184, the Mobile 3D Graphics API for J2ME (M3G), provides three-dimensional graphics functionality in a compact package that's appropriate for devices that support the most widely adopted J2ME software stack, the Connected, Limited Device Configuration (CLDC) and the Mobile Information Device Profile (MIDP). The API provides two APIs for displaying 3D content. The immediate mode API makes it possible for applications to create and manipulate 3D elements directly. On top of this layer is a scene graph API, also called retained mode, that makes it possible to load and display entire 3D scenes you've designed ahead of time. Applications may use whichever API is most appropriate, or a combination of retained mode and immediate mode. The JSR 184 specification also defines a file format for scene graphs, .m3g.
The toolkit's emulator fully supports JSR 184 and you'll find several MIDlets that show off the API's capabilities in the Demo3D project.
Life3D demonstrates the use of immediate mode:
PogoRoo is an interactive demonstration that features a bouncing kangaroo:
Finally, retainedmode shows how to load and render a scene graph file:
Multimedia Messaging
The J2ME Wireless Toolkit has long supported JSR 120, version 1.1 of the Wireless Messaging API (WMA); the new release supports WMA 2.0 (JSR 205), which expands WMA's capabilities to include Multimedia Messaging.
In the toolkit, messaging takes place in a simulated environment. If you run the emulator multiple times, applications on the emulators can communicate with each other, and you can use the toolkit's handy WMA Console utility to exchange messages with the applications in the same environment. Messages may conform to any of three standard protocols: Short Message Service (SMS), Cell Broadcast Service (CBS), or - new in version 2.2 of the toolkit - Multimedia Messaging Service (MMS).
You can address MMS messages and add any collection of files to the message.
Furthermore, the network monitor now displays MMS messages that are sent or received by the emulator.
Bluetooth and OBEX
The J2ME Wireless Toolkit emulator supports JSR 82, the Java APIs for Bluetooth, which includes two independent APIs:
The Bluetooth API provides an interface to Bluetooth wireless
networking, including device discovery and data exchange.
The OBEX API allows applications to use the Object Exchange (OBEX)
protocol over Bluetooth or other communication channels.
?
The toolkit allows you to develop and test applications that use Bluetooth technology even if you don't have any actual Bluetooth hardware. The toolkit simulates a Bluetooth environment, in which you can run multiple emulator instances that can discover each other and exchange data using the Bluetooth API.
?
An example application, BluetoothDemo, shows how to transfer imagesfrom? one emulator to another.
?
The J2ME Wireless Toolkit implements OBEX transfer over simulated Bluetooth and infrared connections. The simulated infrared connection
follows the IrDA standard defined by the Infrared Data Association. The? toolkit simulates infrared transfers between multiple running emulators.
?????
You can configure the Bluetooth and OBEX environment using the Bluetooth/OBEX tab in the toolkit preferences. This controls such
parameters as how long the emulator attempts to discover other devices in the simulated Bluetooth environment and the maximum packet size. See the toolkit's User's Guide for more details.
?????
Local Files and Personal Information
The J2ME Wireless Toolkit supports JSR 75, the PDA Optional Packages for
the J2ME Platform, which also includes two independent APIs:
?
The FileConnection API gives MIDlets access to a local file system on the device.
The Personal Information Management (PIM) optional package includes APIs for manipulating contact lists, calendars, and to-do lists.
?????
A real device may have a local file system which can be accessed using the FileConnection API. In the J2ME Wireless Toolkit emulator, a simulated file system is maintained as a directory on your hard disk.
?????
The files your application can access using FileConnection are stored in subdirectories of <toolkit>/appdb/<skin>/filesystem., where <toolkit> is the installation directory of the J2ME Wireless Toolkit and <skin> is the name of the emulator skin. For example, the DefaultColorPhone emulator skin comes with a root directory installed called root1, which contains a file called Readme. The file's full path is <toolkit>/appdb/DefaultColorPhone/filesystem/root1/Readme.
?????
You can manage the root directories that are available by choosing MIDlet > External events from the emulator window's menu. You'll see a small utility window for adding and removing roots. These actions will also generate events for a registered listener object.
In a real device, personal information might be stored in a proprietary
format in memory. The emulator uses a directory on your hard disk to
contain this information, accessible using the PIM API. All information is stored in <toolkit>/appdb/pim. Lists are stored in subdirectories of the contacts, events, and todo directories. For example, a contact list called Contacts is contained in <toolkit>/ appdb/ pim/ contacts/ Contacts.
????
Inside the list directory, items are stored in standard formats specified by the Internet Mail Consortium. Contacts are stored in vCard format, while calendar and to-do items are both stored in vCalendar format.
Summary
The J2ME Wireless Toolkit 2.2 is much more than an incremental update of an excellent tool. It includes support for four exciting new
specifications that together define six new APIs. As the world of wireless Java technology rapidly evolves, the J2ME Wireless Toolkit keeps pace and contains all the tools you need for
About the Author: Jonathan Knudsen [e-mail] [home page] is the author of several books, including Wireless Java (second edition), The Unofficial Guide to LEGO MINDSTORMS Robots, Learning Java (second edition), and Java 2D Graphics. Jonathan has written extensively about Java and Lego robots, including articles for JavaWorld, EXE, NZZ Folio, and the O'Reilly Network. Jonathan holds a degree in mechanical engineering from Princeton University.
譯文
J2ME Wireless Toolkit 2.2 新改進
作者:Jonathan Knudsen
2004 年 6 月
屢獲殊榮的 J2ME Wireless Toolkit 已經成為 J2ME 開發應用程序的事實標準工具包。自從 2000 年初次亮相以來,該工具包一直在發展以趕上移動 Java 技術外觀上快速改變的步伐。不要被從 2.1 版本以來的小改變所誤導。新的工具包在四個重要的領域支持 Java Community Process (JCP) 所指定的新的可選 API:3D 圖形、多媒體通信、藍牙連網(Bluetooth networking)和數據管理。本文將描述這些新的 API 并且向您展示如何在工具包中實現他們。
在這之前,讓我們贊美一下更新后的 DefaultColorPhone 模擬器皮膚,自從 2.1 版本以來,該皮膚已有了一個更大的屏幕(320 x 240, 或 QVGA)和更多的顏色(4096 色而不是 256 色)。
移動 3D 圖形
JSR 184,? 即 Mobile 3D 圖形 API for J2ME (M3G) 在一個集成軟件包中提供了三維圖形功能,適用于支持最為廣泛采用的 J2ME 軟件棧、有限連接設備配置(CLDC)和移動信息設備描述(MIDP)的設備。API 為顯示 3D 內容提供了兩種 API。立即模式 API 使應用程序能夠直接創建和操縱 3D 元素。這一層之上是一個場景圖 API,也稱為保留模式,能夠提早加載并顯示已設計的整個 3D 場景。應用程序可以采用最適合的 API,或保留模式與立即模式的組合。JSR 184 規范還為場景圖定義了一種文件格式-.m3g。
該工具包的模擬器全面支持 JSR 184,并且有幾個 MIDlet 展示了 API 在 Demo3D 項目中的功能。Life3D 演示了立即模式的使用。PogoRoo 是一個的交互的演示,特點是顯示一只跳躍的袋鼠:
多媒體通信
J2ME Wireless Toolkit 長期支持 JSR 120、Wireless Messaging API(WMA)的1.1版本;新版本支持 WMA 2.0(JSR 205),其把 WMA 的功能擴展到包括多媒體通信。
在工具包中,通信發生于模擬的環境中。如果多次運行模擬器,模擬器上的應用程序能夠相互通信,并且可以使用工具包方便的 WMA Console 實用程序在同一環境中與應用程序交換消息。通信可以遵照以下三種標準協議之一:短消息服務(Short Message Service,SMS)、蜂窩廣播服務(Cell Broadcast Service,CBS)或工具包 2.2 版本中的新協議-多媒體通信服務(MMS)。
您可以標記 MMS 消息,并向消息添加任何文件集合。
而且,現在網絡監視器能夠顯示模擬器發送或接收的 MMS 消息。
藍牙和 OBEX
J2ME Wireless Toolkit 模擬器支持 JSR 82,即 Java API for Bluetooth,包括兩個獨立的 API:
藍牙 API 為藍牙無線網絡提供了接口,包括設備恢復和數據交換。
OBEX API 允許應用程序在藍牙或其他通信信道上使用對象交換(Object Exchange,OBEX)協議。
該工具包允許在即使沒有實際藍牙硬件的情況下,也可以開發和測試采用藍牙技術的應用程序。該工具包模擬藍牙環境,您可以在該環境中運行可相互發現的多個模擬器實例和使用藍牙 API 交換數據。
應用程序實例 BluetoothDemo 顯示了如何從一個模擬器將圖像傳輸到另一個模擬器。
J2ME Wireless Toolkit 通過模擬的藍牙和紅外連接上實現 OBEX 傳輸。模擬的紅外連接遵循 Infrared Data Association 定義的 IrDA 標準。工具包在多個運行的模擬器之間模擬紅外傳輸。
您可以使用工具包參數中的 Bluetooth/OBEX 標簽來配置藍牙和 OBEX 環境。其控制了諸如模擬器在模擬的藍牙環境中試圖用多長時間去發現其他設備,以及最大數據包大小等參數。請參見工具包的用戶指南獲取更多的詳細信息。
本地文件和個人信息
J2ME Wireless Toolkit 支持 JSR 75,即 PDA Optional Packages for the J2ME Platform,它也包括兩個獨立的 API:
FileConnection API 提供了 MIDlet 對設備上本地文件系統的訪問。
Personal Information Management (PIM) 可選軟件包包括用于操縱聯系人列表、日程安排和計劃列表的 API。
一臺真實的設備可能有一個能通過使用 FileConnection API 訪問的本地文件系統。在 J2ME Wireless Toolkit 模擬器中,模擬的文件系統作為硬盤上的一個目錄存在。
應用程序使用 FileConnection 可訪問的文件都存放在子目錄 <toolkit>/appdb/<skin>/filesystem.中,此處 <toolkit> 是 J2ME Wireless Toolkit 的安裝目錄,<skin> 是模擬器皮膚的名稱。例如,DefaultColorPhone 模擬器皮膚隨安裝根目錄 root1 而產生,包含一個 Readme 文件。文件的完整路徑為<toolkit>/appdb/DefaultColorPhone/filesystem/root1/Readme。
您可以從模擬器窗口的菜單種選擇 MIDlet > External events 來管理可用的根目錄。您將看到一個添加和刪除根目錄的小的實用程序窗口。這些操作也將為 registered listener 對象生成事件。
在真實的設備上,個人信息可能以專有格式存儲在內存中。模擬器使用硬盤中的一個目錄來存放這些信息,可使用 PIM API 來訪問。所有的信息存儲在 <toolkit>/appdb/pim 目錄中。列表存儲在聯系人、事件和計劃目錄的子目錄中。例如,聯系人列表 Contacts 位于 <toolkit>/appdb/pim/contacts/Contacts 目錄中。
在列表目錄內,列表項以 Internet Mail Consortium 指定的標準格式存儲。聯系人以 vCard 格式存儲,日歷和計劃項都以 vCalendar 格式存儲。
結束語
J2ME Wireless Toolkit 2.2 不僅僅是一個出色工具的增量更新。它包括了對令人激動的四項新規范的支持,同時定義了六種新的 API。隨著無線 Java 技術世界的快速發展,J2ME Wireless Toolkit 緊緊跟隨發展的步伐并且包含您所需的全部工具。
關于作者
Jonathan Knudsen[電子郵件] [主頁],有多本著作,包括:Wireless Java (second edition)、The Unofficial Guide to LEGO MINDSTORMS Robots、Learning Java (second edition) 和 Java 2D Graphics 。Jonathan 在 Java 和 Lego 機器人領域編寫了大量的文章,包括 JavaWorld、 EXE、 NZZ Folio 和 the O'Reilly Network 方面的文章。作者擁有普林斯頓大學的機械工程學位。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
目? 錄
1 緒論
1.1 手機軟件現狀
1.2 J2ME介紹
1.3 手機游戲應具有的特征
1.4 本游戲背景介紹
1.5 本章小結
2 開發環境及相關技術的介紹
2.1 開發環境
2.2 Java語言特點
2.3 關于ECLIPSE
2.4 關于Wireless Tool Kit
2.5 Java Appication Manager
2.6 本章小結:
3 程序結構、思想和相關技術
3.1 本程序需要解決的主要技術問題
3.2 程序流程
3.3 Canvas類
3.4 Graphics類
3.5 MIDP1.0技術下的繪制背景技術
3.6 MIDP2.0新增的GameCanvas包
3.7 PNG圖片格式
3.8 玩家飛機的控制方式和敵人方的智能運行
3.9 子彈的運行和控制
3.10 內存的優化
3.11 內存檢測器
3.12 關于混淆器
3.13 本章小結
4 程序分析和具體實現
4.1 游戲進入前的選擇
4.2 mybullets類
4.3 游戲邏輯及gameScreen類
4.3.1 gameScreen類所實現的功能
4.3.2 地圖的創建
4.3.3地圖的移動
4.3.4 gameScreen類的構造函數
4.3.5 關于commandAction()方法
4.3.6 Sprite類對象的碰撞檢測及相關屬性
4.3.7 玩家4次游戲機會的實現方法
4.3.8 input()
4.3.9 render()和renderboss()
4.4 游戲中的獎勵及相關飛機的行為
4.5 普通敵人相關屬性
4.6 白云的實現原理
4.7 關尾BOSS及相關屬性
4.8本章小結
5測試
5.1 打包測試的過程
5.2 發現的BUG及解決情況
5.3 未完善的功能
6總結
6.1 本程序的總結和展望
6.2 感想
致??? 謝
參考文獻
附錄一代碼
附錄二操作說明
附錄三英文文獻及其譯文
?
摘? 要
這款游戲的名字叫《覽橋風光》。J2ME(Java 2 Micro Edition) 是近年來隨著各種不同設備,尤其是移動通信設備的飛速發展而誕生的一項新的開發技術。它定位在消費性電子產品的應用上,對設備的智能化、多樣化,提供了革命性的解決方案,并因其“Write Once, run anywhere”的Java特性而提高開發的效率。
隨著手機的日益普及、Java功能在移動設備上的實現,Java應用程序產生的手機增值服務逐漸體現出其影響力,對豐富人們的生活內容、提供快捷的資訊起著不可忽視的作用。本論文著眼于J2ME技術的應用,開發一款可商用的手機游戲程序。本程序將老少皆宜的經典作品移植到手機上來,為更流行的硬件平臺提供應用軟件。
本論文介紹了J2ME的相關技術及本程序的結構分析和具體功能的實現。
總結
以上是生活随笔為你收集整理的手机游戏毕业设计论文的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Xcode - 使用 DWURecycl
- 下一篇: 微信小程序使用MQTT远程控制单片机——