




已閱讀5頁,還剩75頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
從零開始學(xué)安卓經(jīng)典教程本文是入門android的經(jīng)典教材,文中既有圖片直觀的展示,又有文字的詳細(xì)說明,并且給出了相應(yīng)代碼,對于初學(xué)者來說是極好的入門材料。 -謹(jǐn)以感謝原作者什么是OPhoneOPhone是基于Linux、面向移動互聯(lián)網(wǎng)的終端基礎(chǔ)軟件及系統(tǒng)解決方案。OPhone SDK是專為OPhone平臺設(shè)計(jì)的軟件開發(fā)套件,它包括OPhone API,OPhone模擬器,開發(fā)工具,示例代碼和幫助文檔(摘自O(shè)Phone官方網(wǎng)站:/)。簡而言之,OPhone是一個移動終端的操作系統(tǒng),移動終端包括手機(jī)、MID、NetBook等等。與其他領(lǐng)域的編程一樣,OPhone編程并沒有什么神秘之處,只需簡單的學(xué)習(xí)就可以掌握大部分的概念。剩下的就是盡情發(fā)揮你的想象力了。寫作本文的目的為了普及OPhone編程的基本知識,并通過復(fù)刻一個坦克大戰(zhàn)游戲讓讀者了解2D游戲編程的簡單思路。文中的程序結(jié)構(gòu)和實(shí)現(xiàn)方法并非最優(yōu),希望能起到一個拋磚引玉的作用,讓更多的人加入到OPhone開發(fā)的行列中來。誰適合閱讀本文雖然本文叫做“從零開始OPhone編程”,但并不能面對那些對編程一無所知的讀者。實(shí)際上,本文要求讀者了解java語言的基本知識,最好會使用eclipse。在文章的每個章節(jié)都標(biāo)有難度,有能力的讀者完全可以跳過相對容易的章節(jié)直接閱讀自己感興趣的內(nèi)容。本文的時效性本文只適合當(dāng)前版本的OPhone SDK(v1.0),本文的代碼、圖片、鏈接可能會因時間推移而失效。第一章 搭建開發(fā)環(huán)境工欲善其技,必先利其器。我們要做的第一件事就是搭建Android開發(fā)環(huán)境。本文只介紹Windows下的安裝方法,Linux下的安裝方法請參考官方網(wǎng)站的介紹。與PC編程略有不同的是,Android的程序需要在模擬器中運(yùn)行。因此,我們需要一個集成開發(fā)環(huán)境,一個SDK和一個模擬器。因?yàn)锳ndroid編程使用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(當(dāng)然,如果你不能翻墻,可以到國內(nèi)的網(wǎng)站下載),SDK全部安裝完畢之后,還需要安裝eclipse插件。插件是用來擴(kuò)展eclipse功能的。 開發(fā)Android用的插件叫ADT(Android Developer Tools),它可以幫助我們完成創(chuàng)建項(xiàng)目,向模擬器部署并運(yùn)行程序,調(diào)試程序等工作。關(guān)于ADT的功能,在后面使用中我們會逐漸熟悉。安裝ADT的方法如下(以eclipse3.4為例):啟動eclipse,選擇菜單中的Help - Software Updates點(diǎn)擊Add Site點(diǎn)擊Archive找到OPhone SDK安裝目錄下toolsophone ADT-0.8.0.zip(因?yàn)槲乙呀?jīng)安裝好了ADT,所以出現(xiàn)了重復(fù)URL的提示),點(diǎn)擊OK即可開始安裝ADT安裝完畢后還要簡單配置一下,打開菜單中的Window - Preferences找到Android項(xiàng),通過Browse按鈕指定Android SDK的安裝位置至此為止,Android的安裝環(huán)境就全部搭建完畢了。下一章節(jié),我們會遇見經(jīng)典的helloworld,下章見!第二章 創(chuàng)建第一個程序Hello Tank現(xiàn)在開始,我們要真正寫作Android程序了。雖然前面安裝過程那么復(fù)雜,但是寫起程序來卻是非常簡單。而且為了讓大家有一個直觀的認(rèn)識,本文不會敘述大段的原理,而是在編碼的過程中滲透對原理、概念的講解。讓我們打開eclipse,選擇菜單中的File - New - Project選擇Android - Android Project下面需要我們輸入項(xiàng)目的一些信息,因?yàn)槲覀円獜?fù)刻經(jīng)典游戲坦克大戰(zhàn),所以我們的程序就取名Tank這樣,一個Android項(xiàng)目就創(chuàng)建完成了,我們可以在eclipse的Package Explorer看到我們的項(xiàng)目托ADT的福,雖然我們只輸入了幾個名字,但這個項(xiàng)目實(shí)際上已經(jīng)可以運(yùn)行了。右擊項(xiàng)目名,選擇Run As - Android Application不出意外的話,你會看到一個手機(jī)模擬器被啟動,而我們剛剛建立的程序會被運(yùn)行起來如 果你發(fā)現(xiàn)模擬器啟動了,而程序并沒有被運(yùn)行,可能需要手工啟動程序。這里我們用到一個重要的工具DDMS(Davlik Debug Manager)。運(yùn)行DDMS快捷方法是點(diǎn)擊eclipse右上角的Open Perspective,如果在彈出的列表中沒有DDMS,那么點(diǎn)擊Others選擇DDMS這樣我們就打開了DDMS界面,這個工具我們以后會經(jīng)常用到。剛剛說到模擬器啟動了而程序并沒有被運(yùn)行,很可能是在模擬器啟動過程中DDMS失去了與模擬器的鏈接。解決方法很簡單:點(diǎn)擊Devices標(biāo)簽下的工具欄,選擇Reset adb然后右擊項(xiàng)目名稱,Run As - Android Application。除了右擊運(yùn)行項(xiàng)目,還可以通過工具欄上的運(yùn)行按鈕啟動程序在運(yùn)行按鈕左邊的是Debug按鈕,這兩個我們以后也會經(jīng)常用到。現(xiàn) 在我們已經(jīng)有了第一個可以運(yùn)行的Android,雖然你可能對ADT生成的一堆文件感到一頭霧水,也不知道程序界面上那一句“Hello World, Main”是從哪里來的,但是沒關(guān)系,隨著本文的深入你會逐漸熟悉Android項(xiàng)目的目錄結(jié)構(gòu),程序設(shè)計(jì)的原則和方法,以及調(diào)試和部署的方法?,F(xiàn)在讀者 可以自己熟悉一下模擬器的操作,讓我們下章再見。第三章 顯示文字和圖片從 本章開始,讀者就要編寫代碼了。按照作者的原則少一些理論,多一些實(shí)踐,代碼中可能會有跳躍的地方。但是請大家不要著急,隨著學(xué)習(xí)的深入,你很快就會 了解其中的奧秘。不過在開始之前,我們還是要先來理順一下思路,看看完成一個坦克大戰(zhàn)游戲需要哪些工作:首先,我們需要一個基本的程序,這個程序能夠在 Android上運(yùn)行;這個程序要能夠顯示圖形包括地圖,主角和NPC等等;程序能夠接受用戶的輸入,控制主角移動;程序要能夠控制NPC和子彈的移動; 程序還能對各種事件做出判斷,比如擊中敵人,獲得物品,勝利或者失敗?,F(xiàn)在我們就從基本程序開始,一步一步實(shí)現(xiàn)它。首先,讓我們看一下剛剛生成的文件目錄在源文件目錄下,只有Main.java和R.java兩個文件,剛剛被我們命名成Main.java的文件就是程序的入口文件。而R.java是由插件來維護(hù)的資源定義文件,我們先不管它。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);很 幸運(yùn),Main.java的代碼非常之少,而且還有一段注釋,以致我們很容易知道函數(shù)onCreate的作用,需要解釋的只是 setContentView()。先不要管注釋中提到的Activity和setContentView的參數(shù)R.layout.main,我們使用 setContentView的另一種形式:setContentView(View view)。setContentView的作用是設(shè)定當(dāng)前使用的視圖即View(依此理解,可以有很多個View,需要用哪個就可以把他作為 setContentView的參數(shù)顯示出來)。View是一個非常重要的組件,它可以用來顯示文字,圖片,也可以接收客戶的操作,比如觸摸屏,鍵盤等 等,而我們的游戲中正是需要繪圖和交互,看來View很符合我們的需要(但是請注意,使用View并不是我們的最終方案,原因會在后面說明。此處介紹 View是為了講解基礎(chǔ)的圖形和用戶控制)。下面我們就要訂制一個屬于自己的View,可以通過繼承自系統(tǒng)提供的View,并重載相關(guān)的函數(shù)來實(shí)現(xiàn)。創(chuàng)建類的方法如下:右擊包名 New - Class我們將這個View類命名為GameView,并且由android.view.View繼承點(diǎn) 擊Finish,一個View類就創(chuàng)建好了。這里是第一次創(chuàng)建類,以后就不會有圖片演示了,請大家記住的這個方法。GameView創(chuàng)建好了,但是代碼還 有一些錯誤,這里介紹一下eclipse的使用技巧,將鼠標(biāo)懸停在有錯誤的位置,或者將光標(biāo)停在有錯誤的行,然后按Ctrl+1鍵,就會出現(xiàn)修改建議,大 部分時候,使用修改建議都可以改正我們的錯誤,如圖可以看出來,剛剛的錯誤是因?yàn)闆]有創(chuàng)建構(gòu)造函數(shù),選擇修改建議的第二項(xiàng),增加一個構(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)在讓我們運(yùn)行模擬器,看看程序變成什么樣子了(啟動模擬器的方法見第二章)。不要意外,屏幕上就是一片空白,因?yàn)槲覀儎?chuàng)建了一個View,但是沒有讓它顯示任何內(nèi)容。下面我們就會在View上顯示一段文字和一張圖片。讓View顯示內(nèi)容也很簡單,只需要重載View的onDraw函數(shù),把相應(yīng)的語句寫入onDraw中即可。打開GameView.java,點(diǎn)擊菜單 Source - Override/Implement Method選中onDraw點(diǎn)擊OK下面這段代碼就會被加入到程序當(dāng)中,所有與顯示有關(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)在了屏幕上。讓我們來詳細(xì)看一下這條語句:canvas.drawText(坦克大戰(zhàn), 50, 50, new Paint();第 一個參數(shù)是要顯示的文字,第二、第三個參數(shù)是文字在屏幕上的坐標(biāo),說到坐標(biāo)得多講兩句。在2D編程中,屏幕坐標(biāo)的原點(diǎn)是屏幕的左上角,橫向向右增大,縱向 向下增大,如上圖所示。最后一個參數(shù)是Paint,通常翻譯成畫筆,它決定了文字或圖形的顏色,字體,線條粗細(xì)等等,后面用到相應(yīng)屬性的時候會詳細(xì)介紹。 那么這條語句就是在屏幕上(50,50)的位置用缺省的畫筆寫出“坦克大戰(zhàn)”四個字。另外如果eclipse提示代碼錯誤,不要忘了用Ctrl+1。有了文字,下面就是圖像了。顯示圖像比顯示文字略微復(fù)雜一些,首先我們要準(zhǔn)備一張位圖,圖片必須是png格式的,文件名只能是小寫字母,數(shù)字和下劃線。battlecity.png然后將這張圖片copy到工程的res/drawable目錄下。可以直接在eclipse的目錄樹中粘貼。顯示位圖的函數(shù)是Canvas.drawBitmap(),drawBitmap有很多種形態(tài),我們先看其中最簡單的一種canvas.drawBitmap(bitmap, left, top, paint)乍 一看似乎和drawText差不多,4個參數(shù)有三個都相同,但這第一個參數(shù)bitmap要比文本復(fù)雜得多。首先,他是一個Bitmap類實(shí)例,因?yàn)槲覀儸F(xiàn) 在還不需要這個類的其他功能,所以不過多介紹Bitmap,只考慮它是怎么來的。得到Bitmap實(shí)例的方法也有很多種,這里只介紹其中的一種BitmapFactory.decodeResource(res, id);此 方法可以返回一個bitmap實(shí)例,但是這個函數(shù)還需要兩個參數(shù)res和id。res是Resources實(shí)例,而id是一個整數(shù),下面讓我們分別了解這 兩個參數(shù)。res的地位跟bitmap差不多,只需要作為參數(shù)被使用,因此,只要得到實(shí)例就可以了,獲得Resources實(shí)例的方法如下:res = context.getResources();天哪,事情越來越復(fù)雜了,因?yàn)檫@段代碼里面有多了一個陌生面孔context。context是Context實(shí)例,Context通常翻譯做上下文,這個名稱似乎有點(diǎn)晦澀,他究竟是什么呢?讓我們回頭看看寫好的程序public GameView(Context context) super(context);/ TODO Auto-generated constructor stub這時候我們有一個context實(shí)例,繼續(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實(shí)例。R.layout.main就是一個整數(shù)。它被定義在文件R.java中,我們前面講過R.java是由插件維護(hù)的資源定義文件。說到這里大家應(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ùn)行效果第四章 響應(yīng)用戶事件上一章介紹了如何顯示文字和圖片,一般來說,下一步就該講到動畫了。可是我們前面說了,使用View不是最終的選擇,要實(shí)現(xiàn)動畫還需要很多復(fù)雜的代碼。相對來說,學(xué)習(xí)如何響應(yīng)用戶事件要簡單些。本章前半部分講解按鍵事件的響應(yīng),但是這也不是最終方案,因?yàn)閷?shí)際上的手機(jī)可能沒有硬鍵盤,需要使用虛擬鍵盤,所以后半部分我們會講解虛擬鍵盤的設(shè)計(jì)和實(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ù)。 比如用戶按下右方向鍵,我們就把橫坐標(biāo)增加,這樣下次顯示出來的時候,主角就會往右一點(diǎn)。為了節(jié)約時間,我們就把剛剛顯示的圖片BattleCity作為 主角好了。首先定義兩個全局變量x和y,然后在onKeyDown中改變x、y的值,然后重繪View。因?yàn)榇a沒有什么難度,所以不做講解了。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被顯示時,缺省情況下沒有獲得焦點(diǎn),就是說,按鍵動作沒有發(fā)送給View,所以需要在構(gòu)造函數(shù)中增加一句public GameView(Context context) setFocusable(true);再運(yùn)行程序,看看圖片是否按照我們的指令運(yùn)動起來了。前 面說過,很多手機(jī)沒有硬鍵盤,所以我們需要一個軟鍵盤的解決方案。軟鍵盤就是在屏幕上顯示一個鍵盤,然后響應(yīng)用戶的觸摸屏操作,模擬成鍵盤操作。對于坦克 大戰(zhàn),我們只需要在屏幕上顯示一個模擬的游戲手柄(顯示圖片的方法大家沒有忘記吧,顯示位置可以根據(jù)模擬器自行調(diào)整):在用戶觸摸模擬手柄上的方向鍵和開火鍵時進(jìn)行相應(yīng)的操作。我們拿方向鍵做演示,步驟如下:首先確定四個方向鍵在屏幕上的區(qū)域(上圖的紅色方框),然后在觸摸屏事件的響應(yīng)函數(shù)中判斷事件是否發(fā)生在方向鍵區(qū)域中,最后如果事件發(fā)生在區(qū)域中進(jìn)行相應(yīng)的操作。下 面,我們引入一個非常有用的類Rect(RectF與Rect基本相同,不過以float作為坐標(biāo)參數(shù)),rect是rectangle的簡寫,顧名思 義,這個類代表了一個矩形。Rect通過矩形4個邊來定義這個矩形的范圍。他們分別是left,right,top,bottom,如圖所示:轉(zhuǎn) 化為屏幕坐標(biāo),top是矩形坐上角的縱坐標(biāo),left是矩形坐上角的橫坐標(biāo),right是矩形右下角的橫坐標(biāo),buttom是右下角的縱坐標(biāo)。有了 Rect我們就可以方便的表示虛擬手柄各個鍵的位置。同時Rect還提供了一些很有用的函數(shù),其中Rect.contains(x, y)能夠判斷點(diǎn)(x, y)是否在矩形框中,正好是我們需要的。現(xiàn)在我們就可以開始編碼了,首先為虛擬鍵盤的方向鍵創(chuàng)建Rect(可以用繪圖工具測量坐標(biāo)):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);下面我們要做的是,首先判斷觸摸屏操作是不是按下,如果是,取得坐標(biāo)(x,y),然后判斷坐標(biāo)所在的按鍵,做出相應(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ùn)行一下,每次用鼠標(biāo)點(diǎn)擊模擬手柄的方向鍵,圖片就會移動至此為止,我們介紹了兩種響應(yīng)用戶事件的手段,但是要真正完成對一個游戲的控制,還需要更多的工作,后面還有深入的講解。第五章 小結(jié)掃雷游戲的實(shí)現(xiàn)目前,我們學(xué)習(xí)了如何建立Android編程環(huán)境,如何顯示文字和圖片,如何響應(yīng)用戶事件。作為總結(jié),我們要運(yùn)用這些知識實(shí)現(xiàn)一個掃雷游戲。先說游戲規(guī)則:掃雷,就是在一個分成若干小格的矩形區(qū)域中發(fā)現(xiàn)隱藏的地雷,找到它,但是不能觸發(fā)它。每次翻開一個小格,如果下面是地雷,游戲就失敗 了。如果不是地雷,而它的周圍8個格中有地雷,那么就會顯示周圍的地雷數(shù)。如果周圍8個格中沒有地雷,那就是空白的。如果你認(rèn)為某一格是地雷可以用紅旗標(biāo) 記它,正確標(biāo)記了所有的地雷或者翻開了所有不是地雷的格就取得勝利。再說用戶操作:在Windows中用戶可以有三種操作,左鍵單擊,右鍵單擊,左右鍵同時單擊。左鍵可以翻開一個小格,可以觸雷,如果點(diǎn)到了一個空白 格,跟它相聯(lián)的所有空白格都會被打開。右鍵可以標(biāo)記一個格,不會觸雷,標(biāo)記方式有兩種,第一次單擊用紅旗標(biāo)記,確信此處有雷,再次單擊紅旗變成問號,表示 可能有雷。左右鍵同時單擊只在此種情況有效,即一個格周圍有雷,并且所有的雷都已被用紅旗標(biāo)記出來。此時單擊此格會打開周圍所有未標(biāo)記的格,此操作會觸 雷,就是說如果標(biāo)記錯了游戲就會失敗,所以一定要小心使用。因?yàn)樵谑謾C(jī)上沒有右鍵,所以我們必須設(shè)計(jì)替代方案,一種方法是設(shè)計(jì)一個開關(guān)圖標(biāo),點(diǎn)擊打開開關(guān) 后,所有的操作都被認(rèn)為是右鍵和左右鍵同時單擊,另外還可以借助手機(jī)上的菜單鍵,按住菜單鍵等同打開開關(guān),松開等同關(guān)閉開關(guān)。為了方便游戲,我們可以同時 實(shí)現(xiàn)兩個方案。最后讓我們分析一下程序的大體思路,從最直觀的用戶界面開始,我們需要根據(jù)游戲的顯示區(qū)域創(chuàng)建游戲地圖,一個m行n列的二維整形數(shù)組,數(shù)組中的一個 值對應(yīng)界面上的一個格,不同的數(shù)值可以表示不同的狀態(tài),比如0表示空白格,1表示此格周圍有一個雷,2表示有兩個雷等等。因?yàn)槔椎奈恢檬请S機(jī)的,所以這張 地圖需要在每次游戲開始的時候被初始化。另外因?yàn)檫@張地圖不能直接顯示給用戶看,所以我們還需要另一個同樣大小的地圖把它蓋起來。并且也用不同的數(shù)值來表 示一個格是否被翻開,或者被標(biāo)記等等。這樣每次刷新屏幕我們會根據(jù)地圖上的數(shù)值在屏幕上對應(yīng)的位置顯示不同的圖片,就是我們看到的游戲界面。這種使用多層 地圖的技術(shù)在游戲中非常常見。這兩個地圖可以在同一個二維數(shù)組中,也可以分開兩個數(shù)組,為了便于理解,我們使用兩個數(shù)組分別表示。另外,界面上還要顯示當(dāng) 前剩余的地雷數(shù)量和游戲時間。剩余地雷數(shù)是地雷總數(shù)減去用戶標(biāo)記的地雷數(shù),可以是負(fù)值。游戲時間是每次新游戲開始時啟動的一個計(jì)時器,我們知道,如果要時 間連貫顯示,就必須不停的自動刷新屏幕,但是回顧前面四章的內(nèi)容,并沒有講解如何循環(huán)刷新屏幕,所以在這里會介紹一種使用Handler刷新屏幕的方法, 這種方法比較簡單,但是效率并不高,所以后面我們還會介紹另外一種更有效的方法。接著來看用戶事件的響應(yīng),雖然用戶也可以用鍵盤來操作,但那樣就失去了掃雷游戲追求速度的快感,所以我們只設(shè)計(jì)使用觸摸屏的方案。當(dāng)用戶點(diǎn)擊屏幕 時,首先判斷點(diǎn)擊在哪一格,再根據(jù)用戶點(diǎn)擊的方法,以及被點(diǎn)擊格的狀態(tài),判斷用戶操作的結(jié)果,改變地圖上相應(yīng)格的數(shù)值,刷新后用戶操作的結(jié)果就會在屏幕上 反映出來。另外我們還需要一些游戲狀態(tài)的標(biāo)志,比如游戲勝利,失敗或是正在游戲中。如果游戲勝利,還需要存儲記錄,由于存儲操作前面沒有講到,我們暫時放棄這個功能。為了縮減篇幅,下面使用源代碼直接講解,源程序的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程序生命周期的一個簡單介紹。詳細(xì)內(nèi)容會隨著文章的深入慢慢講解。大家知道在pc中,多 個程序是可以同時運(yùn)行的,即多進(jìn)程。在手機(jī)中,程序依然可以多進(jìn)程運(yùn)行,但是還有一些不同:首先是屏幕,當(dāng)一個應(yīng)用啟動后,他要獨(dú)占屏幕。這樣一些有打斷 功能程序運(yùn)行起來后,當(dāng)前的程序就不可見了,最簡單的例子就是來電。當(dāng)你正在游戲,突然有電話打進(jìn)來,來電程序會占領(lǐng)屏幕,你的游戲轉(zhuǎn)到后臺運(yùn)行(這時 onPause事件就會被觸發(fā));另一個不同的地方是,如果一個程序被轉(zhuǎn)到后臺太長時間而沒有再次被激活,那么系統(tǒng)會結(jié)束這個程序。在結(jié)束之前會觸發(fā)相應(yīng) 的事件(onSaveInstanceState,后面會介紹)。而與之對應(yīng)的,當(dāng)程序開始,觸發(fā)onCreate事件時,我們需要檢測當(dāng)前程序是第一次 運(yùn)行還是被在后臺銷毀后重新運(yùn)行,如果是重新運(yùn)行,我們需要裝載程序銷毀前的狀態(tài)信息。這里我們用onPause的方法并不正確,因?yàn)槌绦驋炱鸬臅r候不應(yīng)該讓游戲結(jié)束,但是為了簡化代碼,我們暫時先這樣做,后面會加以改進(jìn)。程序的主要內(nèi)容在GameView.java中,隨本章提供的源代碼中有詳細(xì)的注釋,請大家自行閱讀源碼。第六章 SurfaceView動畫前 面介紹的內(nèi)容,還是比較簡單的,應(yīng)用這些知識,可以完成一些非實(shí)時游戲,比如井字棋等,或者一些畫面刷新不是很頻繁、實(shí)時性不強(qiáng)的游戲,比如我們前面做的 掃雷。但是我們的目標(biāo)是坦克大戰(zhàn),對操作的實(shí)時性要求比較高,更有很多的NPC需要處理,繪圖的工作量也很大,所以我們要用一個新的視圖類 SurfaceView代替View來完成顯示工作。SurfaceView與View有一些不同,但是我們只用其中的一個特性:在主線程之外的線程中向 屏幕上繪圖。這樣就可以避免在畫圖任務(wù)繁重的時候造成主線程阻塞,從而提高程序的反應(yīng)速度。首先讓我們重新定義一個GameView 類,讓他繼承自SurfaceView,并且要實(shí)現(xiàn)SurfaceHolder.Callback接口。為什么要實(shí)現(xiàn)Callback接口呢?因?yàn)槭褂?SurfaceView有一個原則,所有的繪圖工作必須得在Surface被創(chuàng)建之后才能開始(Surface表面,這個概念在圖形編程中常常被提到。 基本上我們可以把它當(dāng)作顯存的一個映射,寫入到Surface的內(nèi)容可以被直接復(fù)制到顯存從而顯示出來,這使得顯示速度會非??欤?,而在Surface被 銷毀之前必須結(jié)束。所以Callback中的surfaceCreated和surfaceDestroyed就成了繪圖處理代碼的邊界。我們直接讓 GameView類實(shí)現(xiàn)Callback接口,使程序更簡潔一些。GameView被創(chuàng)建,并補(bǔ)充了構(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)且把它當(dāng)作一個Surface的控制器,用它來操作Surface。因?yàn)槲覀儸F(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)在我們可以運(yùn)行一下,跟第一次使用View一樣,界面上什么也沒有。因?yàn)槲覀冞€沒有編寫繪圖的代碼嘛。前面說過,我們之所以使用SurfaceView代替View,是因?yàn)镾urfaceView可以在主線程之外的線程中進(jìn)行繪圖操作,從而提高界面的反應(yīng)速度。下面我們要做的就是創(chuàng)建一個用來繪圖的線程。不過在這之前我們可以先了解一些關(guān)于游戲循環(huán)的知識:我 們知道,一般的應(yīng)用程序是用戶驅(qū)動的,就是用戶操作了,程序再來響應(yīng)。而我們的游戲呢,不管用戶有沒有操作,都會有一些變化,最明顯的就是npc會移動、 發(fā)生世界事件等。因此,我們可以說,游戲程序在一個無限循環(huán)當(dāng)中,我們就把它叫做游戲循環(huán)。那么在游戲循環(huán)中要做哪些工作呢?讓我們用一個流程圖來說明游 戲循環(huán)的過程:這只是我們假設(shè)的流程,不同的游戲肯定會都有些變化。而且細(xì)節(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),并通過適當(dāng)?shù)姆绞浇Y(jié)束循環(huán)進(jìn)而結(jié)束整個線程。還要注意一點(diǎn),所有對Surface的操作都必須要保證同步,因此我們會使用Synchronized 關(guān)鍵字,同步SurfaceHolder。增加了GameThread后的代碼如下:public class GameView extends SurfaceView implements Callback public static final String tag = GameView;/聲明GameThread類實(shí)例GameThread gameThread;public GameView(Context context) super(context);/ TODO Auto-generated constructor stub/獲取SurfaceHolderSurfaceHolder surfaceHolder = getHolder();/添加回調(diào)對象surfaceHolder.addCallback(this);/創(chuàng)建GameThread類實(shí)例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) /我們在屏幕上顯示一個計(jì)數(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);運(yùn)行程序看一下效果從零開始Android游戲編程(第二版) 第七章 精靈、幀動畫與碰撞檢測 收藏 第七章 精靈、幀動畫與碰撞檢測經(jīng)過前幾章的學(xué)習(xí),大 家對使用位圖、接受用戶控制應(yīng)該已經(jīng)有了初步的概念,也可以運(yùn)用這些知識完成簡單的小游戲。這一章中,我們會為游戲中最重要的部分圖形處理建立一個基 本的框架,這還不是游戲引擎,但是其中很多方法可以為讀者以后創(chuàng)建自己的游戲引擎提供借鑒。這一章的涉及的內(nèi)容比較多,既有2D游戲的基礎(chǔ)理論,又有復(fù)雜 的代碼。尤其是代碼部分,如果詳細(xì)講解,恐怕會占用很大的篇幅。所以我們只對關(guān)鍵的函數(shù)進(jìn)行講解,以方便讀者今后靈活運(yùn)用這些代碼(所有的源代碼都與本章 節(jié)內(nèi)容一同提供下載)。這個框架是完全依照MIDP中javax.microedition.lcdui.game包設(shè)計(jì)的:Classes GameCanvasLayerLayerManagerSpriteTiledLayergame 包中有5個類,其中Layer(層)是一個抽象類,對圖形顯示作了基本的定義。以我們的目標(biāo)游戲坦克大戰(zhàn)為例,在游戲中有這樣一些圖形元素:我方和敵 方的坦克、坦克發(fā)出的子彈、地面、墻體、水域掩體等。這些元素雖然外觀不同,但是本質(zhì)上卻非常相似:都是在特定位置以特定尺寸顯示一個或一組位圖,有些位 圖位置還會變動,Layer就定義了位置,尺寸,顯示等相關(guān)的功能。之所以叫做Layer,與游戲中分層地圖的概念有關(guān),先讓我們了解一下什么是分層地圖:還是說坦克大戰(zhàn),當(dāng)我們的坦克行駛在普通地面上時,坦克的圖像肯定是覆蓋了地面的圖像,這樣我們能看到坦克。當(dāng)坦克行駛到掩體時,我們會發(fā)現(xiàn),掩體的圖像覆蓋了坦克的圖像,如圖所示:實(shí) 際上,
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 語音識別試題及答案
- 阿里定級面試題及答案
- 房地產(chǎn)銷售策略與實(shí)戰(zhàn)
- 2025年 道真自治縣“特崗計(jì)劃”教師招聘考試筆試試卷附答案
- 員工安全培訓(xùn)手冊
- 2025年中國噴氣背包行業(yè)市場全景分析及前景機(jī)遇研判報告
- 2025年中國內(nèi)衣褲洗衣機(jī)行業(yè)市場全景分析及前景機(jī)遇研判報告
- 急救培訓(xùn)圓滿畢業(yè)
- 住院患者護(hù)理風(fēng)險評估制度
- 腫瘤晚期患者教育
- 抖音精準(zhǔn)圈層種草
- 店面運(yùn)營手冊(店面布置與陳列)
- 裝修申請書模板
- 四川水電站建設(shè)用地地質(zhì)災(zāi)害危險性評估報告
- 建筑電氣設(shè)計(jì)技術(shù)規(guī)程
- 公開招標(biāo)招標(biāo)文件范本
- (完整版)OEE記錄表格(設(shè)備綜合效率)
- 智慧燃?xì)獍踩O(jiān)管平臺解決方案
- 鋼結(jié)構(gòu)檢測專項(xiàng)方案(33頁)
- 人教版小學(xué)三年級下冊英語復(fù)習(xí)課件(164頁P(yáng)PT)
- 300MW單元機(jī)組過熱汽溫控制系統(tǒng)的設(shè)計(jì)
評論
0/150
提交評論