在開發游戲開發中,android相應的提供了幾個重要的模塊:
1、顯示界面的視圖: Android 提供 View 和 SurfaceView
2、控制游戲整體結構: android 提供 Activity
3、邏輯控制類:專門用於處理游戲的邏輯計算
4、處理游戲界面與用戶交互事件 : 利用 View 類提供的 onKeyDown onKeyUp onTounchEvent等方法
我們這裡簡單熟悉一下如何在視圖上畫東西。
1、View 類: android.view.View
View 是Android中的一個超類,這個類幾乎包含了所有的屏幕類型。每一個View都有一個用於繪畫的畫布,這個畫布 可以進行任何擴展。
任何一個View類都只需要重寫onDraw方法來實現界面顯示,任何一個View都只需要重寫 OnDraw 方法來實現界面顯示,自定義的視圖可以是復雜的3D實現,也可以是非常簡單的文本或位圖。
Android 中有個重要的東東: Android UI 線程
在這裡 http://blog.csdn.net/andyhuabing/article/details/11921887 有對其簡要精典的介紹及注意點,這裡就不再重復說明了。
這裡來個簡單例子說明一下View的用法,利用線程變更顯示顏色,通過上下左右移動矩形
TestView.java 類如下:
[java]
package com.example.testondraw;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
/**
* View 是Android中的一個超類,這個類幾乎包含了所有的屏幕類型。每一個View都有一個用於繪畫的畫布,這個畫布 可以進行任何擴展。
*
* 任何一個View類都只需要重寫onDraw方法來實現界面顯示。
*
*/
public class TestView extends View {
int miCount = 0;
int x = 10, y = 10;
public TestView(Context context) {
super(context);
}
@Override
protected 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(x, y, x + 120, y + 80, mPaint);
}
}
如何在 Acitivty 使用呢?示例代碼如下:
[java]
package com.example.testondraw;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
public class MainActivity extends Activity {
static final String TAG = "MainActivity";
private TestView mTestView = null;
private TestSurfaceView mTestSurfaceView = null;
private int mWidth = 0, mHeight = 0;
private MyHandler mHandler = new MyHandler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
startTestView();
// setContentView(R.layout.main);
}
void initView() {
// 使用自定義的View
mTestView = new TestView(this);
setContentView(mTestView);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mWidth = dm.widthPixels;
mHeight = dm.heightPixels;
Log.i(TAG, "Display Metrics width:" + mWidth + " mHeight:" + mHeight);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
void startTestView() {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// 使用postInvalidate可以直接在線程中更新界面
// mTestView.postInvalidate();
// 使用發消息給UI線程
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
});
th.start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
mTestView.invalidate();
break;
default:
break;
}
super.handleMessage(msg);
}
}
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
if (mTestView.y >= mHeight)
mTestView.y = 0;
mTestView.y += 10;
break;
case KeyEvent.KEYCODE_DPAD_UP:
if (mTestView.y <= 0)
mTestView.y = mHeight;
mTestView.y -= 10;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (mTestView.x <= 0)
mTestView.x = mWidth;
mTestView.x -= 10;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (mTestView.x >= mWidth)
mTestView.x = 0;
mTestView.x += 10;
break;
}
return false;
};
}
2、SurfaceView android.view.SurfaceView
當執行效率有要求很高時,View類就無法滿足需求。必須使用 SurfaceView 類 -- 利用雙緩沖技術
使用SurfaceView提供給需要直接畫像素而不是使用畫窗體部件的應用使用。
而每個Surface創建一個Canvas對象,用來管理View在Surface上的繪畫操作。
簡要說明一下具體的方法及使用:
SurfaceHolder 對象需要通過 getHolder() 獲取
在 Layout 上擺一個 SurfaceView 組件:
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
SurfaceHolder holder = mSurfaceView.getHolder();
對於SurfaceView 的創建,銷毀及變更
@SuppressWarnings("unused")
private SurfaceHolder.Callback mSurfaceCbk = new SurfaceHolder.Callback() {
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) { // 在Surface 大小發生變更時觸發
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) { // 在創建 Surface 時觸發
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { // 在銷毀 Surface 時觸發
// TODO Auto-generated method stub
}
};
添加及刪除 SurfaceView 的回調函數:
display.addCallback(mSurfaceCbk);
display.removeCallback(mSurfaceCbk);
Canvas 的使用:
lockCanvas 鎖定畫布,繪圖之前必須鎖定畫布才能得到當前畫布對象
unlockCanvasAndPost 開始繪制時鎖定畫布,繪制完成之後解鎖畫布
下面例子是繪制一個不斷變換顏色的圓,並實現 SurfaceView 的事件處理
TestSurfaceView.java 代碼:
[java]
package com.example.testondraw;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* 使用SurfaceView提供給需要直接畫像素而不是使用畫窗體部件的應用使用。
* 而每個Surface創建一個Canvas對象,用來管理View在Surface上的繪畫操作。
*/
public class TestSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
// 控制循環
private boolean mbLoop = false;
// 定義SurfaceHolder對象
private SurfaceHolder mSurfaceHolder = null;
private int miCount = 0;
public int x = 50, y = 50;
private int mWidth = 1280,mHeight = 720;
private Bitmap mBitmap = null;
public TestSurfaceView(Context context) {
super(context);
// 實例化SurfaceHolder
mSurfaceHolder = this.getHolder();
// 添加回調
mSurfaceHolder.addCallback(this);
this.setFocusable(true);
}
public void setDisplayWH(int w, int h) {
mWidth = w;
mHeight = h;
}
public void setBitmap(Bitmap bitmap) {
this.mBitmap = bitmap;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mbLoop = true;
Thread th = new Thread(new Runnable() {
@Override
public void run() {
while (mbLoop){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized( mSurfaceHolder ){
drawBitmap();
DrawData();
}
}
}
});
th.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mbLoop = false;
}
private void drawBitmap() {
// 鎖定畫布,得到canvas
if (mSurfaceHolder == null || this.mBitmap == null)
return;
Canvas canvas = mSurfaceHolder.lockCanvas();
if (canvas == null) {
return;
}
// 繪圖
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
canvas.drawBitmap(this.mBitmap, 0, 0, paint);
// 繪制後解鎖,繪制後必須解鎖才能顯示
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
// 繪圖方法
private void DrawData() {
if (mSurfaceHolder == null)
return;
// 鎖定畫布,得到canvas
Canvas canvas = mSurfaceHolder.lockCanvas();
if (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, mWidth, mHeight, 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(x, y, 50, mPaint);
// 繪制後解鎖,繪制後必須解鎖才能顯示
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
測試使用例子:
[java]
package com.example.testondraw;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainActivity extends Activity {
static final String TAG = "MainActivity";
private TestSurfaceView mTestSurfaceView = null;
private int mWidth = 0, mHeight = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
startTestSurfaceView();
// setContentView(R.layout.main);
}
void initView() {
// 使用自定義的View
mTestSurfaceView = new TestSurfaceView(this);
setContentView(mTestSurfaceView);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mWidth = dm.widthPixels;
mHeight = dm.heightPixels;
Log.i(TAG, "Display Metrics width:" + mWidth + " mHeight:" + mHeight);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
if (mTestSurfaceView.y >= mHeight)
mTestSurfaceView.y = 0;
mTestSurfaceView.y += 10;
break;
case KeyEvent.KEYCODE_DPAD_UP:
if (mTestSurfaceView.y <= 0)
mTestSurfaceView.y = mHeight;
mTestSurfaceView.y -= 10;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (mTestSurfaceView.x <= 0)
mTestSurfaceView.x = mWidth;
mTestSurfaceView.x -= 10;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (mTestSurfaceView.x >= mWidth)
mTestSurfaceView.x = 0;
mTestSurfaceView.x += 10;
break;
case KeyEvent.KEYCODE_BACK:
this.finish();
break;
}
return false;
};
void startTestSurfaceView() {
mTestSurfaceView.setDisplayWH(mWidth, mHeight);
}
}