为SurfaceView视图添加线程

      游戏中有些时候需要固定一个时间去刷新画布,例如背景动态的浮云、流水等等,这些元素不会与玩家交互,但它却是动态的。因此游戏中会有一个线程在不停地重绘画布,实时更新游戏背景动态元素的状态。除此之外,游戏中还有其他的逻辑需要不断更新,例如游戏中钱币的更新等等。

public class MySurfaceView extends SurfaceView implementsCallback, Runnable {

...

// 声明一个线程对象

private Thread thread;

// 线程标示符

private boolean threadFlag;

public MySurfaceView(Contextcontext) {

super(context);

// 实例holder

holder = this.getHolder();

// 为SurfaceView添加状态监听

holder.addCallback(this);

// 实例画笔

paint = new Paint();

// 设置画笔颜色为白色

paint.setColor(Color.WHITE);

// 设置焦点

setFocusable(true);

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

// 初始化屏幕尺寸

SCREEN_W = this.getWidth();

SCREEN_H = this.getHeight();

// 在SurfaceView创建时修改线程标识符为真,表名线程启动

threadFlag = true;

myDraw();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

threadFlag = false;

}

/**

* 自定义绘图函数

*/

public void myDraw() {

...

}

@Override

public boolean onTouchEvent(MotionEvent event) {

textX = (int)event.getX();

textY = (int)event.getY();

myDraw();

return true;

}

/**

* 功能:封装游戏逻辑

*/

public void logic() {

;

}

@Override

public void run() {

while (threadFlag) {

longstartTime = System.currentTimeMillis();

myDraw();

logic();

long endTime= System.currentTimeMillis();

/*

* 1000ms /60 = 16.67ms 这里,我们采用15,使帧率限制在最大66.7帧

*/

if (endTime -startTime < 15) {

try{

Thread.sleep(15- (endTime - startTime));

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

      本类中,有以下注意的地方:

      1.线程标示符

      在代码中“boolean flag;”语句声明一个布尔值,主要用途有:(1)防止重复创建线程。(2)便于销毁线程。

      android手机上都有Home键和Back键,当用户按下这个按键,手机无论执行什么程序,都会返回桌面。从而导致SurfaceView状态的改变。Home和Back的区别在于,在用户按下Back键后再重新进入程序,SurfaceView的生命周期调用如下:surfaceDestroyed→ 构造方法 → surfaceCreated → surfaceChanged。在用户按下Home键后再重新进入程序,surfaceView的生命周期调用是这样的:surfaceDestroyed→ surfaceCreated → surfaceChanged。

      由以上区别可知,当每次按下Back后再返回程序时,SurfaceView都会被重新加载。

      因为这个原因,我们为了避免线程重复创建而出现线程状态异常。最完美的做法就是,线程的初始化和线程的启动都放在视图创建的surfaceCreated中来完成,并且在surfaceDestroyed 中将线程标示符设置为false。这样既可以避免线程已启动异常,同样也可避免线程无线创建的问题。

      2.控制帧频

      由于不同手机不同的性能,处理逻辑和绘图的时间不同,为了尽量使游戏的用户体验一直,我们就要控制帧频,以避免设备性能好游戏就能运行飞快的问题。性能较差的设备,能够做到不丢帧的运行即可。当设备处理完绘图和逻辑之后,如果处理所用时间小于一帧的时间,那么就让它休眠够剩下的时间。