本节需用到的知识点:

(1)非阻塞响应键盘输入函数kbhit()

怎样来控制蛇上下左右进行移动呢,思路就是我们键盘进行输入,程序判定输入的方向,然后控制蛇的x,y坐标不断的进行加加或减减

如我们需要用键盘上的w a s d来控制蛇上下左右移动,只需要判断键盘输入的是哪个字母,然后相应的修改坐标即可,因此我们需要在while()循环内,map[snake_x][snake_y]=0;之后添加以下代码,实现控制蛇的移动

char c;
c=getch();
switch(c)
{
case w:snake_x--; break; //按w键,蛇向上移动
case s:snake_x++; break; //按s键,蛇向上移动
case a:snake_y--; break; //按a键,蛇向上移动
case d:snake_y++; break; //按d键,蛇向上移动
default: break;
}

大家运行的时候可能会发现,当程序等待键盘输入的时候,屏幕是没有显示内容的,只有当我们不断的输入,屏幕上才会不断的出现画面,这是因为getch()堵塞了程序的运行,只有当键盘有输入时,程序才会继续向下运行,蛇的坐标进行更改,然后执行printf()列印出画面。

为了解决此问题,就需要使用到kbhit() 函数,它可以非阻塞响应键盘输入,检查当前是否有键盘输入,若有则返回一个非0值,否则返回0。需要引入头文件#include<conio.h>

对于游戏的制作,我们可以使用此种方式来接收键盘的输入

if(kbhit())
{
执行语句;
}

即执行到kbhit()时,如果我们没有键盘输入,则返回0,执行if后的其他语句,如果我们键盘有输入,则返回非0,就执行if内的语句,如果我们直接使用getch()来接收键盘输入的话,则执行到getch(),就会暂停程序等待我们输入,这样游戏就不能连续运行了

这样上面的代码就变换为如下:

if(kbhit())
{
char c;
c=getch();
switch(c)
{
case w:snake_x--; break; //按w键,蛇向上移动
case s:snake_x++; break; //按s键,蛇向下移动
case a:snake_y--; break; //按a键,蛇向左移动
case d:snake_y++; break; //按d键,蛇向右移动
default: break;
}
}

这样咱们就能实现控制蛇的移动了,完整代码如下

#include <stdio.h>
#include<Windows.h>
#include<conio.h>
void main()
{
int map[20][40]; //二维数组map[][],用来表示游戏地图
//为0时,表示空白,什么都没有
//为1时,表示上下围墙
//为2时,表示左右围墙
//为3时,表示蛇
//为4时,表示食物

int snake_x=10,snake_y=20; //用来表示蛇的位置坐标
int i,j;

for(i=0;i<20;i++)
for(j=0;j<40;j++)
map[i][j]=0; //初始化二维数组,全部置为0

for(i=0;i<20;i++)
for(j=0;j<40;j++)
{
if(i==0||i==19)
map[i][j]=1; //赋值上下围墙 ------------------
if(j==0||j==39)
map[i][j]=2; //赋值左右围墙|||||||||||||||||||
}

map[snake_x][snake_y]=3; //利用变数在地图中间初始化蛇身
map[15][6]=4; //初始化食物位置,随便定义了一个位置

for(i=0;i<20;i++) //列印地图
{
for(j=0;j<40;j++)
switch(map[i][j])
{
case 0: printf(" ");break; //0代表空格,什么也不列印
case 1: printf("-");break; //1代表上下围墙
case 2: printf("|");break; //2代表左右围墙
case 3: printf("@");break; //3代表蛇身用@表示
case 4: printf("$");break; //4代表食物用$表示
}
printf("
");
}

while(1) //不断的循环
{
system("CLS"); //清屏函数,清除屏幕内容
map[snake_x][snake_y]=0; //更新地图,将蛇的老位置赋值为0
if(kbhit())
{
char c;
c=getch();
switch(c)
{
case w:snake_x--; break; //按w键,蛇向上移动
case s:snake_x++; break; //按s键,蛇向下移动
case a:snake_y--; break; //按a键,蛇向左移动
case d:snake_y++; break; //按d键,蛇向右移动
default: break;
}
}

map[snake_x][snake_y]=3; //更新地图,将蛇的新位置赋值为3

for(i=0;i<20;i++) //列印地图
{
for(j=0;j<40;j++)
switch(map[i][j])
{
case 0: printf(" ");break; //0代表空格,什么也不列印
case 1: printf("-");break; //1代表上下围墙
case 2: printf("|");break; //2代表左右围墙
case 3: printf("@");break; //3代表蛇身用@表示
case 4: printf("$");break; //4代表食物用$表示
}
printf("
");
}
Sleep(400); //睡眠函数,使程序暂停0.4秒,防止运行太快
}
}

以上程序都在一个main()函数里实现的,导致程序内部结构有些混乱,更改及阅读起来比较效率,我们可以分开用几个函数来实现

(1)初始化函数 init() 用来初始化地图

(2)显示界面函数 show() 用来每次更新后,重新显示新的界面

(3)控制蛇移动的函数 move() 用来响应键盘输入,控制蛇的移动

更改后的程序如下

#include <stdio.h>
#include<Windows.h>
#include<conio.h>

int map[20][40]; //二维数组map[][],用来表示游戏地图
//为0时,表示空白,什么都没有
//为1时,表示上下围墙
//为2时,表示左右围墙
//为3时,表示蛇
//为4时,表示食物

int snake_x=10,snake_y=20; //用来表示蛇的位置坐标

void show() //显示界面
{
for(int i=0;i<20;i++) //列印地图
{
for(int j=0;j<40;j++)
switch(map[i][j])
{
case 0: printf(" ");break; //0代表空格,什么也不列印
case 1: printf("-");break; //1代表上下围墙
case 2: printf("|");break; //2代表左右围墙
case 3: printf("@");break; //3代表蛇身用@表示
case 4: printf("$");break; //4代表食物用$表示
}
printf("
");
}
}

void init() //初始化地图
{
int i,j;
for(i=0;i<20;i++)
for(j=0;j<40;j++)
map[i][j]=0; //初始化二维数组,全部置为0

for(i=0;i<20;i++)
for(j=0;j<40;j++)
{
if(i==0||i==19)
map[i][j]=1; //赋值上下围墙 --------------
if(j==0||j==39)
map[i][j]=2; //赋值左右围墙|||||||||||||||
}

map[snake_x][snake_y]=3; //利用变数在地图中间初始化蛇身
map[15][6]=4; //初始化食物位置,随便定义了一个位置
show();
}

void move() //响应键盘输入,控制蛇的移动
{
map[snake_x][snake_y]=0; //更新地图,将蛇的老位置赋值为0
if(kbhit())
{
char c;
c=getch();
switch(c)
{
case w:snake_x--; break; //按w键,蛇向上移动
case s:snake_x++; break; //按s键,蛇向上移动
case a:snake_y--; break; //按a键,蛇向上移动
case d:snake_y++; break; //按d键,蛇向上移动
default: break;
}
}
map[snake_x][snake_y]=3; //更新地图,将蛇的新位置赋值为3
}
void main()
{
init();
while(1)
{
system("CLS"); //清屏函数,清除屏幕内容
move();
show();
Sleep(400); //睡眠函数,使程序暂停0.4秒,防止运行太快
}
}

不过好像贪吃蛇不是这样运动的,它应该是自己不间断的运动,不需要我们一步一步的控制,如果这样,可能就永远都不会死了,下一节咱们将实现贪吃蛇自己运动

推荐阅读:

相关文章