开始!
2048的游戏,说干就干。
相比之前用swing做的五子棋,安卓上的2048真是难度增加了很多;做完会感叹一句——真是适合新手练习编程的好东西T T
分析一下游戏系统的组成。在本游戏中,大致可以列为
1.游戏体
2.计分牌
3.操作与提示
4.视觉优化
随着代码行数的增加,我也渐渐感受到了编程的最佳顺序:核心功能——次要功能——画面效果等。对于我等新手来说,编程的顺序像是粉刷,是一遍一遍刷出来的。
开发游戏也是一样,先实现最基本的规则,然后再对其进行修正。按照这样的编程思想,我们一步步开始进行2048的开发。
2048的规则是啥?
首先,游戏随机在两个方块内生成随机的2或4,然后你就往某个方向滑屏幕吧,见着空地它就划过去了,一直到底。假如滑的方向有连续两个相同的数字,他们还会合并,顺着滑的方向知道底端。在此之后,还会在空余的地方随机生成两个2或4,让游戏得以继续。
一:游戏体规则
1.对于每一行/列来说,每滑动一次到下次滑动之前的这段判断范围内,游戏遵循以下原则:
(一):能动则动,不撞南墙不回头原则
以向右滑为例,不管是2000,0200,还是0020,每个2的右边都有至少一个空余的方块,此时向右滑动,2遇到边界(墙)才停止,故一律变为0002.而0002这种情况本身则无法再滑动;如果是2004,0204,每个2右边仍然有至少一个空格,此时的墙是4,自然一律变为0024,,而0024本身这种情况则不能向此方向移动。
(二):从滑动方向反着看,来同类则吞并(合并)原则
仍然以向右滑为例,假设滑动之前的情况是0202,那么从滑动的反方向来看,第一个是2,称为大2,第三个是2,称为小2,这时的小2按照原则一向滑动方向滑动,此时的大2则会将其吞并,变为0004.这里“反着看”是为了方便分析。类似的情况,比如4040,按照原则一,两个4都向右滑动,可以看做是右边发4先滑动到底,变为4004,然后按照本条原则,左边的4向右滑动,被右边的4吞并,变为0008.
(三):原则二之上的原则:每次最多只合并两个数原则
仍然以向右滑为例,假设滑动之前的情况是2022,那么这时可以看做是第三个2向右滑动被最后一个2吞并变成2004,然后第一个2向右滑动到这时的墙“4”之前,变为0024,而不是0006.
同样的,如果滑动之前的情况是2222,那么可以看做是第三个2被最后一个2吞并变为2204,然后第二个2向右滑变为2024,再然后第一个2向右滑被现在的第三个位置的2吞并变为0044.此时两个4要不要合并?此时引出下一个原则:
(四):合并一次得到的结果不能再(被)合并原则,即向右滑动的2222只能变为0044而非0008.
2.对于游戏过程来说,每次滑动之后,如果发生了数字的移动或合并(合并了一定已经移动过),我们称其为“合格的滑动”,也就是游戏进行了一回合。而在类似下图的情况时,如果向下滑动,是不能发生数字的移动或合并的,按照游戏规则,不能是一擦合格的移动。这里的移动合格与否会决定是否在随机的空格位置产生一个新的2或4.如果移动合格,则在一个随机的空白位置产生一个2或者4.否则不应有任何变化。
二:记分牌规则
按照游戏规则,每发生一次合并,分数将增加,增加的值等于合并后的值,并且只要分数增加,就显示出来。
当按下“重新开始”按钮时,把当前分数与之前的最高分比较,更新最高分,然后将当前分数置零,游戏主体界面只显示重新生成的2或4。
三:操作与提示
当游戏进行到一定程度,无法继续产生合格的滑动,游戏结束,弹出提示窗口,上面有“重新开始”的按钮,按下之后重新开始游戏,与直接按下重新开始按钮效果相同。
四:视觉优化
略
第一步实现游戏主体。这里采用了自定义组件的方法,将游戏体当做一个组件,自定义这个组件的内容,直接放在xml文件中,再与Activity等联系起来即可。
既然要自定义组件自然要抱View的大腿,继承之后发现有三个构造方法,add哪个呢?注意啦,context可以理解为Activity,(顺着api可以看到它其实是Activity的父类,哦不,爷爷类,爷爷的爷爷类)AttributeSet可以理解为在Layout中向图形编程界面拖动组件时的参数,int defStyle则是默认的组件试图格式,那么我们用其中的第二个就可以了。
注意,仅仅重写构造方法是不够的,还需重写onDraw方法。如何理解?我的理解方法是,Game2048blog是继承了View的孩子,构造方法决定了他的性格,paint即是它思考问题的方法,是内在的,是准备的,是选择好画笔,而onDraw则是他在出生时的样子,用到的canvas是母亲的子宫,“磨合”了他出生时的外貌,是外在的,是动词,是真正实施了;二者缺一不可。有没有好理解一点呢?
1.继承View
来一个萌萌的自定义组件……
这时就可以在Layout里看到它的身影啦。可以拖上去试试~
2.重写构造方法、onDraw方法
我们需要画出这样的边框,写出这样的数字
所以我们要画出一个大大的圆角矩形,和16个小圆角矩形,于是,我们加上了下面几行代码对paint进行设置:
注意空心矩形与实心的区别,在于setStyle。
这时重写onDraw方法,用canvas画出矩形。这里想达到的效果是画出的图形能与控件适配。
这里强调画圆角矩形的方法。实例化RectF对象r1,几个参数的含义如注释所示,均为矩形边缘距离组件边缘的距离。
画完了轮廓画数字,不过这时候能做的最多的也就是设置下字体的格式啦。
这里一个小tip:如何设置字体居中?
在重写onDraw方法时,需要对字体进行设置
paint.setTextAlign(Paint.Align.CENTER);//使坐标处于字体中间而不是左下角,便于水平调整坐标
paint.setTextSize(108);//设置大小
在需要画数字时,则要再计算字体高度,找准纵坐标与baseline之间的关系 即
FontMetrics fontMetrics =paint.getFontMetrics();
// 计算文字高度
float fontHeight =fontMetrics.bottom - fontMetrics.top;
游戏要求我们在刚刚进入游戏时就要随机显示两个2或4,也就是需要在onDraw里画出数字。为了更有条理,我们把画数字的方法单独拿出来,也就是
这里的array数组用来储存每个空格应该显示的值(0不显示),应定义为全局变量。
3.滑动事件处理(烧脑)方法
处理事件要有监听器,事件处理方法。