




已閱讀5頁,還剩75頁未讀, 繼續(xù)免費閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
從零開始學(xué)安卓經(jīng)典教程本文是入門android的經(jīng)典教材,文中既有圖片直觀的展示,又有文字的詳細說明,并且給出了相應(yīng)代碼,對于初學(xué)者來說是極好的入門材料。 -謹以感謝原作者什么是OPhoneOPhone是基于Linux、面向移動互聯(lián)網(wǎng)的終端基礎(chǔ)軟件及系統(tǒng)解決方案。OPhone SDK是專為OPhone平臺設(shè)計的軟件開發(fā)套件,它包括OPhone API,OPhone模擬器,開發(fā)工具,示例代碼和幫助文檔(摘自O(shè)Phone官方網(wǎng)站:/)。簡而言之,OPhone是一個移動終端的操作系統(tǒng),移動終端包括手機、MID、NetBook等等。與其他領(lǐng)域的編程一樣,OPhone編程并沒有什么神秘之處,只需簡單的學(xué)習(xí)就可以掌握大部分的概念。剩下的就是盡情發(fā)揮你的想象力了。寫作本文的目的為了普及OPhone編程的基本知識,并通過復(fù)刻一個坦克大戰(zhàn)游戲讓讀者了解2D游戲編程的簡單思路。文中的程序結(jié)構(gòu)和實現(xiàn)方法并非最優(yōu),希望能起到一個拋磚引玉的作用,讓更多的人加入到OPhone開發(fā)的行列中來。誰適合閱讀本文雖然本文叫做“從零開始OPhone編程”,但并不能面對那些對編程一無所知的讀者。實際上,本文要求讀者了解java語言的基本知識,最好會使用eclipse。在文章的每個章節(jié)都標有難度,有能力的讀者完全可以跳過相對容易的章節(jié)直接閱讀自己感興趣的內(nèi)容。本文的時效性本文只適合當前版本的OPhone SDK(v1.0),本文的代碼、圖片、鏈接可能會因時間推移而失效。第一章 搭建開發(fā)環(huán)境工欲善其技,必先利其器。我們要做的第一件事就是搭建Android開發(fā)環(huán)境。本文只介紹Windows下的安裝方法,Linux下的安裝方法請參考官方網(wǎng)站的介紹。與PC編程略有不同的是,Android的程序需要在模擬器中運行。因此,我們需要一個集成開發(fā)環(huán)境,一個SDK和一個模擬器。因為Android編程使用java語言,所以我們還需要JDK,最好使用安裝版本(/javase/downloads/index.jsp)選用JDK 6 Update 16 Windows版即可。集成開發(fā)環(huán)境我們選用eclipse,可以使用eclipse3.3到3.5的任意版本(/eclipse/downloads/)最好下載JDT集成版。然后我們可以從Android官方網(wǎng)站() 下載Android SDK(當然,如果你不能翻墻,可以到國內(nèi)的網(wǎng)站下載),SDK全部安裝完畢之后,還需要安裝eclipse插件。插件是用來擴展eclipse功能的。 開發(fā)Android用的插件叫ADT(Android Developer Tools),它可以幫助我們完成創(chuàng)建項目,向模擬器部署并運行程序,調(diào)試程序等工作。關(guān)于ADT的功能,在后面使用中我們會逐漸熟悉。安裝ADT的方法如下(以eclipse3.4為例):啟動eclipse,選擇菜單中的Help - Software Updates點擊Add Site點擊Archive找到OPhone SDK安裝目錄下toolsophone ADT-0.8.0.zip(因為我已經(jīng)安裝好了ADT,所以出現(xiàn)了重復(fù)URL的提示),點擊OK即可開始安裝ADT安裝完畢后還要簡單配置一下,打開菜單中的Window - Preferences找到Android項,通過Browse按鈕指定Android SDK的安裝位置至此為止,Android的安裝環(huán)境就全部搭建完畢了。下一章節(jié),我們會遇見經(jīng)典的helloworld,下章見!第二章 創(chuàng)建第一個程序Hello Tank現(xiàn)在開始,我們要真正寫作Android程序了。雖然前面安裝過程那么復(fù)雜,但是寫起程序來卻是非常簡單。而且為了讓大家有一個直觀的認識,本文不會敘述大段的原理,而是在編碼的過程中滲透對原理、概念的講解。讓我們打開eclipse,選擇菜單中的File - New - Project選擇Android - Android Project下面需要我們輸入項目的一些信息,因為我們要復(fù)刻經(jīng)典游戲坦克大戰(zhàn),所以我們的程序就取名Tank這樣,一個Android項目就創(chuàng)建完成了,我們可以在eclipse的Package Explorer看到我們的項目托ADT的福,雖然我們只輸入了幾個名字,但這個項目實際上已經(jīng)可以運行了。右擊項目名,選擇Run As - Android Application不出意外的話,你會看到一個手機模擬器被啟動,而我們剛剛建立的程序會被運行起來如 果你發(fā)現(xiàn)模擬器啟動了,而程序并沒有被運行,可能需要手工啟動程序。這里我們用到一個重要的工具DDMS(Davlik Debug Manager)。運行DDMS快捷方法是點擊eclipse右上角的Open Perspective,如果在彈出的列表中沒有DDMS,那么點擊Others選擇DDMS這樣我們就打開了DDMS界面,這個工具我們以后會經(jīng)常用到。剛剛說到模擬器啟動了而程序并沒有被運行,很可能是在模擬器啟動過程中DDMS失去了與模擬器的鏈接。解決方法很簡單:點擊Devices標簽下的工具欄,選擇Reset adb然后右擊項目名稱,Run As - Android Application。除了右擊運行項目,還可以通過工具欄上的運行按鈕啟動程序在運行按鈕左邊的是Debug按鈕,這兩個我們以后也會經(jīng)常用到。現(xiàn) 在我們已經(jīng)有了第一個可以運行的Android,雖然你可能對ADT生成的一堆文件感到一頭霧水,也不知道程序界面上那一句“Hello World, Main”是從哪里來的,但是沒關(guān)系,隨著本文的深入你會逐漸熟悉Android項目的目錄結(jié)構(gòu),程序設(shè)計的原則和方法,以及調(diào)試和部署的方法?,F(xiàn)在讀者 可以自己熟悉一下模擬器的操作,讓我們下章再見。第三章 顯示文字和圖片從 本章開始,讀者就要編寫代碼了。按照作者的原則少一些理論,多一些實踐,代碼中可能會有跳躍的地方。但是請大家不要著急,隨著學(xué)習(xí)的深入,你很快就會 了解其中的奧秘。不過在開始之前,我們還是要先來理順一下思路,看看完成一個坦克大戰(zhàn)游戲需要哪些工作:首先,我們需要一個基本的程序,這個程序能夠在 Android上運行;這個程序要能夠顯示圖形包括地圖,主角和NPC等等;程序能夠接受用戶的輸入,控制主角移動;程序要能夠控制NPC和子彈的移動; 程序還能對各種事件做出判斷,比如擊中敵人,獲得物品,勝利或者失敗?,F(xiàn)在我們就從基本程序開始,一步一步實現(xiàn)它。首先,讓我們看一下剛剛生成的文件目錄在源文件目錄下,只有Main.java和R.java兩個文件,剛剛被我們命名成Main.java的文件就是程序的入口文件。而R.java是由插件來維護的資源定義文件,我們先不管它。Main.java內(nèi)容如下:package org.yexing.android.games.tank;import android.app.Activity;import android.os.Bundle;public class Main extends Activity /* Called when the activity is first created. */Overridepublic void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main);很 幸運,Main.java的代碼非常之少,而且還有一段注釋,以致我們很容易知道函數(shù)onCreate的作用,需要解釋的只是 setContentView()。先不要管注釋中提到的Activity和setContentView的參數(shù)R.layout.main,我們使用 setContentView的另一種形式:setContentView(View view)。setContentView的作用是設(shè)定當前使用的視圖即View(依此理解,可以有很多個View,需要用哪個就可以把他作為 setContentView的參數(shù)顯示出來)。View是一個非常重要的組件,它可以用來顯示文字,圖片,也可以接收客戶的操作,比如觸摸屏,鍵盤等 等,而我們的游戲中正是需要繪圖和交互,看來View很符合我們的需要(但是請注意,使用View并不是我們的最終方案,原因會在后面說明。此處介紹 View是為了講解基礎(chǔ)的圖形和用戶控制)。下面我們就要訂制一個屬于自己的View,可以通過繼承自系統(tǒng)提供的View,并重載相關(guān)的函數(shù)來實現(xiàn)。創(chuàng)建類的方法如下:右擊包名 New - Class我們將這個View類命名為GameView,并且由android.view.View繼承點 擊Finish,一個View類就創(chuàng)建好了。這里是第一次創(chuàng)建類,以后就不會有圖片演示了,請大家記住的這個方法。GameView創(chuàng)建好了,但是代碼還 有一些錯誤,這里介紹一下eclipse的使用技巧,將鼠標懸停在有錯誤的位置,或者將光標停在有錯誤的行,然后按Ctrl+1鍵,就會出現(xiàn)修改建議,大 部分時候,使用修改建議都可以改正我們的錯誤,如圖可以看出來,剛剛的錯誤是因為沒有創(chuàng)建構(gòu)造函數(shù),選擇修改建議的第二項,增加一個構(gòu)造函數(shù)public GameView(Context context) super(context);/ TODO Auto-generated constructor stub我們的View就創(chuàng)建好了?;氐組ain.java,剛剛說了,只要將View作為setContentView的參數(shù),這個View就可以被顯示出來:public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(new GameView(this);現(xiàn)在讓我們運行模擬器,看看程序變成什么樣子了(啟動模擬器的方法見第二章)。不要意外,屏幕上就是一片空白,因為我們創(chuàng)建了一個View,但是沒有讓它顯示任何內(nèi)容。下面我們就會在View上顯示一段文字和一張圖片。讓View顯示內(nèi)容也很簡單,只需要重載View的onDraw函數(shù),把相應(yīng)的語句寫入onDraw中即可。打開GameView.java,點擊菜單 Source - Override/Implement Method選中onDraw點擊OK下面這段代碼就會被加入到程序當中,所有與顯示有關(guān)的代碼都會在這里面完成Overrideprotected void onDraw(Canvas canvas) / TODO Auto-generated method stubsuper.onDraw(canvas);這 里我們遇到了又一個非常重要的類Canvas,Canvas一般翻譯成畫布,所有的繪圖操作都是通過Canvas中的函數(shù)來完成的,比如顯示文字的函數(shù) Canvas.drawText(),顯示位圖的函數(shù)Canvas.drawBitmap(),以及各種繪制圖形的函數(shù)如 Canvas.drawRect(),Canvas.drawArc()等等。下面讓我們顯示一段文字在屏幕上:protected void onDraw(Canvas canvas) / TODO Auto-generated method stubsuper.onDraw(canvas);canvas.drawText(坦克大戰(zhàn), 50, 50, new Paint();坦克大戰(zhàn)四個字已經(jīng)出現(xiàn)在了屏幕上。讓我們來詳細看一下這條語句:canvas.drawText(坦克大戰(zhàn), 50, 50, new Paint();第 一個參數(shù)是要顯示的文字,第二、第三個參數(shù)是文字在屏幕上的坐標,說到坐標得多講兩句。在2D編程中,屏幕坐標的原點是屏幕的左上角,橫向向右增大,縱向 向下增大,如上圖所示。最后一個參數(shù)是Paint,通常翻譯成畫筆,它決定了文字或圖形的顏色,字體,線條粗細等等,后面用到相應(yīng)屬性的時候會詳細介紹。 那么這條語句就是在屏幕上(50,50)的位置用缺省的畫筆寫出“坦克大戰(zhàn)”四個字。另外如果eclipse提示代碼錯誤,不要忘了用Ctrl+1。有了文字,下面就是圖像了。顯示圖像比顯示文字略微復(fù)雜一些,首先我們要準備一張位圖,圖片必須是png格式的,文件名只能是小寫字母,數(shù)字和下劃線。battlecity.png然后將這張圖片copy到工程的res/drawable目錄下??梢灾苯釉趀clipse的目錄樹中粘貼。顯示位圖的函數(shù)是Canvas.drawBitmap(),drawBitmap有很多種形態(tài),我們先看其中最簡單的一種canvas.drawBitmap(bitmap, left, top, paint)乍 一看似乎和drawText差不多,4個參數(shù)有三個都相同,但這第一個參數(shù)bitmap要比文本復(fù)雜得多。首先,他是一個Bitmap類實例,因為我們現(xiàn) 在還不需要這個類的其他功能,所以不過多介紹Bitmap,只考慮它是怎么來的。得到Bitmap實例的方法也有很多種,這里只介紹其中的一種BitmapFactory.decodeResource(res, id);此 方法可以返回一個bitmap實例,但是這個函數(shù)還需要兩個參數(shù)res和id。res是Resources實例,而id是一個整數(shù),下面讓我們分別了解這 兩個參數(shù)。res的地位跟bitmap差不多,只需要作為參數(shù)被使用,因此,只要得到實例就可以了,獲得Resources實例的方法如下:res = context.getResources();天哪,事情越來越復(fù)雜了,因為這段代碼里面有多了一個陌生面孔context。context是Context實例,Context通常翻譯做上下文,這個名稱似乎有點晦澀,他究竟是什么呢?讓我們回頭看看寫好的程序public GameView(Context context) super(context);/ TODO Auto-generated constructor stub這時候我們有一個context實例,繼續(xù)朔源而上,在Main.java中public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(new GameView(this);原來,context指向Main類。好了,我們終于找到res的源頭了。還有另外一個分支第二個參數(shù)id。BitmapFactory.decodeResource(res, id);id是一個整形,它到底是誰的id呢?我們還是得往前面找,還記得我們第一次見到函數(shù)setContentView時什么樣子么setContentView(R.layout.main);對,他的參數(shù)是R.layout.main,后來被我們替換成了GameView實例。R.layout.main就是一個整數(shù)。它被定義在文件R.java中,我們前面講過R.java是由插件維護的資源定義文件。說到這里大家應(yīng)該猜到了吧。讓我們打開R.java文件public final class R public static final class attr public static final class drawable public static final int battlecity=0x7f020000;public static final int icon=0x7f020001;public static final class layout public static final int main=0x7f030000;public static final class string public static final int app_name=0x7f040001;public static final int hello=0x7f040000;果然,位圖文件battlecity.png在這里面也被分配了一個id:R.drawable.battlecity,沒錯,就是它了,這就是我們要找的id。至此為止,我們終于可以使用drawBitmap了。對于一次創(chuàng)建,多次使用的資源,我們把他放到構(gòu)造函數(shù)里面。增加了圖形顯示的GameView如下:public class GameView extends View Bitmap bmp;public GameView(Context context) super(context);/ TODO Auto-generated constructor stubResources res = context.getResources();bmp = BitmapFactory.decodeResource(res, R.drawable.battlecity);Overrideprotected void onDraw(Canvas canvas) / TODO Auto-generated method stubsuper.onDraw(canvas);canvas.drawText(坦克大戰(zhàn), 0, 50, new Paint();canvas.drawBitmap(bmp, 0, 100, new Paint();運行效果第四章 響應(yīng)用戶事件上一章介紹了如何顯示文字和圖片,一般來說,下一步就該講到動畫了??墒俏覀兦懊嬲f了,使用View不是最終的選擇,要實現(xiàn)動畫還需要很多復(fù)雜的代碼。相對來說,學(xué)習(xí)如何響應(yīng)用戶事件要簡單些。本章前半部分講解按鍵事件的響應(yīng),但是這也不是最終方案,因為實際上的手機可能沒有硬鍵盤,需要使用虛擬鍵盤,所以后半部分我們會講解虛擬鍵盤的設(shè)計和實現(xiàn)。同繪圖一樣,View也是通過回調(diào)函數(shù)來響應(yīng)用戶事件的。鍵盤事件的回調(diào)函數(shù)有多個,以對應(yīng)不同的事件,我們暫時只用到onKeyDown,對應(yīng)按鍵被按下的事件,其他函數(shù)以后用到再介紹。讓我們重載onKeyDown(重載一個函數(shù)的方法前面章節(jié)有介紹):Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) / TODO Auto-generated method stubreturn super.onKeyDown(keyCode, event);onKeyDown有兩個參數(shù):keyCode和event,通過keyCode能判斷是哪個鍵被按下,event比較復(fù)雜,包含了這次按鍵更多的信息,我們暫時先不考慮它?,F(xiàn) 在我們要通過按鍵控制主角向四個方向移動。所謂移動,就是將主角的圖像在不同的位置顯示出來,也就是改變函數(shù)drawBitmap中的第二、第三個參數(shù)。 比如用戶按下右方向鍵,我們就把橫坐標增加,這樣下次顯示出來的時候,主角就會往右一點。為了節(jié)約時間,我們就把剛剛顯示的圖片BattleCity作為 主角好了。首先定義兩個全局變量x和y,然后在onKeyDown中改變x、y的值,然后重繪View。因為代碼沒有什么難度,所以不做講解了。public class GameView extends View int x=0, y=0;Overrideprotected void onDraw(Canvas canvas) canvas.drawBitmap(bmp, x, y, new Paint();Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) / TODO Auto-generated method stubswitch(keyCode) case KeyEvent.KEYCODE_DPAD_UP:y -= 10;break;case KeyEvent.KEYCODE_DPAD_DOWN:y += 10;break;case KeyEvent.KEYCODE_DPAD_LEFT:x -= 10;break;case KeyEvent.KEYCODE_DPAD_RIGHT:x += 10;break;postInvalidate(); /通知系統(tǒng)重繪Viewreturn super.onKeyDown(keyCode, event);完成后我們肯定很想測試一下,但是此時你會發(fā)現(xiàn),按鍵根本沒有任何反應(yīng)。這就是我們要特殊指出的地方。View被顯示時,缺省情況下沒有獲得焦點,就是說,按鍵動作沒有發(fā)送給View,所以需要在構(gòu)造函數(shù)中增加一句public GameView(Context context) setFocusable(true);再運行程序,看看圖片是否按照我們的指令運動起來了。前 面說過,很多手機沒有硬鍵盤,所以我們需要一個軟鍵盤的解決方案。軟鍵盤就是在屏幕上顯示一個鍵盤,然后響應(yīng)用戶的觸摸屏操作,模擬成鍵盤操作。對于坦克 大戰(zhàn),我們只需要在屏幕上顯示一個模擬的游戲手柄(顯示圖片的方法大家沒有忘記吧,顯示位置可以根據(jù)模擬器自行調(diào)整):在用戶觸摸模擬手柄上的方向鍵和開火鍵時進行相應(yīng)的操作。我們拿方向鍵做演示,步驟如下:首先確定四個方向鍵在屏幕上的區(qū)域(上圖的紅色方框),然后在觸摸屏事件的響應(yīng)函數(shù)中判斷事件是否發(fā)生在方向鍵區(qū)域中,最后如果事件發(fā)生在區(qū)域中進行相應(yīng)的操作。下 面,我們引入一個非常有用的類Rect(RectF與Rect基本相同,不過以float作為坐標參數(shù)),rect是rectangle的簡寫,顧名思 義,這個類代表了一個矩形。Rect通過矩形4個邊來定義這個矩形的范圍。他們分別是left,right,top,bottom,如圖所示:轉(zhuǎn) 化為屏幕坐標,top是矩形坐上角的縱坐標,left是矩形坐上角的橫坐標,right是矩形右下角的橫坐標,buttom是右下角的縱坐標。有了 Rect我們就可以方便的表示虛擬手柄各個鍵的位置。同時Rect還提供了一些很有用的函數(shù),其中Rect.contains(x, y)能夠判斷點(x, y)是否在矩形框中,正好是我們需要的。現(xiàn)在我們就可以開始編碼了,首先為虛擬鍵盤的方向鍵創(chuàng)建Rect(可以用繪圖工具測量坐標):Rect rKeyUp = new Rect(56,290,86,320);Rect rKeyDown = new Rect(56, 350, 86, 380);Rect rKeyLeft = new Rect(26, 320, 56, 350);Rect rKeyRight = new Rect(86, 320, 116, 350);然后重載觸摸屏響應(yīng)函數(shù):Overridepublic boolean onTouchEvent(MotionEvent arg0) / TODO Auto-generated method stubreturn super.onTouchEvent(arg0);下面我們要做的是,首先判斷觸摸屏操作是不是按下,如果是,取得坐標(x,y),然后判斷坐標所在的按鍵,做出相應(yīng)的操作Overridepublic boolean onTouchEvent(MotionEvent arg0) / TODO Auto-generated method stubif (arg0.getAction() = MotionEvent.ACTION_DOWN) int ax = (int) arg0.getX();int ay = (int) arg0.getY();if (rKeyUp.contains(ax, ay) y -= 10; else if (rKeyDown.contains(ax, ay) y += 10; else if (rKeyLeft.contains(ax, ay) x -= 10; else if (rKeyRight.contains(ax, ay) x += 10;postInvalidate(); /不要忘記刷新屏幕return super.onTouchEvent(arg0);現(xiàn)在讓我們運行一下,每次用鼠標點擊模擬手柄的方向鍵,圖片就會移動至此為止,我們介紹了兩種響應(yīng)用戶事件的手段,但是要真正完成對一個游戲的控制,還需要更多的工作,后面還有深入的講解。第五章 小結(jié)掃雷游戲的實現(xiàn)目前,我們學(xué)習(xí)了如何建立Android編程環(huán)境,如何顯示文字和圖片,如何響應(yīng)用戶事件。作為總結(jié),我們要運用這些知識實現(xiàn)一個掃雷游戲。先說游戲規(guī)則:掃雷,就是在一個分成若干小格的矩形區(qū)域中發(fā)現(xiàn)隱藏的地雷,找到它,但是不能觸發(fā)它。每次翻開一個小格,如果下面是地雷,游戲就失敗 了。如果不是地雷,而它的周圍8個格中有地雷,那么就會顯示周圍的地雷數(shù)。如果周圍8個格中沒有地雷,那就是空白的。如果你認為某一格是地雷可以用紅旗標 記它,正確標記了所有的地雷或者翻開了所有不是地雷的格就取得勝利。再說用戶操作:在Windows中用戶可以有三種操作,左鍵單擊,右鍵單擊,左右鍵同時單擊。左鍵可以翻開一個小格,可以觸雷,如果點到了一個空白 格,跟它相聯(lián)的所有空白格都會被打開。右鍵可以標記一個格,不會觸雷,標記方式有兩種,第一次單擊用紅旗標記,確信此處有雷,再次單擊紅旗變成問號,表示 可能有雷。左右鍵同時單擊只在此種情況有效,即一個格周圍有雷,并且所有的雷都已被用紅旗標記出來。此時單擊此格會打開周圍所有未標記的格,此操作會觸 雷,就是說如果標記錯了游戲就會失敗,所以一定要小心使用。因為在手機上沒有右鍵,所以我們必須設(shè)計替代方案,一種方法是設(shè)計一個開關(guān)圖標,點擊打開開關(guān) 后,所有的操作都被認為是右鍵和左右鍵同時單擊,另外還可以借助手機上的菜單鍵,按住菜單鍵等同打開開關(guān),松開等同關(guān)閉開關(guān)。為了方便游戲,我們可以同時 實現(xiàn)兩個方案。最后讓我們分析一下程序的大體思路,從最直觀的用戶界面開始,我們需要根據(jù)游戲的顯示區(qū)域創(chuàng)建游戲地圖,一個m行n列的二維整形數(shù)組,數(shù)組中的一個 值對應(yīng)界面上的一個格,不同的數(shù)值可以表示不同的狀態(tài),比如0表示空白格,1表示此格周圍有一個雷,2表示有兩個雷等等。因為雷的位置是隨機的,所以這張 地圖需要在每次游戲開始的時候被初始化。另外因為這張地圖不能直接顯示給用戶看,所以我們還需要另一個同樣大小的地圖把它蓋起來。并且也用不同的數(shù)值來表 示一個格是否被翻開,或者被標記等等。這樣每次刷新屏幕我們會根據(jù)地圖上的數(shù)值在屏幕上對應(yīng)的位置顯示不同的圖片,就是我們看到的游戲界面。這種使用多層 地圖的技術(shù)在游戲中非常常見。這兩個地圖可以在同一個二維數(shù)組中,也可以分開兩個數(shù)組,為了便于理解,我們使用兩個數(shù)組分別表示。另外,界面上還要顯示當 前剩余的地雷數(shù)量和游戲時間。剩余地雷數(shù)是地雷總數(shù)減去用戶標記的地雷數(shù),可以是負值。游戲時間是每次新游戲開始時啟動的一個計時器,我們知道,如果要時 間連貫顯示,就必須不停的自動刷新屏幕,但是回顧前面四章的內(nèi)容,并沒有講解如何循環(huán)刷新屏幕,所以在這里會介紹一種使用Handler刷新屏幕的方法, 這種方法比較簡單,但是效率并不高,所以后面我們還會介紹另外一種更有效的方法。接著來看用戶事件的響應(yīng),雖然用戶也可以用鍵盤來操作,但那樣就失去了掃雷游戲追求速度的快感,所以我們只設(shè)計使用觸摸屏的方案。當用戶點擊屏幕 時,首先判斷點擊在哪一格,再根據(jù)用戶點擊的方法,以及被點擊格的狀態(tài),判斷用戶操作的結(jié)果,改變地圖上相應(yīng)格的數(shù)值,刷新后用戶操作的結(jié)果就會在屏幕上 反映出來。另外我們還需要一些游戲狀態(tài)的標志,比如游戲勝利,失敗或是正在游戲中。如果游戲勝利,還需要存儲記錄,由于存儲操作前面沒有講到,我們暫時放棄這個功能。為了縮減篇幅,下面使用源代碼直接講解,源程序的eclipse工程文件已經(jīng)隨本文一起提供下載,這里就算是一個源程序?qū)ёx(在源程序的res/raw目錄下有一首mp3很好聽哦)。首先看Main.javaOverrideprotected void onPause() /* 在程序被掛起或者退出的時候改變游戲狀態(tài)以結(jié)束游戲循環(huán)*/gameView.gameState = GameView.STATE_LOST;super.onPause();這里我們對onPause做一個說明,也是對Android程序生命周期的一個簡單介紹。詳細內(nèi)容會隨著文章的深入慢慢講解。大家知道在pc中,多 個程序是可以同時運行的,即多進程。在手機中,程序依然可以多進程運行,但是還有一些不同:首先是屏幕,當一個應(yīng)用啟動后,他要獨占屏幕。這樣一些有打斷 功能程序運行起來后,當前的程序就不可見了,最簡單的例子就是來電。當你正在游戲,突然有電話打進來,來電程序會占領(lǐng)屏幕,你的游戲轉(zhuǎn)到后臺運行(這時 onPause事件就會被觸發(fā));另一個不同的地方是,如果一個程序被轉(zhuǎn)到后臺太長時間而沒有再次被激活,那么系統(tǒng)會結(jié)束這個程序。在結(jié)束之前會觸發(fā)相應(yīng) 的事件(onSaveInstanceState,后面會介紹)。而與之對應(yīng)的,當程序開始,觸發(fā)onCreate事件時,我們需要檢測當前程序是第一次 運行還是被在后臺銷毀后重新運行,如果是重新運行,我們需要裝載程序銷毀前的狀態(tài)信息。這里我們用onPause的方法并不正確,因為程序掛起的時候不應(yīng)該讓游戲結(jié)束,但是為了簡化代碼,我們暫時先這樣做,后面會加以改進。程序的主要內(nèi)容在GameView.java中,隨本章提供的源代碼中有詳細的注釋,請大家自行閱讀源碼。第六章 SurfaceView動畫前 面介紹的內(nèi)容,還是比較簡單的,應(yīng)用這些知識,可以完成一些非實時游戲,比如井字棋等,或者一些畫面刷新不是很頻繁、實時性不強的游戲,比如我們前面做的 掃雷。但是我們的目標是坦克大戰(zhàn),對操作的實時性要求比較高,更有很多的NPC需要處理,繪圖的工作量也很大,所以我們要用一個新的視圖類 SurfaceView代替View來完成顯示工作。SurfaceView與View有一些不同,但是我們只用其中的一個特性:在主線程之外的線程中向 屏幕上繪圖。這樣就可以避免在畫圖任務(wù)繁重的時候造成主線程阻塞,從而提高程序的反應(yīng)速度。首先讓我們重新定義一個GameView 類,讓他繼承自SurfaceView,并且要實現(xiàn)SurfaceHolder.Callback接口。為什么要實現(xiàn)Callback接口呢?因為使用 SurfaceView有一個原則,所有的繪圖工作必須得在Surface被創(chuàng)建之后才能開始(Surface表面,這個概念在圖形編程中常常被提到。 基本上我們可以把它當作顯存的一個映射,寫入到Surface的內(nèi)容可以被直接復(fù)制到顯存從而顯示出來,這使得顯示速度會非??欤?,而在Surface被 銷毀之前必須結(jié)束。所以Callback中的surfaceCreated和surfaceDestroyed就成了繪圖處理代碼的邊界。我們直接讓 GameView類實現(xiàn)Callback接口,使程序更簡潔一些。GameView被創(chuàng)建,并補充了構(gòu)造函數(shù)之后就是這個樣子(創(chuàng)建類和添加構(gòu)造函數(shù)的方法前面有介紹哦)package org.yexing.android.games.tank;import android.content.Context;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.SurfaceHolder.Callback;public class GameView extends SurfaceView implements Callback public GameView(Context context) super(context);/ TODO Auto-generated constructor stubpublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) / TODO Auto-generated method stubpublic void surfaceCreated(SurfaceHolder arg0) / TODO Auto-generated method stubpublic void surfaceDestroyed(SurfaceHolder arg0) / TODO Auto-generated method stub這 里我們有看到了一個新的類SurfaceHolder,我們權(quán)且把它當作一個Surface的控制器,用它來操作Surface。因為我們現(xiàn)在還不需要直 接操作Surface,所以我們不做深入講解。而唯一要使用的是SurfaceHolder.addCallback,即為SurfaceHolder添 加回調(diào)函數(shù)。原因前面我已經(jīng)說明了,方法如下:public GameView(Context context) super(context);/ TODO Auto-generated constructor stubgetHolder().addCallback(this);現(xiàn)在我們可以運行一下,跟第一次使用View一樣,界面上什么也沒有。因為我們還沒有編寫繪圖的代碼嘛。前面說過,我們之所以使用SurfaceView代替View,是因為SurfaceView可以在主線程之外的線程中進行繪圖操作,從而提高界面的反應(yīng)速度。下面我們要做的就是創(chuàng)建一個用來繪圖的線程。不過在這之前我們可以先了解一些關(guān)于游戲循環(huán)的知識:我 們知道,一般的應(yīng)用程序是用戶驅(qū)動的,就是用戶操作了,程序再來響應(yīng)。而我們的游戲呢,不管用戶有沒有操作,都會有一些變化,最明顯的就是npc會移動、 發(fā)生世界事件等。因此,我們可以說,游戲程序在一個無限循環(huán)當中,我們就把它叫做游戲循環(huán)。那么在游戲循環(huán)中要做哪些工作呢?讓我們用一個流程圖來說明游 戲循環(huán)的過程:這只是我們假設(shè)的流程,不同的游戲肯定會都有些變化。而且細節(jié)上會有更多的差別。了解了游戲循環(huán),下面的工作就是建立一個線程,線程中包含一個游戲循環(huán),在游戲循環(huán)中更新游戲的各種數(shù)據(jù),并根據(jù)這些數(shù)據(jù)將游戲畫面繪制在Surface上最終顯示給玩家。創(chuàng) 建線程的方法很簡單,我們不需要知道Thread的很多高級特性。只需要知道,在線程中完成具體的工作需要重載run()函數(shù)。線程通過start()函 數(shù)啟動。然后就會執(zhí)行run()函數(shù)中的內(nèi)容,run()函數(shù)執(zhí)行結(jié)束后線程就會終止。因此我們將游戲循環(huán)放在run()函數(shù)中。通過start()啟動 循環(huán),并通過適當?shù)姆绞浇Y(jié)束循環(huán)進而結(jié)束整個線程。還要注意一點,所有對Surface的操作都必須要保證同步,因此我們會使用Synchronized 關(guān)鍵字,同步SurfaceHolder。增加了GameThread后的代碼如下:public class GameView extends SurfaceView implements Callback public static final String tag = GameView;/聲明GameThread類實例GameThread gameThread;public GameView(Context context) super(context);/ TODO Auto-generated constructor stub/獲取SurfaceHolderSurfaceHolder surfaceHolder = getHolder();/添加回調(diào)對象surfaceHolder.addCallback(this);/創(chuàng)建GameThread類實例gameThread = new GameThread(surfaceHolder);public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) / TODO Auto-generated method stubLog.v(tag, surfaceChanged);public void surfaceCreated(SurfaceHolder arg0) / TODO Auto-generated method stubLog.v(tag, surfaceCreated);/啟動gameThreadgameThread.start();public void surfaceDestroyed(SurfaceHolder arg0) / TODO Auto-generated method stubLog.v(tag, surfaceDestroyed);/通過結(jié)束run()函數(shù)的方法結(jié)束gameThread,詳見GameThread類的定義gameThread.run = false;/* GameThread的定義* author xingye*/class GameThread extends Thread SurfaceHolder surfaceHolder;/run()函數(shù)中控制循環(huán)的參數(shù)。boolean run = true;public GameThread(SurfaceHolder surfaceHolder) this.surfaceHolder = surfaceHolder;Overridepublic void run() / TODO Auto-generated method stubint i = 0;while(run) Log.v(tag, GameThread);Canvas c = null;try synchronized (surfaceHolder) /我們在屏幕上顯示一個計數(shù)器,每隔1秒鐘刷新一次c = surfaceHolder.lockCanvas();c.drawARGB(255, 255, 255, 255);c.drawText( + i+, 100, 100, new Paint();Thread.sleep(1000); catch (Exception e) / TODO Auto-generated catch blocke.printStackTrace(); finally if (c != null) surfaceHolder.unlockCanvasAndPost(c);運行程序看一下效果從零開始Android游戲編程(第二版) 第七章 精靈、幀動畫與碰撞檢測 收藏 第七章 精靈、幀動畫與碰撞檢測經(jīng)過前幾章的學(xué)習(xí),大 家對使用位圖、接受用戶控制應(yīng)該已經(jīng)有了初步的概念,也可以運用這些知識完成簡單的小游戲。這一章中,我們會為游戲中最重要的部分圖形處理建立一個基 本的框架,這還不是游戲引擎,但是其中很多方法可以為讀者以后創(chuàng)建自己的游戲引擎提供借鑒。這一章的涉及的內(nèi)容比較多,既有2D游戲的基礎(chǔ)理論,又有復(fù)雜 的代碼。尤其是代碼部分,如果詳細講解,恐怕會占用很大的篇幅。所以我們只對關(guān)鍵的函數(shù)進行講解,以方便讀者今后靈活運用這些代碼(所有的源代碼都與本章 節(jié)內(nèi)容一同提供下載)。這個框架是完全依照MIDP中javax.microedition.lcdui.game包設(shè)計的:Classes GameCanvasLayerLayerManagerSpriteTiledLayergame 包中有5個類,其中Layer(層)是一個抽象類,對圖形顯示作了基本的定義。以我們的目標游戲坦克大戰(zhàn)為例,在游戲中有這樣一些圖形元素:我方和敵 方的坦克、坦克發(fā)出的子彈、地面、墻體、水域掩體等。這些元素雖然外觀不同,但是本質(zhì)上卻非常相似:都是在特定位置以特定尺寸顯示一個或一組位圖,有些位 圖位置還會變動,Layer就定義了位置,尺寸,顯示等相關(guān)的功能。之所以叫做Layer,與游戲中分層地圖的概念有關(guān),先讓我們了解一下什么是分層地圖:還是說坦克大戰(zhàn),當我們的坦克行駛在普通地面上時,坦克的圖像肯定是覆蓋了地面的圖像,這樣我們能看到坦克。當坦克行駛到掩體時,我們會發(fā)現(xiàn),掩體的圖像覆蓋了坦克的圖像,如圖所示:實 際上,
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 材料力學(xué)模擬試卷A及答案
- 核酸代謝動力學(xué)-洞察及研究
- 手術(shù)室藥耗品的管理講課件
- 廣東省江門市新會區(qū)2025屆八下英語期末教學(xué)質(zhì)量檢測試題含答案
- 探索新能源驅(qū)動的未來汽車發(fā)展趨勢報告
- 康復(fù)訓(xùn)練中的功能性體能鍛煉
- 投影儀的色彩調(diào)整與畫面優(yōu)化
- 提升國際交流中的教育技術(shù)能力
- 昆理工固體廢物處理與處置教學(xué)大綱
- 2025年護理學(xué)院護理學(xué)試題
- 天津市西青區(qū)2024年七年級下學(xué)期數(shù)學(xué)期末試題附答案
- 《浮力》名師課件
- (高清版)TDT 1012-2016 土地整治項目規(guī)劃設(shè)計規(guī)范
- 網(wǎng)絡(luò)與信息安全管理員(四級)考試題庫附答案
- 2024版《安全生產(chǎn)法》考試題庫附答案(共130題)
- 2024年內(nèi)蒙古北方聯(lián)合電力有限責(zé)任公司招聘筆試參考題庫含答案解析
- 建設(shè)養(yǎng)老院項目計劃書
- 房建工程監(jiān)理大綱范本(內(nèi)容全面)
- 學(xué)校會議室改造項目投標方案(技術(shù)標)
- 兒童樂園安全管理制度
- 【醫(yī)學(xué)課件】外科營養(yǎng)支持
評論
0/150
提交評論