写在开头:
本人初入iOS,刚刚学习OC一个月,学到的东西还比较有限,我利用这有限的知识尝试自己去写一个2048小游戏,难度极低,希望能帮助到广大新手编程爱好者,另外也借此记录下自己平时的学习。
本文主要讲游戏的思路,以及编程时候的注意点,不会刻意去讲代码,游戏代码非常简单,文章底部我会附上代码连接。
先上游戏展示: 设置的滑动屏幕实现移动,所以这里用鼠标代替的
首先先说下我开始打码之前做的准备工作:
第一步---登录2048游戏界面观察游戏界面,了解游戏规则,思考游戏机制,整理编程思路。
送上游戏链接,没玩过的朋友可以熟悉下游戏 点这里玩2048
上面的游戏名字,分数,以及新游戏,游戏信息等内容我们可以用一些简单的Label 或者Button之类的完成,如何将分数跟随游戏变化后面会说到,这里我们主要观察下这个正方形的游戏面板。
游戏机制非常简单,玩家只需要通过上下左右的移动即可参与游戏,游戏规则大家玩一两把就懂,这里直接跳过。观察完毕后我把程序中要实现的功能罗列出来,然后尽量在代码中完成这些功能:
1. 游戏开始的时候是在16个格子中随机出现两个2
2. 每次移动的时候,数字会挤到移动方向的那一边堆在一起
3. 如果两个数字相同,会挤成一个数字,且是原来数字大小的2倍
细节注意:如果同一行有3个连续的2,如2224,往右边移动的时候是最右边的两个2变成4,结果为244,并非424,并且刚刚产生的这个4并不会与最右边的的4立马合并,而是到下次往右移动的时候才会。
4. 每次成功移动,会随机在一个没有数字的格子里出现一个2
细节注意:若出现下图情况,往右边移动的时候如果不会有变化,则不会出现随机的2,注意加点延迟,用户体验会更好。
5. 格子的颜色会随着数字不同而变化
好,这里游戏的大致规则以及思路想必大家都差不多了解了,应该没有遗漏的地方把。
第二步---游戏界面与二维数组的巧妙结合
第二步的标题我直接把我代码的最重要的地方说出来了,对的就是二维数组,想必聪明的读者看到这里是不是已经有一种恍然大悟的感觉了,把游戏界面转化为一个二维数组,是不是就可以为我们的开发减少了不少的难度呢,当然我也不知道这个游戏的作者的变成思路以及方法,可能也有更好的其它的方法,但我经验太少了,只想到了这一个方法,而且后来成功实现了,本文就以这种思路去进行讲解。
上图所示的界面是不是现在已经变成了这样的一个二维数组
int array[4][4] = {{0,0,0,0},{0,0,0,2},{0,0,0,2},{0,0,0,0}};
所以我的编程思路就是图中出现的16个格子就是16个Label,它的text属性就是对应的数字,如果数字为0,则设置它的text属性为空即可。然后根据不同的数字给Label的backgroundColor属性设置对应的颜色即可,Label的font属性注意修改一个合适的数值,不然数字变大后很可能格子显示不出来,如果你对细节要求很高,则可以让字体的大小跟随着数字大小而变化。
这里建议手动创建label,并且用一个数组管理它们,这样每次根据二维数组赋值的时候,会比较方便。
第三步---格子移动的核心算法
我觉得这个游戏最核心的地方就在这里了,最难也是最有价值的地方,不过大家也不用害怕,难是难在很难去想到,但是非常容易理解,废话不多说,进入正题。
以往右移动为例子,这个理解后,其它四个方向的移动思路和这个都是一样的,所以搞懂一个就ok了
往右移动的时候就是同一行的会发生变化,对同列之间的数没有影响,所以,我们只要会移动每一行的数据,然后嵌套到一个for循环里是不是就搞定了所有4行的了,所以我们可以将整个问题缩小到对同一行四个数字的操作,问题是不是又简单了呢,我说了不难吧。
1. 先举个不需要合并的例子:
以{4,0,2,0}为例子,这就是一个普通的整形数组了,右移的结果就是达成{0,0,4,2}的效果
这里喜欢动脑筋的同学可以自己写这个方法,就是一个for循环里进行判断,自己想这种问题会非常有意思,这也是我觉得编程非常有意思的重要原因之一,我喜欢弄脑筋并想出办法的感觉,而不是靠记忆力硬生生的记住一个办法。
如果,你没想出来,希望我的办法会有所帮助
有过编程经验的同学看到这种问题基本都知道先敲个for循环是第一步,就如同冒泡排序差不多,这也算是一个排序问题,不过这可不是大小排序。
因为要往右移动,所以先判断右边的数字开始
第4个数字已经无法往右移动,所以进入下一步
第三个数字和第四个数字比较,如果第四个位0,则交换两个数字的位置,然后第三个数字到了第四个位置无法右移,下一步
第二个数字和第三个数字比较,如果第三个数子为0,交换位置,继续和第四个比,若第4个位0,交换位置,现在又无法移动了,下一步
第一个数字和第二个比较,后面省略,大家应该明白了吧。
我的语言表达能力比较差,可能说的不是特别清楚,这里再附上一小段打码,便于大家理解
int a[4] = {0,4,0,2};
int i, k, temp;
for ( i = 2; i >=0; i++)
{
k = j;
while (k+1 <= 3 && a[k+1] == 0)
{
temp = a[k];
a[k] = a[k+1];
a[k+1] = temp;
}
}
大家写个C程序敲一敲应该是能理解的
2. 接下来是一个需要合并的例子:
这里以{2,0,2,4}为例子,移动后的结果应该是{0,0,4,4}
这种看起来虽然要比上一种情况复杂,但是我们是不是可以把它分成两步啊,这样就会简单很多
第一步就是按照不需要合并的方法进行移动,移动后的结果是{0,2,2,4}
第二步就非常加单了,只需从最后一个开始判断,这个数和它左边的进行比较,如果相等,让它乘以2,让它左边的数字为0即可
代码例子:
for(int i=3;i >= 1; i--)
{
if (a[i] == a[i-1])
{
a[i] += a[i-1];
a[i-1] = 0;
}
}
刚才我说了两步,如果只写到这里还是有问题的,细心的读者估计已经发现了
如果是2244按照这种方法移动得到的是不是0408啊并不是0048
所以每次移动完了之后再进行一次非合并的移动方法就好了啊,所以大家写代码的时候不要忘了哦
好了,到这里整个对二维数组的移动大家应该都学会了把,将到这里,游戏精髓的地方也基本就差不多了
第四步---补充总结
这里顺便说下随机出2的方法
我的方法就是每次移动后,随机生成一个0到15到的数字,也就是第几个数字,如果这个数字不为0,则继续随机
我觉得我的方法可能不是特别好,应该还有更好的办法
-(void)new2
{
int n = arc4random()%16;
do {
n = arc4random()%16;
} while ((a[n/4][n%4] != 0));
a[n/4][n%4] = 2;
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// [self reload];
// });
}
注释的部分是延迟把2赋值给对应的label
再说下分数的问题
我显示的分数就是显示数组里面的最大值
最后再稍微谈谈不能移动的情况判断问题
我的方法比较呆,虽然能实现但看上去就挺没技术含量的
因为每次都是数组先变化再把数值给label显示的,所以每次移动之后的数组和移动前的数组比较,如果不一样再给label更新赋值。。。是的。我就是这么写的。。
好了,基本上说的差不多了,打了这么多字好累啊,大家能坚持看完我这个萌新写文章也真是苦了大家了,写这个小游戏的整个过程是非常有意思的,不断的去发现bug并且去改善,最终大致实现游戏的基本功能,虽然说技术含量不高,但对于新人来说自信心方面会得到极大的提升,而且这个过程中我体验到了编程的快乐,对于我以后的学习启到了很好的影响,也希望大家在有了一定的编程基础之后尝试自己做一些东西,自己去主动学习的感觉远远高过于被动接受。
最后附上代码的网盘链接 点这里下载 密码是rxeh
祝我和大家都能慢慢从一个萌新蜕变成大牛!
请大家多多留言和我交流!