天天看点

Android游戏开发(一) SurfaceView游戏框架

最近准备写一个RPG游戏,一开始决定用AndEngine引擎写,刚开始写点尝试代码时发现使用起来很不舒服,我还不太习惯OpenGl ES,想加点自己的东西总弄的代码非常难看,最后决定还是采用Android提供的标准绘图接口来实现,这一系列的博文记录了开发过程中遇到的问题和解决办法。

(一) 绘图框架的建立

游戏图像显示在一个SufaceView中,要用SufaceView进行绘图,首先要写自己的SufaceView继承SufaceView 并实现SurfaceHolder.Callback接口,然后在启动一个线程不断去绘制图像,绘制分两步,第一步把游戏图像绘制到一个和屏幕等大小的BItmap对象上,第二步在把Bitmap对象绘制到屏幕上。这是因为CPU访问内存速度比访问屏幕速度快很多,直接绘制到屏幕上会消耗更多时间。这也是游戏开发中常用的双缓冲技术,具体代码如下。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class GameSurfaceView extends SurfaceView implements Callback,Runnable{

	public static int width;
	public static int height;
	private SurfaceHolder holder;
	private Bitmap bitmap;
	private Canvas mCanvas;
	private Paint paint;
	private Thread gameThread;
	private Boolean flag;
	int i = 0;
	
	
	public GameSurfaceView(Context context, AttributeSet attrs) {
			super(context, attrs);
			holder = this.getHolder();
			holder.addCallback(this);
			flag = false;
			this.setFocusable(true);
	}
	
	@Override
	public void run() {
		while(flag){
			onlogic();
			ondraw();
			drawBitmap();
			try {
				Thread.sleep(30);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void onlogic() {
		
	}
	
	private void ondraw() {
		mCanvas.drawRGB(255, 255, 255);
	}

	private void drawBitmap() {
		Canvas canvas = holder.lockCanvas();
		try {
			if(canvas != null){
				canvas.drawBitmap(bitmap, 0, 0, paint);
			}
		} catch (Exception e) {
		}finally{
				holder.unlockCanvasAndPost(canvas);
		}
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
		width = this.getWidth();
		height = this.getHeight();
		Log.i("wh", width + "=" + height);
		bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		mCanvas = new Canvas(bitmap);
		paint = new Paint();
		paint.setColor(Color.YELLOW);
		flag = true;
		
		gameThread = new  Thread(this);
		gameThread.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		flag = false;
	}


}
           

(二) 屏幕适应

Android手机的分辨率各种各样,屏幕适应是一个必须要解决的问题,为了使游戏在不同分辨率的手机上运行效果一样,我想到了下面一种办法,首先固定长宽比,类似AndEngine中的Camera。

private static float cameraWidth = 800;   //预设尺寸
private static float cameraHeight = 480;
	
           

绘图所用的缓冲BItmap的长宽固定为上面的数值,然后在每次绘制Bitmap到屏幕上时根据屏幕实际尺寸和Bitmap的尺寸进行缩放或伸展,具体代码如下。

private void drawBitmap() {
		Canvas canvas = holder.lockCanvas();
		try {
			if (canvas != null) {
				Matrix matrix = new Matrix(); // 屏幕适应
				matrix.setScale(width / cameraWidth, height / cameraHeight);
				canvas.drawBitmap(bitmap, matrix, paint);
			}
		} catch (Exception e) {
		} finally {
			if (holder != null && canvas != null) {
				holder.unlockCanvasAndPost(canvas);
			}
		}
	}
           

这样问题解决了。