Android围住神经猫的实现
2016年3月2日 会当凌绝顶,一览众山小。
为期三天的围住神经猫极简版已经出炉,虽说github或者其他博客已经吧这个简单的小项目写的很详细了,但我还是忍不住再扯一篇。一来为了加深理解,二来也给自己留个学习回忆,毕竟这是我的第一个完整的小游戏项目嘛。
下面我就按照我忍为比较好理解的思路来把整个项目重新整理一遍,期待可以和大家一起学习讨论。
功能预览
原版游戏项目预览:
本人的精简版:

游戏玩法: 点击灰色的点设置红色的路障,每点击一次神经猫(橙色)都会移动一次,如果神经猫到达边界游戏失败,若围住了神经猫,则游戏胜利。
元素定义
由图中可以看出的,游戏的元素大致为10行10列的点阵,我们首先建立Dot类,然后建立Dot数组完成这个点阵。 Dot属性分析: 游戏中需要在背景图片上画出这些元素,所以他们仅仅通过数组下标进行区分是不合理的,为了找到他们在画板上的位置,我们就要给他们添上x,y坐标 其次,每个Dot都应该有着三种状态: 神经猫可走的状态 STATE_ON 神经猫不可走的路障状态 STATE_OFF 以及神经猫所处的状态 STATE_IN 我们设置对应的颜色为 ON_GRAY 灰色 OFF_RED红色 IN_ORANGE橙色 最后给对应的属性配置set和get方法。
Dot 类:
建立好这些点,我们要对游戏背景进行初始化,我们不能在通过activity_main.xml进行设置。 这时我首先想到view,但是很不幸,只有UI线程才能修改UI,如果使用view,我们将频繁的在线程间通信,这无疑加大了代码的复杂度和线程阻塞的可能性。 这时我们就需要游戏开发的常客:SurfaceView
SurfaceView
View必须在UI线程更新画面,而surfaceView是在一个新起的单独线程中重新绘制画面。这是两者的根本区别。 要想实现surfaceview 首先要继承surfaceview类,并实现SurfaceView.CallBack接口。 SurfaceVIew详解:http://www.360doc.com/content/13/0103/14/7724936_257842268.shtml
创建视图类
创建PlayGround类并继承SurfaceView。 该类主要实现游戏界面的绘制,游戏逻辑的实现。
Callback的三个方法:
surfaceCreated() Surface第一次创建后会立即调用该函数。 程序可以在该函数中做些和绘制界面相关的初始化工作, 一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制Surface。 surfaceChanged() 当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。 surfaceDestroyed() 当Surface被摧毁前会调用该函数,该函数被调用后就不能继续使用Surface了,一般在该函数中来清理使用的资源。
为了方便检查程序的执行顺序,我习惯在每个方法上加上Log。
建立好后,我们为Activity设置
初始化游戏
在初始化数组时,让我们首先看一张数组下标和点坐标关系的图
由图中可知,点的坐标和数组下标刚好相反 例如dots[0][1]坐标为(1,0)。
我有一个想把什么代码都放入方法的毛病,不知是好是坏,这里为了方便后面代码的理解,我就把数组的初始化单独的放在initDots方法中了。
定义数组的长度final:
初始化数组
为了方便赋值state,我们可以先将所有元素都设置为灰色,然后指定橙色神经猫的位置,最后在已经变成灰色的点上随机出15个红色路障。 为这个数组的所有元素赋予属性STATE_ON:
定义路障数量:
随机路障:
再初始化神经猫之前,为了方便使用坐标引用对应的数组,建立方法
初始化神经猫:
初始化游戏: 每次重新开始游戏,都要调用该方法,重新初始化时,没必要重新初始化数组,只需改变数组中每个元素的STATE就好了,所以我们将initDots放在playground的构造函数时,而把其他三个初始化函数放入initGame中。 记住要按顺序调用函数。
数组元素的属性都配置好了,让我们测试一下!
在initGame后调用这个方法,检查一下初始化是否正确!
接下来就可以使用canves和paint进行绘制了!
元素的绘制
首先我们要根据屏幕的尺寸来确定点的半径。 共有两种实现方案。 1> 在MainActivity中获取屏幕尺寸
2> 第二种方法在callback的surfaceChanged的方法的第二个参数width(屏幕宽度)巧妙地获取点的直径
有了点的直径,我们就可以进行绘制了!
redraw方法
思考: 我们要根据点的属性的不同二给他们绘制不同的颜色,所以,优先考虑使用switch语句。 在游戏中,奇数行的起始位置显然比偶数行的起始位置大一个半径,我们可以使用偏移值来解决这个问题,当为偶数行时,偏移值为0,不骗移,如果为偶数时,偏移值为半径。
切记,不能在initGame后直接调用redraw方法,这样会使canvas对象为null 因为,如果surfaceCreated没有被调用就lockCanves,就会返回空,需要先创建surface才能使用canves绘制,如果没有surface,就永远不会有canves。
然后在callback方法中调用该方法,初始化游戏界面
响应用户的点击
当用户点击灰色的点时,灰色变为红色的路障,神经猫移动一次。 用户点击点阵以外的背景,进行游戏初始化。 用户点击其他点不做处理。 通过判断用户点击的坐标所落得位置,来做相应的颜色处理。 要想响应用户的点击,首先要实现OnTouchListener 并 重写OnTouch方法。
判断用户点击了哪一个元素,并作出相应的处理:
move()方法
我们通过返回cat到边缘的距离或障碍物的距离,来选出最优路径

由图知,神经猫具有6个行走方向,我给他们设置了1-6编号

如果该方向处于边缘,返回1 如果该方向上没有障碍物,返回正数 如果有返回负数
移动cat到dot点:
判断一点是否在边界:
根据方向获取cat某一方向上的相邻点:
getDistance 获取该方向上的距离
判断玩家输赢:
move 根据距离选择最佳路径:
源码网上一大堆,我就不上传了,欢迎大家指出错误或提出建议.........
最后更新于
这有帮助吗?