s
本文章面向c语言初学者,所以我尽可能用最基本的语法实现整个游戏,并且只用到一个二维数组实现,下面将详细讲解实现过程。
一个二维数组可以直接打印成一个平面,就形成了整个游戏的背景,我们可以通过改变数组的内容来控制蛇的移动,食物的生成等。
先建立整个游戏框架
#include#include #include #include #define ROW 10//行数 #define COL 25//列数 #define SPEED 100//这里其实是刷新率,所以越低蛇速度越快,后边会引用到 int a[ROW][COL]; int main(void) { char play; do { game(); printf("1:continuen"); printf("2:exitn"); play = getch(); } while (play=='1'); printf("exitn"); return 0; }
s
将二维数组建立为全局变量,使数组所有的数都初始化为0。之后可以用数组中不同的数字代表不同的事物,比如我们将数组的边框初始化为-2,-2就代表了墙
for (int i = 0; i < ROW; i++)//生成墙壁 for (int j = 0; j < COL; j++) if (i == 0 || j == 0 || i == ROW - 1 || j == COL - 1) a[i][j] = -2;
蛇的数字处理很重要,这涉及到蛇的移动问题,蛇的移动实际上可以理解为将尾巴那一块转移到将要移动的前方去,如果蛇要向上移动,就是把尾巴那一块转移到头的上边,同理向右移动即把尾巴移动到头的右边,理解了这个移动方式,就可以对蛇在数组中的值进行创建了,令头的值为1,之后身体块就是2,3、、、直到尾巴那个值,我们初始化蛇有三节,所以尾巴数为3(当然你也可以初始化其他的值)。
a[ROW-2][1] = 3;//生成蛇 a[ROW-2][2] = 2;//生成蛇 a[ROW-2][3] = 1;//生成蛇头 int tailmax = 3;//蛇长,之后蛇的变长要靠这个值
食物生成比较简单,取随机数在数组的范围内,如果是不恰当的位置就重新设置,设置食物的值为-1
void toeat(int a[ROW][COL])//生成食物
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (x != 0 && y != 0 && a[x][y] == 0)
{
a[x][y] = -1;
break;
}
}
}
s
现在数组的基本处理完成,数组内一共有4种值 ,一种是-2,表示墙,一种是-1,表示食物,一种是0,表示空白区域,剩下的正数全都代表蛇,蛇头是1,那么就可以编写打印函数
void print(int a[ROW][COL])//打印
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if ((i == 0 || i == ROW - 1) && j != 0 && j != COL - 1)//上下边界
printf("-");
else if ((j == 0 || j == COL - 1) && i != 0 && i != ROW - 1)//左右边界
printf("|");
else if ((i == 0 || i == ROW - 1) && (j == 0 || j == COL - 1))//四个角
printf("+");
else if (a[i][j] == 0)//空白区域
printf(" ");
else if (a[i][j] == 1)//蛇头,我用字母‘O’表示
printf("O");
else if (a[i][j] == -1)//食物
printf("$");
else
printf("*");//剩下的都是正数,是蛇身
}
printf("n");
}
}
前三个if选择式可能有点吓人,因为我想建立一个(稍微)好看的边界,如果你嫌麻烦,可以直接让边界都是一个字符,如下
void print(int a[ROW][COL])//打印
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if(a[i][j]==-2)
printf("*");
else if (a[i][j] == 0)
printf(" ");
else if (a[i][j] == 1)
printf("O");
else if (a[i][j] == -1)
printf("$");
else
printf("*");
}
printf("n");
}
}
这些都处理好后,就可以进行蛇的移动操作了,我们习惯用wsad表示上下左右(不是)。首先思考,如何表示一只蛇向上移动一次呢?
从前文我们知道只要找到头尾坐标,将尾巴放到头上方就可以,但是蛇是一串连续的数字,在数组中必须要经过数据处理才能进行,得到头尾坐标后,我们可以先让尾巴消失,即坐标设置为0,然后把包括蛇头在内的蛇本体数字全部加1,这样原来蛇头的数字变成了2,现在没有蛇头,我们就可以把原来蛇头上面的数(如果头是a[i][j],头上面就是a[i-1][j])设置为1,新的蛇头就生成了,而且蛇新的尾巴的值没有改变,这样我们简单实现了蛇向上移动一格这个操作,转换为代码如下
int handx, handy;//蛇头坐标 int tailx, taily;//蛇尾坐标 for(int i=0;i|
运用这个逻辑,我们可以很容易实现吃食物这个过程,如果前进方向的值是-1即食物,就将整个蛇连头带尾所有值加1,然后把食物的值设为1,形成新的蛇头
else if (a[handx - 1][handy] == -1)//判断食物 { for (int i = 0;i < ROW; i++) for (int j = 0; j < COL; j++) if (a[i][j] != 0 && a[i][j] != -1 && a[i][j] != -2&&a[i][j]!=-5) a[i][j]++; a[handx - 1][handy] = 1; tailmax++;//蛇变长了,所以尾巴的值要加1 toeat(a);.//生成一个新的食物蛇的前方除了是空白和食物外就是墙和蛇身,如果继续前进就会游戏结束
else gameover = 1;//之后用到我们已经可以实现一次移动,稍微修改二维数组的参数就可以实现四个方向的移动,但是蛇的移动是一个连续的过程,我们应该用循环实现连续移动,但单纯的循环是非常快的,所以蛇会飞快移动,为了避免这种情况,我们要用到windows.h里边的Sleep函数即Sleep(m),m的值为停顿的毫秒,我们将之前定义的SPEED调用上去,Sleep(SPEED)就能控制蛇移动的速度。
另外,因为蛇一直在移动,程序一直在运行,我们要控制蛇必须要输入wsad的指令,不可能蛇动一次就输入一次,太麻烦,所以我们要学习一个新函数_kbhit(),它判断你的键盘有没有输入,没有就返回0,有就返回一个非0值。把他放在每次循环移动的后边,再用getch不回显直接读取输入的值,就可以操作蛇。
一次完整的移动如下while(1) { if(move=='w')//以向上移动为例 { if (a[handx - 1][handy] == 0)//判断可行走 { a[tailx][taily] = 0; for (int i = 0; i < ROW; i++) for (int j = 0; j < COL; j++) if (a[i][j] != 0 && a[i][j] != -1 && a[i][j] != -2) a[i][j]++; a[handx - 1][handy] = 1; } else if (a[handx - 1][handy] == -1)//判断食物 { for (int i = 0;i < ROW; i++) for (int j = 0; j < COL; j++) if (a[i][j] != 0 && a[i][j] != -1 && a[i][j] != -2&&a[i][j]!=-5) a[i][j]++; a[handx - 1][handy] = 1; tailmax++; toeat(a); } else gameover = 1;//判断游戏失败 break; system("cls");//清除之前的屏幕 print(a);//打印新的局面,这样刷新基本实现的蛇的动态过程 Sleep(SPEED);//停一下 if (_kbhit())//判断是否有输入,没有直接跳过 { char cao = getch();//用另一个变量来接受,避免接受到wsad以外的垃圾值 if (cao == 'w' || cao == 's' || cao == 'a' || cao == 'd') move = cao; } } }因为要判断四个移动方向,我们用在while循环内部用switch语句来判断move的值决定移动的方向,
同时设置一个值int gameover=1来判断游戏是否结束。具体代码如下while (!gameover) { for(int i=0;i|
完整代码如下
#include#include #include #include #define ROW 10 #define COL 25 #define SPEED 100 int a[ROW][COL]; void toeat(int a[ROW][COL])//生成食物 { while (1) { int x = rand() % ROW; int y = rand() % COL; if (x != 0 && y != 0 && a[x][y] == 0) { a[x][y] = -1; break; } } } void print(int a[ROW][COL])//打印 { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { if ((i == 0 || i == ROW - 1) && j != 0 && j != COL - 1) printf("-"); else if ((j == 0 || j == COL - 1) && i != 0 && i != ROW - 1) printf("|"); else if ((i == 0 || i == ROW - 1) && (j == 0 || j == COL - 1)) printf("+"); else if (a[i][j] == 0) printf(" "); else if (a[i][j] == 1) printf("O"); else if (a[i][j] == -1) printf("$"); else printf("*"); } printf("n"); } } void game() { system("cls"); for (int i = 0; i < ROW; i++)//重置数组,不然重开游戏会出现前一条蛇的尸体,甚至撞上去会死,而且食物数量会加1,莫名有意思,想体验可以注释这三行 for (int j = 0; j < COL; j++) a[i][j] = 0; srand((unsigned int)time(NULL)); for (int i = 0; i < ROW; i++)//生成墙壁 for (int j = 0; j < COL; j++) if (i == 0 || j == 0 || i == ROW - 1 || j == COL - 1) a[i][j] = -2; a[ROW-2][1] = 3;//生成蛇 a[ROW-2][2] = 2;//生成蛇 a[ROW-2][3] = 1;//生成蛇头 print(a); toeat(a); char move='w';//默认为先向上移,你也可以改为其他方向 int handx, handy; int tailx, taily; int tailmax = 3;//蛇长 int gameover=0;//判断游戏是否结束 printf("nPress any key to cintinue"); char flag = getch();//按任意键开始游戏 while (!gameover) { for(int i=0;i |
最后存在的问题:因为是用这种刷新方式所以眼睛可能会不适,另外如果蛇往反方向走游戏会立即结束(应该没人会这样做吧)。



