您的位置:首页 > 移动开发 > Android开发

Android学习笔记:使用SurfaceView制作简单游戏(1)

2015-12-31 18:36 776 查看
这次准备把以前在Windows上玩过的一个小游戏《潜艇大战》在Android上实现,这个游戏的Windows版大概是这个样子的


这部分先实现创建玩家船只,并通过按键对其进行控制,效果图:



中间绿色的方块代表玩家的船只,之后会替换成船只贴图,按住L或R键控制船只左右移动,当船只触碰到边缘时停止移动。使用的主要工具是SurfaceView类。按开发文档介绍以及网上的资料,SurfaceView类是View类的子类,并且有一些新特性,主要是允许另外一个线程来对屏幕(screen)进行渲染(render),而View类对屏幕进行渲染和响应用户指令使用同一个线程,当这个线程被阻塞时,画面的更新也会受影响。游戏本身就是一直在对画面进行更新,比如每秒30/60次(帧),使用SurfaceView是比较合适的。下面把关键步骤记录下来,顺便整理一下思路。

1.创建一个自定义的GameView类,继承SurfaceView,注意要实现SurfaceHolder.Callback接口,同时也实现了Runnable接口,因为我们需要一个线程来不断的刷新屏幕。GameView类中处构造函数外,还有3个默认的方法,分别在GameView对象创建,改变和销毁时被调用。对SurfaceView的操作需要通过SufaceHolder,在构造函数中通过getHolder()来获得一个对象。代码如下:

public class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder surfaceHolder;
private Canvas canvas;
public GameView(Context context) {
super(context);
surfaceHolder = this.getHolder(); // 获取SurfaceHolder对象
surfaceHolder.addCallback(this); // 添加回调
}

public void surfaceCreated(SurfaceHolder holder) {

}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {

}

public void surfaceDestroyed(SurfaceHolder holder) {

}

}


2.定义一些必要的变量,定义xPos和yPos两个变量来确定船的位置。为了让船只出现在屏幕适当的位置,需要知道屏幕的宽度和高度,Android系统中,屏幕左上角为坐标原点(0,0),x轴向右增长,y轴向下增长。在surfaceCreated(SurfaceHolder holder)方法里,使用holder.getSurfaceFrame()方法来获得该surface的尺寸,其返回值是一个矩形(Rect)对象。代码如下:

public void surfaceCreated(SurfaceHolder holder) {
Rect surfaceFrame = holder.getSurfaceFrame();
width = surfaceFrame.width();	//屏幕宽度
height = surfaceFrame.height();	//屏幕高度
xPos = width / 2;	        //船初始x轴位置
yPos = height / 4;		//船初始y轴位置
boatSpeed = width / 90;		//船移动速度
startThread();			//启动绘图线程
}

//启动绘图线程
public void startThread() {
exitThread = false;
new Thread(this).start();
}
3.创建并移动船的方法,首先自定义一个draw()方法,用于绘制船只。

public void draw() {
synchronized(surfaceHolder){
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawRect(xPos-20, yPos+10, xPos+20, yPos-10, paint); //画一个绿色的方块
surfaceHolder.unlockCanvasAndPost(canvas); //更新屏幕
}
}现在只需修改船的位置xPos,yPos,然后再调用draw()方法,就能实现船的移动了,修改船位置的方法如下,当触碰到屏幕边缘时停止修改。
public void moveLeftBoat() {
if(xPos - boatWidthHalf < 0 ) { //已到屏幕左边缘
xPos = boatWidthHalf; //boatWidthHalf是船宽度的一半,自定义的一个常量
} else {
xPos -= boatSpeed;
}

}
public void moveRightBoat() {
if(xPos + boatWidthHalf > width ) { //已到屏幕右边缘
xPos = width - boatWidthHalf;
} else {
xPos += boatSpeed;
}
}

为了让draw方法一直执行,重写线程的run方法。在分支代码执行完成后,线程休眠33毫秒,每秒钟就能重绘30次屏幕,对船位置的修改可以通过draw()重绘体现出来,这样船就动起来了:

public void run() {
while(!exitThread) {
switch(direction) { //判断船移动的方向
case LEFT:
moveLeftBoat();
draw();
try {
Thread.sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case RIGHT:
moveRightBoat();
draw();
try {
Thread.sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
default:
draw();
try {
Thread.sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}

}


4.在MainAcitivty的onCreate()中,将GameView对象作为参数传递给setContentView方法,这样就能将该SurfaceView显示出来。但由于我们需要添加用户界面,例如按钮,文字等,所以不直接传递GameView对象给setContentView(),而是用一个容器把用户界面和SurfaceView装在一起,作为参数传递给setContentView()。部分代码如下:
View gameWidgets = inflater.inflate(R.layout.ui_layout,null); //用户界面
GameView gameView = new GameView(this);
FrameLayout mFrame = new FrameLayout(this); //使用一个FrameLayout做容器
mFrame.addView(gameView);
mFrame.addView(gameWidgets);
setContentView(mFrame);
第一次写,有点乱,暂时先写这么多,按键逻辑和投深水炸弹的实现留到下次再写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 游戏