游戏的静态初始化已经完成,下面要做的就是动态逻辑的编写,在游戏开始后,我们需要实现的有几个功能:在不按下按键(上下左右)时,蛇朝着默认方向前进,在按下方向键时,蛇改变前进方向,如果蛇撞到墙或者咬到自己,则游戏结束。那么问题来了,如何用代码实现键盘控制方向呢,这里用到的是short GetAsyncKeyState(int nVirtKey);方法,该方法传入的参数nVirtKey为虚拟键盘值常量,这样一来,通过传入的nVirtKey参数我们就可以控制蛇的方向了,同理,加速减速以及暂停等功能也可以实现。
/*
控制键盘按键
*/
void keyboardControl()
{
status=R; //初始蛇向右移动
while(1)
{
scoreandtips();
if(GetAsyncKeyState(VK_UP) && status!=D) //GetAsyncKeyState函数用来判断函数调用时指定虚拟键的状态
{
status=U; //如果蛇不是向下前进的时候,按上键,执行向上前进操作
}
else if(GetAsyncKeyState(VK_DOWN) && status!=U) //如果蛇不是向上前进的时候,按下键,执行向下前进操作
{
status=D;
}
else if(GetAsyncKeyState(VK_LEFT)&& status!=R) //如果蛇不是向右前进的时候,按左键,执行向左前进
{
status=L;
}
else if(GetAsyncKeyState(VK_RIGHT)&& status!=L) //如果蛇不是向左前进的时候,按右键,执行向右前进
{
status=R;
}
if(GetAsyncKeyState(VK_SPACE)) //按暂停键,执行pause暂停函数
{
while(1)
{
Sleep(300); //sleep()函数,头文件#include 令进程暂停,直到达到里面设定的参数的时间
if(GetAsyncKeyState(VK_SPACE)) //按空格键暂停
{
break;
}
}
}
else if(GetAsyncKeyState(VK_ESCAPE))
{
endgamestatus=3; //按esc键,直接到结束界面
break;
}
else if(GetAsyncKeyState(VK_F1)) //按F1键,加速
{
speedup();
}
else if(GetAsyncKeyState(VK_F2)) //按F2键,减速
{
speeddown();
}
Sleep(sleeptime);
snakemove();
}
}
蛇在前进时,是通过新建头节点,擦去尾节点实现的,并且在吃到食物时,会自动加速。
/*
控制方向
*/
void snakemove() //蛇前进,上U,下D,左L,右R
{
snake * nexthead;
cantcrosswall();
nexthead=(snake*)malloc(sizeof(snake)); //为下一步开辟空间
if(status==U)
{
nexthead->x=head->x; //向上前进时,x坐标不动,y坐标-1
nexthead->y=head->y-1;
nexthead->next=head;
head=nexthead;
q=head; //指针q指向蛇头
if(nexthead->x==food->x && nexthead->y==food->y) //如果下一个有食物 下一个位置的坐标和食物的坐标相同
{
while(q!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆"); //原来食物的位置,从●换成◆
q=q->next; //指针q指向的蛇身的下一位也执行循环里的操作
}
score=score+add; //吃了一个食物,在总分上加上食物的分
speedup();
createfood(); //创建食物
}
else
{
while(q->next->next!=NULL) //如果没遇到食物
{
gotoxy(q->x,q->y);
color(14);
printf("◆"); //蛇正常往前走,输出当前位置的蛇身
q=q->next; //继续输出整个蛇身
}
gotoxy(q->next->x,q->next->y); //经过上面的循环,q指向蛇尾,蛇尾的下一位,就是蛇走过去的位置
color(3);
printf("■");
free(q->next); //进行输出■之后,释放指向下一位的指针
q->next=NULL; //指针下一位指向空
}
}
if(status==D)
{
nexthead->x=head->x; //向下前进时,x坐标不动,y坐标+1
nexthead->y=head->y+1;
nexthead->next=head;
head=nexthead;
q=head;
if(nexthead->x==food->x && nexthead->y==food->y) //有食物
{
while(q!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
score=score+add;
speedup();
createfood();
}
else //没有食物
{
while(q->next->next!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
gotoxy(q->next->x,q->next->y);
color(3);
printf("■");
free(q->next);
q->next=NULL;
}
}
if(status==L)
{
nexthead->x=head->x-2; //向左前进时,x坐标向左移动-2,y坐标不动
nexthead->y=head->y;
nexthead->next=head;
head=nexthead;
q=head;
if(nexthead->x==food->x && nexthead->y==food->y)//有食物
{
while(q!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
score=score+add;
speedup();
createfood();
}
else //没有食物
{
while(q->next->next!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
gotoxy(q->next->x,q->next->y);
color(3);
printf("■");
free(q->next);
q->next=NULL;
}
}
if(status==R)
{
nexthead->x=head->x+2; //向右前进时,x坐标向右移动+2,y坐标不动
nexthead->y=head->y;
nexthead->next=head;
head=nexthead;
q=head;
if(nexthead->x==food->x && nexthead->y==food->y)//有食物
{
while(q!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
score=score+add;
speedup();
createfood();
}
else //没有食物
{
while(q->next->next!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("◆");
q=q->next;
}
gotoxy(q->next->x,q->next->y);
color(3);
printf("■");
free(q->next);
q->next=NULL;
}
}
if(biteself()==1) //判断是否会咬到自己
{
endgamestatus=2;
endgame();
}
}
加速代码即缩短时间间隔,同时得分增加。
/*
加速,蛇吃到食物会自动提速,并且按F1会加速
*/
void speedup()
{
if(sleeptime>=50)
{
sleeptime=sleeptime-10;
add=add+2;
}
}
减速亦然。
/*
减速,按F2会减速
*/
void speeddown()
{
if(sleeptime<350) //如果时间间隔小于350
{
sleeptime=sleeptime+30; //时间间隔加上30
add=add-2; //每吃一次食物的得分减2
}
}
如何判断蛇是否咬到自己,是通过遍历蛇身节点判断是否重复实现的。
/*
判断是否咬到了自己
*/
int biteself()
{
snake *self; //定义self为蛇身上的一个节点
self=head->next; //self是蛇头之外的蛇身上的节点
while(self!=NULL)
{
if(self->x==head->x && self->y==head->y) //如果self和蛇身上的节点重合
{
return 1; //返回1
}
self=self->next;
}
return 0;
}
而撞墙检查更为简单,判断头节点与上下左右“墙”的坐标值是否重合即可。
/*
设置蛇撞墙的情况
*/
void cantcrosswall()
{
if(head->x==0 || head->x==56 ||head->y==0 || head->y==26) //如果蛇头碰到了墙壁
{
endgamestatus=1; //返回第一种情况
endgame(); //出现游戏结束界面
}
}
至此,游戏动态逻辑的编写已经完成。