手势操作的Snake游戏_游戏视图分析之SnakeView
本文是snake on a phone 贪吃蛇游戏的项目解析系列文章之4,基于google sample code 改编而成项目链接接上一篇文章手势操作的Snake游戏_游戏视图分析之TileView
SnakeView继承自TileView,在TileView的基础上添加了具体游戏元素。涉及代码较多,我们去繁从简,跟着大体框架去剖析其流程。通过上篇文章我们知道,TileView有一组网格状态集合mTileGrid并提供了setTile的public方法去设置状态,那么子类SnakeView显然正是通过这个状态去表示当前游戏布局详情的。
新添加的主要成员
如下这些参数表示游戏的状态,作为setMode去设置游戏状态的参数。
private int mMode = READY;
public static final int PAUSE = 0;
public static final int READY = 1;
public static final int RUNNING = 2;
public static final int LOSE = 3;
如下是图片编号表示,作为视图元素中的红色方格、黄色方格、绿色方格。
会有对应的drawable资源表示,这个int数值用在TileView中的mTileArray[]数组中,分别对应1~3号,0号是空的,表示黑色的区域,绿色是外围的墙壁。红色表示蛇身,换色表示蛇头和苹果。
private static final int RED_STAR = 1;
private static final int YELLOW_STAR = 2;
private static final int GREEN_STAR = 3;
主体函数
SnakeView构造函数,layout加载的时候会调用,其中initSnakeView做了视图初始化的主要工作。
public SnakeView(Context context, AttributeSet attrs) {
super(context, attrs);
initSnakeView();
}
initSnakeView加载了视图元素,如我们上面所说的图片资源,其中初始化gestureDetector的部分我们前面讲述过,属于我们改进的手势操作,这里不再讲述。
private void initSnakeView() {
setFocusable(true);
Resources r = this.getContext().getResources();
resetTiles(4);//长度为4的数组 0黑色 1~3对应红黄绿
loadTile(RED_STAR, r.getDrawable(R.drawable.redstar));
loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar));
loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
//初始化gestureDetector
gestureDetector = new GestureDetector(getContext(), this);
}
当然SnakeView初始化的时候会先去初始化父类TileView,对应相关状态集合的初始化工作也都同时完成。
视图刷新的动态实现
前面数据已经初始化,那么游戏要跑起来,界面要不断刷新,程序通过handler和update函数的交互来实现。
首先看一下handler实现,handler收到消息后会update状态并调用invalidate通知系统需要再次绘制界面了,于是父类的onDraw就会被调用。
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
SnakeView.this.update();//更新网格状态
SnakeView.this.invalidate();//绘制新界面
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
这是update函数的细节,如果当前是running的状态,则更新数据并向handler发送消息,告诉延迟一段时间再次执行更新操作。
public void update() {
if (mMode == RUNNING) {
long now = System.currentTimeMillis();
if (now - mLastMove > mMoveDelay) {
clearTiles();//所有网格归零
updateWalls();//赋值墙壁 绿色标示
updateSnake();//更新蛇的坐标
updateApples();//更新苹果的坐标
mLastMove = now;//记录最后一次运动时间
}
mRedrawHandler.sleep(mMoveDelay);
}
}
至此应该明白视图变化的流程了,通过update更新状态,并利用mRedrawHandler进行消息传递,延迟一定时间后再次通过handlerMessage处理会再次调用update,于是整个游戏就跑起来了。这里的update函数中的updateSnake和updateApples则会根据当前状态以及运动方向动态地更新网格数据。游戏第一次启动update函数是由事件触发的,也就是我们游戏开始时提示的”press up to start”,是否还记得我们在第一节讲述的onKeyDown事件响应,对于dpad_up类型响应代码如下
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
if (mMode == READY | mMode == LOSE) {
initNewGame();
setMode(RUNNING);
update();
return (true);
}
setMode函数用于设置游戏状态标示,这里第一次调用了update函数,于是游运行起来了。
当然我们已经修改可以通过向上滑动来启动游戏。至于updateSnake()是如何变换状态,以及苹果随机生成方法,我们下节讨论。