在上一篇中,我们把这个项目的各个文件都创立了下,而且还在snake.h文件中把我们要用到的函数都列了出来,接下来我们来逐步完善各个函数。
gotoxy函数
为啥子不按照顺序先从initMap开始讲嘞?因为initMap这个函数需要定点输出,而且我之前说了,在这个项目中我不会使用“\n”这种来输出界面,所以我们采用定点输出的方式,为了方便它的使用,当然是把它打包成一个函数啦。
这个函数没啥子讲的,只是死套模板罢了,只不过我们把x和y作为函数的输入就可以了:
void gotoxy(int x, int y)
{
HANDLE hout; //Defining handle objects
COORD cor; //Defining coordinate objects
hout = GetStdHandle(STD_OUTPUT_HANDLE); //Get the handle of the output screen buffer
cor.X = y;
cor.Y = x;
SetConsoleCursorPosition(hout, cor); //Move Cursor
}
这样,我们在主函数中导入snake.h头文件后就可以直接调用这个函数了,而且在snake.c文件中也是。
menu函数
如果你大概玩了下这个小游戏你就会知道,我们在刚打开这个游戏的时候,会有个问你玩游戏还是退出的界面,这个函数就是用来显示这个界面的。
不知大家还记不记得我们在snake.h里面定义的一个ret变量,它就是在这里用来当这个函数的返回值的。
int menu()
{
gotoxy(12, 42);//移动到12,42的位置
printf("欢迎来到贪吃蛇小游戏....");
gotoxy(14, 45);//移动到14,45的位置
printf("开始游戏请按(1)");
gotoxy(16, 42);//移动到16,42的位置
printf("按其他任意键退出游戏QAQ");
gotoxy(18,25);//移动到18,25的位置
printf("反正闲着也是闲着,不如坐下来来一把紧张又刺激的贪吃蛇如何?┐(‘~`;)┌");
int ch = getch();//使用ch接收键盘输入的值,getch()作用参考第一章
while (TRUE)
{
if (ch == 49) //因为它的 ASCII 值是1,因为我们的ch是int型
{
ret = 1;//则把ret标记为1,意为用户同意玩
break;
}
else
{
break;
}
}
system("cls");//把屏幕清空下,方便接下来的显示界面
return ret;//把ret的值返回
}
initMap函数
这个函数是用来显示地图界面的,它用来初始化蛇的各种信息,果子的坐标,和游戏边框等地方,是非常重要的函数。我的注释会打的非常详细,帮助大家理解
void initMap(void)
{
ch = UP;//默认的ch为向前
Direction = UP;//默认方向为向前
//初始化食物
srand(time(NULL)); //使用当前时间进行随机数发生器的初始化
food.x = rand() % (FRAME_HEIGHT - 2) + 1;//rand( )随机函数, 食物的x坐标为1到界面最右边少一个位置中的任意一个值。FRAME_HEIGHT 和FRAME_WIDTH都是我们之前已经宏定义后的值。
food.y = rand() % (FRAME_WIDTH - 2) + 1;
gotoxy(food.x, food.y);//定位到我们随机出的坐标
printf("!");//使用!代表食物
//初始化蛇
snake.x[0] = FRAME_HEIGHT / 2;//用地图的长和宽都除2,从而把蛇头定位到地图中央
snake.y[0] = FRAME_WIDTH / 2;
gotoxy(snake.x[0], snake.y[0]);//到地图中央的地方
printf("@");//用@表示蛇身
snake.len = 3;//初始蛇的长度是3个
snake.speed = 200;//默认蛇的速度是200
for (k = 1; k<snake.len; k++)//从正中央的地点开始后3个把蛇的身子部分都显示出来
{
snake.x[k] = snake.x[k - 1] + 1;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k], snake.y[k]);
printf("@");
}
//初始化地图
for (j = 0; j<FRAME_WIDTH; j++)//初始化宽
{
gotoxy(0, j);
printf("#");//是用#表示边界
gotoxy(FRAME_HEIGHT - 1, j);
printf("#");
}
for (i = 1; i<FRAME_HEIGHT - 1; i++)//初始化长
{
gotoxy(i, 0);
printf("#");
gotoxy(i, FRAME_WIDTH - 1);
printf("#");
}
}
printFont函数
这个函数主要是显示一些游戏信息啊神马的东西与游戏内容无关,主要是加强游戏体验的东西。为了方便,这个函数的入口参数就弄了俩,其他输出地点的坐标直接计算出来,emm至于计算公式,,不用太深究,,慢慢调出来的,主要是为了美观。
void printFont(int x, int y, int speed)
{
int i = 1;//定义一个变量,后面计算用
gotoxy(x, y);
printf("反正闲着也是闲着,不如坐下来来一把紧张又刺激的贪吃蛇如何?");
gotoxy(x + ADD, y);//ADD也是我们在snake.h里面定义的一个常量,现在用作计算坐标用,大家随意处理即可
if (speed == 200)//根据速度显示数度级数
{
printf("现在的速度是:%d级", i);
}
else if (speed == 175)
{
printf("现在的速度等级是:%d级", i + 1);
}
else if (speed == 150)
{
printf("现在的速度等级是:%d级", i + 2);
}
else if (speed == 100)
{
printf("现在的速度等级是:%d级", i + 3);
}
else
{
printf("恭喜你,召唤师,现在是最高级");
}
gotoxy(x + 2 * ADD, y);
printf("上下左右操作键分别是:w,s,a,d");
gotoxy(x + 3 * ADD, y);
printf("当吃到自己身体或者撞墙时游戏结束");
gotoxy(x + 4 * ADD, y);
printf("按空格键暂停,在按空格键继续");
}
updataFood函数
这个函数主要是用来更新了食物的,它用来判断食物是否被吃,如果被吃掉了就再随机出一个新的食物。。
至于怎么判断食物是否被吃掉了,很简单,直接判断蛇头的坐标是否和食物的坐标一样就可与了,,emm,,但是后来我玩这个游戏的时候,发现这个bug,因为食物是全图生成的,如果生成的食物在蛇的身上,它会随着蛇的移动,输出的食物图标“!”被覆盖,随后消失。而且不会生成新的食物。。。说白了,按照上面的逻辑,这个bug就是食物没了,而且不再生成。
所以我把它的判断逻辑小改了下——当食物的坐标在蛇的身体中时,它才判定食物被吃掉了。
void updataFood()
{
int iseat=0;//用作标记食物是否被吃,默认为没有被吃
for(int i=0;i<snake.len;i++){//循环判断,食物的坐标是否以在蛇的身体中
if(snake.x[i]==food.x&&snake.y[i]==food.y){
iseat=1;//如果时,则记录食物被吃了
break;
}
}
if (iseat)//当食物被吃了后,再次随机新的食物
{
srand(time(NULL));//不明白的参考第一章
food.x = rand() % (FRAME_HEIGHT - 2) + 1;//使用取余的方式,把随机的结果固定在地图范围中
food.y = rand() % (FRAME_WIDTH - 2) + 1;
gotoxy(food.x, food.y);
printf("!");
snake.len++;//由于食物被吃了,蛇的长度加一
grow = 1;//是否增长标记为是,这个变量也是snake.h宏定义过的
}
}
好了,今天就先讲解这么多,剩下的明天再讲吧,,,毕竟打字打的手有点疼