目前,我们学习了如何建立Android编程环境,如何显示文字和图片,如何响应用户事件。作为总结,我们要运用这些知识实现一个扫雷游戏。

先说游戏规则:扫雷,就是在一个分成若干小格的矩形区域中发现隐藏的地雷,找到它,但是不能触发它。每次翻开一个小格,如果下面是地雷,游戏就失败了。如果不是地雷,而它的周围8个格中有地雷,那么就会显示周围的地雷数。如果周围8个格中没有地雷,那就是空白的。如果你认为某一格是地雷可以用红旗标记它,正确标记了所有的地雷或者翻开了所有不是地雷的格就取得胜利。

再说用户操作:在Windows中用户可以有三种操作,左键单击,右键单击,左右键同时单击。左键可以翻开一个小格,可以触雷,如果点到了一个空白格,跟它相联的所有空白格都会被打开。右键可以标记一个格,不会触雷,标记方式有两种,第一次单击用红旗标记,确信此处有雷,再次单击红旗变成问号,表示可能有雷。左右键同时单击只在此种情况有效,即一个格周围有雷,并且所有的雷都已被用红旗标记出来。此时单击此格会打开周围所有未标记的格,此操作会触雷,就是说如果标记错了游戏就会失败,所以一定要小心使用。因为在手机上没有右键,所以我们必须设计替代方案,一种方法是设计一个开关图标,点击打开开关后,所有的操作都被认为是右键和左右键同时单击,另外还可以借助手机上的菜单键,按住菜单键等同打开开关,松开等同关闭开关。为了方便游戏,我们可以同时实现两个方案。

最后让我们分析一下程序的大体思路,从最直观的用户界面开始,我们需要根据游戏的显示区域创建游戏地图,一个m行n列的二维整形数组,数组中的一个值对应界面上的一个格,不同的数值可以表示不同的状态,比如0表示空白格,1表示此格周围有一个雷,2表示有两个雷等等。因为雷的位置是随机的,所以这张地图需要在每次游戏开始的时候被初始化。另外因为这张地图不能直接显示给用户看,所以我们还需要另一个同样大小的地图把它盖起来。并且也用不同的数值来表示一个格是否被翻开,或者被标记等等。这样每次刷新屏幕我们会根据地图上的数值在屏幕上对应的位置显示不同的图片,就是我们看到的游戏界面。这种使用多层地图的技术在游戏中非常常见。这两个地图可以在同一个二维数组中,也可以分开两个数组,为了便于理解,我们使用两个数组分别表示。另外,界面上还要显示当前剩余的地雷数量和游戏时间。剩余地雷数是地雷总数减去用户标记的地雷数,可以是负值。游戏时间是每次新游戏开始时启动的一个计时器,我们知道,如果要时间连贯显示,就必须不停的自动刷新屏幕,但是回顾前面四章的内容,并没有讲解如何循环刷新屏幕,所以在这里会介绍一种使用Handler刷新屏幕的方法,这种方法比较简单,但是效率并不高,所以后面我们还会介绍另外一种更有效的方法。

接着来看用户事件的响应,虽然用户也可以用键盘来操作,但那样就失去了扫雷游戏追求速度的快感,所以我们只设计使用触摸屏的方案。当用户点击屏幕时,首先判断点击在哪一格,再根据用户点击的方法,以及被点击格的状态,判断用户操作的结果,改变地图上相应格的数值,刷新后用户操作的结果就会在屏幕上反映出来。

另外我们还需要一些游戏状态的标志,比如游戏胜利,失败或是正在游戏中。如果游戏胜利,还需要存储记录,由于存储操作前面没有讲到,我们暂时放弃这个功能。

为了缩减篇幅,下面使用源代码直接讲解,源程序的eclipse工程文件已经随本文一起提供下载,这里就算是一个源程序导读(在源程序的res/raw目录下有一首mp3很好听哦)。

首先看Main.java

……
@Override
protected void onPause() {
/*
* 在程序被挂起或者退出的时候改变游戏状态以结束游戏循环
*/
gameView.gameState = GameView.STATE_LOST;
super.onPause();
}
……

这里我们对onPause做一个说明,也是对Android程序生命周期的一个简单介绍。详细内容会随着文章的深入慢慢讲解。大家知道在pc中,多个程序是可以同时运行的,即多进程。在手机中,程序依然可以多进程运行,但是还有一些不同:首先是屏幕,当一个应用启动后,他要独占屏幕。这样一些有打断功能程序运行起来后,当前的程序就不可见了,最简单的例子就是来电。当你正在游戏,突然有电话打进来,来电程序会占领屏幕,你的游戏转到后台运行(这时onPause事件就会被触发);另一个不同的地方是,如果一个程序被转到后台太长时间而没有再次被激活,那么系统会结束这个程序。在结束之前会触发相应的事件(onSaveInstanceState,后面会介绍)。而与之对应的,当程序开始,触发onCreate事件时,我们需要检测当前程序是第一次运行还是被在后台销毁后重新运行,如果是重新运行,我们需要装载程序销毁前的状态信息。

这里我们用onPause的方法并不正确,因为程序挂起的时候不应该让游戏结束,但是为了简化代码,我们暂时先这样做,后面会加以改进。

程序的主要内容在GameView.java中,随本章提供的源代码中有详细的注释,请大家自行阅读源码。

 

本章示例程序http://u.115.com/file/f1e65e86c1