赞
踩
贪吃蛇的实现,实现了几遍。从开始的举步维艰到最终的思路清晰,都是不容易的。这里不想针对整个工程大谈。只针对里面的三点进行叙述,便是产生食物时,用到一个算法,也叫洗牌算法,以及整体上的一维数组的使用。而其中的一维数组的使用,而不是二维数组。这里也是为了方便编程,以及提高数据的处理速度。其实在我看来,数组的灵活使用,其实就是下标的灵活使用。也就是说,玩数组就是玩下标。再有一点便是程序的整体上,很多人有一个误区,具体就是处理图形的方式上有所错误理解。接下来一一叙述。
注:这里为了画图以及讲述方便,假设只有10张牌,分别为0-9.
方式一:在10以内产生一个随机数,然后放到第一张牌,即下标为0处;
在10以内再产生一个随机数,然后放到第二张牌上,即下标为1处;
......
上面这种方式,无非是最简单的方式,但却有一个致命的缺点。即从第二次开始便要查重,而且随着循环的继续,重复的可能性就会越来越高,显然是不合理的。这里在第一种方式的基础上改进,将产生的牌作为最后一张牌,然后每次的基础上产生随机出的范围减一,这样便轻松产生一副随机的牌,而且不需要查重的。对于这个思想,发现这种不叫“洗牌”,因为没有洗。下面给出的方式二,是在这种思路的基础上的,才是真正的洗牌,而这种办法才是具有通用性的。
方式二:首先需要先准备一个一维数组,按照这里的10张牌,即长度为10,依次赋值为下标的值(如图所示),这里赋值为下标的的值,说明之前为一副新牌,而在实际应用中,这里便是用来记录原数据的。
在10以内随机产生一个数,以这个数为下标,将下标所对应的这个值与最后一个值交换;
在9以内随机产生一个值,以这个数为下标,将下标所对应的这个值与倒数第二个值交换;
......
这种方式既可以避免查重,而且可以对原数据进行真正意义上的洗牌,时间复杂度为O(n)。代码如下:
- int i;
- int temp;
- int randNum;
- int arr[10];
- int count = 10;
-
- for(i = 0; i < 10; i++) {
- arr[i] = i;
- }
-
- srand(time(NULL));
- for(i = 0; i < 10; i++) {
- randNum = rand() % count;
- temp = arr[randNum];
- arr[randNum] = arr[count - 1];
- arr[count - 1] = temp;
- count--;
- }
-
- for(i = 0; i < 10; i++) {
- printf("%d ", arr[i]);
- }

由于洗牌算法在贪吃蛇中的使用牵扯众多,因此在最后详谈。
一维数组的使用也是源于之前的经验。首先说明,这里的一维数组只是为了方便运算,实际是用一维数组表示二维数组,只不过在转换为坐标时,进行一步运算即可。在贪吃蛇游戏设计过程中,前几次编程时,对于其中的食物的产生以及蛇咬到自己的身体或者对手的身体,这个处理,总是很复杂。因为每一次移动或者产生食物时,需要对身体进行遍历,以及食物的坐标也是需要遍历的。这就会产生很大的时间复杂度。对于这个问题,最终想到一个办法,那就是给一个全局的数组,用来记录屏幕上点的当前状态,至于好几种状态(食物,自己蛇身或蛇头,对手蛇身或蛇头,空地,障碍物墙壁),可以给好几个宏,以记录。这样的话,每次移动或者产生食物时,只需改变相应的几个点的坐标,而在处理之前的几个问题时,就可以直接用下标判断,一句搞定。没有代码很难讲清楚,后面我会用代码详谈。
覆盖法只是这么一个叫法。实际想说的是在每次移动蛇或产生食物时,可以用覆盖法代替刷新屏幕的方法。网上很多人的贪吃蛇每次刷新整个屏幕,实际上复杂了问题,因为每次只有几个点在变化。我们可以直接通过覆盖来达到我们的目的。至于具体的就不详说了,可以在最后看看代码。
贪吃蛇项目在屏幕信息数组上实际上有两个,一个便是上面的全局的一维数组,因为屏幕上共2000个点,因此便是申请了一个长度为2000的全局一维数组以记录信息,而在产生食物时,还需要有一个局部的长度为两千的一维数组,这个数组就是之前洗牌算法中的需要的数组。这个数组只是为了产生随机的并且不重复的食物点阵信息而存在。先给出这块的代码,再拿代码讲述吧。
- //产生食物的坐标
- void getFoodXy(int *point) {
- int randNum;
- int i;
- int count = 0;
- int array[2000] = {0};
- int j = 1999;
-
- for(i = 0; i < 2000; i++) {
- if(point[i] == 0) {
- array[count] = i;
- count++;
- }
- }
-
- for(i = 0; i < FOODNUM; i++) {
- srand(time(0) + i);
- randNum = rand() % count;
- point[array[randNum]] = FOOD;
- array[randNum] = array[j--];
- count--;
- }
- }

这里可以看到得到随机食物的函数相当简单。这便是得益于一维数组和发牌算法的支持。如果按照一般的实现方案,你需要剔除掉蛇身,蛇头,边框,还有剩余的食物,然后再在里面产生食物。我开始也是按照这种方法实现的,这里的代码相当复杂,繁琐,令我恶心之至。不过加上犀利的操作后,一切变得简单方便。可见这几部操作的重要性。
https://github.com/kennDJ/snake
有不同意见,欢迎交流!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。