- Android游戲開發技術實戰詳解
- 褚尚軍 張加春編著
- 1596字
- 2018-12-30 05:33:20
3.5 游戲框架
大多數知名企業的游戲都是基于Apache Struts、Spring和Hibernate等開發框架的。這些框架都是基于MVC設計模式的,實現了業務和邏輯的分離,這已經成為當前游戲開發的主流模式。本節將簡單分析Android平臺提供的View和Surfaceview類的基本知識。
3.5.1 View類
View視圖類是Android系統中的一個超類,在此類中幾乎包含了所有的屏幕類型。每一個View都有一個用于繪圖的畫布,這個畫布可以進行任意擴展。在游戲開發中也可以自定義View視圖,這個畫布的功能更能滿足我們在游戲開發中的需要。
在Android系統中,任何一個View類都只需重寫onDraw()方法來實現界面顯示,自定義的視圖可以是復雜的3D實現,也可以是非常簡單的文本形式。
在游戲中最重要的就是與玩家的交互,例如,鍵盤輸入、觸筆點擊事件如何來處理呢?在Android中提供了onKeyUp、onKeyDown、onKeyMultiple、onKeyPreIme、onTouchEvent和onTrackballEvent等方法,通過這些方法可以輕松處理游戲中的事件信息。在繼承View時需要重載這幾個方法,當有按鍵按下或彈起事件發生時,按鍵代碼自動會傳輸給這些相應的方法來處理。
游戲的核心功能是不斷繪圖和刷新界面,視圖可以通過onDraw()方法繪制,接下來重點分析如何刷新界面。在Android中提供了invalidate()方法來刷新界面。不能直接在線程中調用方法invalidate(),特別是不能在子線程中調用,因為這違背了Android單線程模型。Android UI操作并不是線程安全的,并且這些操作必須在UI線程中執行,因此Android中最常用的方法就是利用Handler來實現UI線程的更新。
接下來通過一個具體實例,介紹在Android中使用View類實現屏幕更新顯示的方法。
實例3-13 使用View類(daima\3\ViewC)。
在本實例中,要在屏幕上繪制了一個不停變換顏色的矩形,并且定義一些事件來通過模擬器的上下鍵調節矩形的位置(比如把這個矩形向上移動或者把這個矩形向下移動)。本實例的實現文件是ViewC.java,主要代碼如下所示。
public class ViewC extends View { int miCount = 0; int y = 0; public ViewC(Context context) { super(context); } // //繪圖處理 public void onDraw(Canvas canvas) { if (miCount < 100) { miCount++; } else { miCount = 0; } //繪圖 Paint mPaint = new Paint(); switch (miCount%4) { case 0: mPaint.setColor(Color.BLUE); break; case 1: mPaint.setColor(Color.GREEN); break; case 2: mPaint.setColor(Color.RED); break; case 3: mPaint.setColor(Color.YELLOW); break; default: mPaint.setColor(Color.WHITE); break; } //繪制矩形--后面將詳細講解 canvas.drawRect((320-80)/2, y, (320-80)/2+80, y+40, mPaint); } }
執行后將在屏幕內繪制一個矩形,并隨著線程的變化矩形的填充顏色隨之變化,從而實現閃爍效果,如圖3-35所示。通過鍵盤上的上下鍵來移動矩形,如圖3-36所示。

圖3-35 閃爍效果

圖3-36 上下移動矩形
3.5.2 SurfaceView類
類SurfaceView在游戲開發中有著舉足輕重的作用,它對畫面的控制有更大的自由度。SurfaceView類有個雙緩沖機制,在開發游戲時經常用到,提高整個效率。
1. SurfaceView類基礎
在Android中開發游戲時,一般來說,要想寫一個復雜一點的游戲,必須使用SurfaceView來實現。SurfaceView可直接訪問一個可畫圖的界面,可以控制在界面頂部的子視圖層。SurfaceView是提供給需要直接畫像素而不是使用窗體部件的應用使用的。Android圖形系統中的一個重要的概念和線索是Surface(界面)、View(視圖)及其子類,如TextView和Button。
要想在Surface上繪圖。則必須為每個Surface創建一個Canvas對象(但屬性時常改變),用來管理View在Surface上的繪圖操作,如畫點與畫線。還要注意的是,在使用SurfaceView的時候,一般都是出現在最頂層。
在使用SurfaceView的時候,一般情況下還要對創建、銷毀、改變時的情況進行監視,格式如下所示。
//在 surface的大小發生改變時激發 public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){} //在創建時激發,一般在這里調用畫圖的線程 public void surfaceCreated(SurfaceHolder holder){} //銷毀時激發,一般在這里將畫圖的線程停止、釋放 public void surfaceDestroyed(SurfaceHolder holder) {}
surfaceCreated會首先被調用,然后是surfaceChanged,當程序結束時會調用surfaceDestroyed。
由于SurfaceHolder是一個共享資源,所以在對其操作時應該實行“互斥操作”,即需要使用synchronized的“封鎖”機制。
渲染文字的工作實際上是主線程(也就是LunarView類)的父類View的工作,而并不屬于工作線程LunarThread,在工作線程中是無法控制的,所以改為向主線程發送一個Message來代替,讓主線程通過Handler對接收到的消息進行處理,從而更新界面文字信息。
接下來將通過一個具體的實例,介紹在Android中使用SurfaceView類實現屏幕更新顯示的流程。
實例3-14 使用SurfaceView類實現屏幕內容的閃爍顯示(daima\3\SurfaceC)。
本實例的實現文件是SurfaceC.java,具體代碼如下所示。
package com.SurfaceC; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceView; public class SurfaceC extends SurfaceView implements SurfaceHolder.Callback,Runnable { //控制循環 boolean mbLoop = false; //定義SurfaceHolder對象 SurfaceHolder mSurfaceHolder = null; int miCount = 0; int y = 50; public SurfaceC(Context context) { super(context); //實例化SurfaceHolder mSurfaceHolder = this.getHolder(); //添加回調 mSurfaceHolder.addCallback(this); this.setFocusable(true); mbLoop = true; } //在surface的大小發生改變時激發 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } //在surface創建時激發 public void surfaceCreated(SurfaceHolder holder) { //開啟繪圖線程 new Thread(this).start(); } //在surface銷毀時激發 public void surfaceDestroyed(SurfaceHolder holder) { //停止循環 mbLoop = false; } //繪圖循環 public void run() { while (mbLoop) { try { Thread.sleep(200); } catch (Exception e) { } synchronized( mSurfaceHolder ) { Draw(); } } } //繪圖方法 public void Draw() { //鎖定畫布,得到canvas Canvas canvas= mSurfaceHolder.lockCanvas(); if (mSurfaceHolder==null || canvas == null ) { return; } if (miCount < 100) { miCount++; } else { miCount = 0; } //繪圖 Paint mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); //繪制矩形--清屏作用 canvas.drawRect(0, 0, 320, 480, mPaint); switch (miCount % 4) { case 0: mPaint.setColor(Color.BLUE); break; case 1: mPaint.setColor(Color.GREEN); break; case 2: mPaint.setColor(Color.RED); break; case 3: mPaint.setColor(Color.YELLOW); break; default: mPaint.setColor(Color.WHITE); break; } // 繪制矩形--后面將詳細講解 canvas.drawCircle((320 - 25) / 2, y, 50, mPaint); // 繪制后解鎖,繪制后必須解鎖才能顯示 mSurfaceHolder.unlockCanvasAndPost(canvas); } }
執行后將在屏幕內繪制一個圓形,并隨著線程的變化,圓形的填充顏色也隨之變化,從而實現閃爍效果,如圖3-37所示;可以通過鍵盤上的上下鍵來移動圓形,如圖3-38所示。

圖3-37 閃爍效果

圖3-38 上下移動圓形
2. 雙緩沖
雙緩沖的是一種防止動畫閃爍的多線程應用,基于SurfaceView的雙緩沖實現很簡單,只需開一條線程并在其中繪圖即可。Android中的SurfaceView類就基于雙緩沖機制,所以在開發游戲時應盡量使用SurfaceView而不要使用View,這樣效率會較高,而且SurfaceView的功能也更加完善。
雙緩沖的核心是先通過方法setBitmap()將要繪制的所有圖形繪制到一個Bitmap(圖像對象)上,然后調用方法drawBitmap()繪制這個Bitmap,并在屏幕上顯示出來。下面將通過一個具體的實例,講解在Android中使用SurfaceView類實現雙緩沖。
實例3-15 使用雙緩沖技術在屏幕中顯示一幅圖片(daima\3\shuanghuan)。
本實例的實現文件是shuanghuan.java,具體代碼如下所示。
package com.shuanghuan; import com.shuanghuan.R; import Android.content.Context; import Android.graphics.Bitmap; import Android.graphics.Canvas; import Android.graphics.Paint; import Android.graphics.Bitmap.Config; import Android.graphics.drawable.BitmapDrawable; import Android.view.KeyEvent; import Android.view.MotionEvent; import Android.view.View; public class shuanghuan extends View implements Runnable { /* 聲明Bitmap對象 */ Bitmap mBitQQ = null; Paint mPaint = null; /* 創建一個緩沖區 */ Bitmap mSCBitmap = null; /* 創建Canvas對象 */ Canvas mCanvas = null; public shuanghuan(Context context) { super(context); /* 裝載資源 */ mBitQQ = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap(); /* 創建屏幕大小的緩沖區 */ mSCBitmap=Bitmap.createBitmap(320, 480, Config.ARGB_8888); /* 創建Canvas */ mCanvas = new Canvas(); /* 設置將內容繪制在mSCBitmap上 */ mCanvas.setBitmap(mSCBitmap); mPaint = new Paint(); /* 將mBitQQ繪制到mSCBitmap上 */ mCanvas.drawBitmap(mBitQQ, 0, 0, mPaint); /* 開啟線程 */ new Thread(this).start(); } public void onDraw(Canvas canvas) { super.onDraw(canvas); /* 將mSCBitmap顯示到屏幕上 */ canvas.drawBitmap(mSCBitmap, 0, 0, mPaint); } //觸筆事件 public boolean onTouchEvent(MotionEvent event) { return true; } //按鍵按下事件 public boolean onKeyDown(int keyCode, KeyEvent event) { return true; } //按鍵彈起事件 public boolean onKeyUp(int keyCode, KeyEvent event) { return false; } public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { return true; } /*線程處理*/ public void run() { while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } //使用postInvalidate可以直接在線程中更新界面 postInvalidate(); } } }
執行后將用雙緩沖技術在屏幕中顯示圖片,效果如圖3-39所示。

圖3-39 執行效果