3.功能描述:本游戏主要实现以下几种功能
图1.游戏功能模块
3.1. 贪吃蛇的控制功能:通过各种条件的判断,实现对游戏蛇的左移、右移、下移、上移、自由移动,贪吃蛇的加长功能。
3.2. 游戏显示更新功能:当贪吃蛇左右移动、上下移动,以及身体加长时要清除先前的贪吃蛇图像,用新坐标重绘贪吃蛇。
3.3. 游戏分数更新功能:在游戏玩家进行游戏过程中,需要按照一定的游戏规则给游戏玩家计算游戏分数。比如,贪吃蛇每吃到一个事物就加十分。
4.数据结构设计:
4.1食物Food结构体
struct Food
{
int x;/*食物的横坐标*/
int y;/*食物的纵坐标*/
int yes;/*判断是否要出现食物的变量*/
}food;
4.2贪吃蛇snake的结构体
struct Snake
{
int x[N];
int y[N];
int node;/*蛇的节数*/
int direction;/*蛇移动方向*/
int life;/* 蛇的生命,0活着,1死亡*/
}snake;
5.程序设计实现:
5.1. 主函数main()
Main()函数主要实现了对整个程序的运行控制,以及相关功能模块的调用。
void Init(void);/*图形驱动*/
void Close(void);/*图形结束*/
void DrawK(void);/*开始画面*/
void GameOver(void);/*结束游戏*/
void GamePlay(void);/*玩游戏具体过程*/
void PrScore(void);/*输出成绩*/
void main(void)
{
Init();/*图形驱动*/
DrawK();/*开始画面*/
GamePlay();/*玩游戏具体过程*/
Close();/*图形结束*/
}
5.2. 图形驱动init()
Init()主要功能是初始化屏幕为图形模式函数。
void Init(void)
{
int gd=DETECT,gm;
initgraph(&gd,&gm,"c:\\tc");
cleardevice();
}
5.3. 开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙
void DrawK(void)
{
/*setbkcolor(LIGHTGREEN);*/
setcolor(11);
setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型*/
for(i=50;i<=600;i+=10)/*画围墙*/
{
rectangle(i,40,i+10,49); /*上边*/
rectangle(i,451,i+10,460);/*下边*/
}
for(i=40;i<=450;i+=10)
{
rectangle(50,i,59,i+10); /*左边*/
rectangle(601,i,610,i+10);/*右边*/
}
}
5.4. 玩游戏具体过程
主要实现游戏运行中的操作,以及分数更新等。
void GamePlay(void)
{
randomize();/*随机数发生器*/
food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/
snake.life=0;/*活着*/
snake.direction=1;/*方向往右*/
snake.x[0]=100;snake.y[0]=100;/*蛇头*/
snake.x[1]=110;snake.y[1]=100;
snake.node=2;/*节数*/
PrScore();/*输出得分*/
while(1)/*可以重复玩游戏,压ESC键结束*/
{
while(!kbhit())/*在没有按键的情况下,蛇自己移动身体*/
{
if(food.yes==1)/*需要出现新食物*/
{
food.x=rand()%400+60;
food.y=rand()%350+60;
while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到*/
food.x++;
while(food.y%10!=0)
food.y++;
food.yes=0;/*画面上有食物了*/
}
if(food.yes==0)/*画面上有食物了就要显示*/
{
setcolor(GREEN);
rectangle(food.x,food.y,food.x+10,food.y-10);
}
for(i=snake.node-1;i>0;i--)/*蛇的每个环节往前移动,也就是贪吃蛇的关键算法*/
{
snake.x[i]=snake.x[i-1];
snake.y[i]=snake.y[i-1];
}
/*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/
switch(snake.direction)
{
case 1:snake.x[0]+=10;break;
case 2: snake.x[0]-=10;break;
case 3: snake.y[0]-=10;break;
case 4: snake.y[0]+=10;break;
}
for(i=3;i<snake.node;i++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/
{
if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])
{
GameOver();/*显示失败*/
snake.life=1;
break;
}
}
if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||
snake.y[0]>455)/*蛇是否撞到墙壁*/
{
GameOver();/*本次游戏结束*/
snake.life=1; /*蛇死*/
}
if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内循环,重新开始*/
break;
if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/
{
setcolor(0);/*把画面上的食物东西去掉*/
rectangle(food.x,food.y,food.x+10,food.y-10);
snake.x[snake.node]=-20;snake.y[snake.node]=-20;
/*新的一节先放在看不见的位置,下次循环就取前一节的位置*/
snake.node++;/*蛇的身体长一节*/
food.yes=1;/*画面上需要出现新的食物*/
score+=10;
PrScore();/*输出新得分*/
}
setcolor(4);/*画出蛇*/
for(i=0;i<snake.node;i++)
rectangle(snake.x[i],snake.y[i],snake.x[i]+10,
snake.y[i]-10);
delay(gamespeed);
setcolor(0);/*用黑色去除蛇的的最后一节*/
rectangle(snake.x[snake.node-1],snake.y[snake.node-1],
snake.x[snake.node-1]+10,snake.y[snake.node-1]-10);
} /*endwhile(!kbhit)*/
if(snake.life==1)/*如果蛇死就跳出循环*/
break;
key=bioskey(0);/*接收按键*/
if(key==ESC)/*按ESC键退出*/
break;
else
if(key==UP&&snake.direction!=4)
/*判断是否往相反的方向移动*/
snake.direction=3;
else
if(key==RIGHT&&snake.direction!=2)
snake.direction=1;
else
if(key==LEFT&&snake.direction!=1)
snake.direction=2;
else
if(key==DOWN&&snake.direction!=3)
snake.direction=4;
}/*endwhile(1)*/
}
5.5. 游戏结束
结束游戏的运行。
void GameOver(void)
{
cleardevice();
PrScore();
setcolor(RED);
settextstyle(0,0,4);
outtextxy(200,200,"GAME OVER");
getch();
}
5.6. 输出成绩
其功能是输出玩家游戏结束后的分数。
void PrScore(void)
{
char str[10];
setfillstyle(SOLID_FILL,YELLOW);
bar(50,15,220,35);
setcolor(6);
settextstyle(0,0,2);
sprintf(str,"score:%d",score);
outtextxy(55,20,str);
}
5.7. 图形结束
结束图形驱动函数,退出程序。
void Close(void)
{ getch();
closegraph();
}
6.游戏设计过程与思路:
首先,明确该游戏所拥有的功能与游戏规则。
贪吃蛇的要求为:一条蛇在封密的围墙内,在围墙内随机出现一个食物。通过按键盘上的四个光标控键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,这时蛇的身体长一节,同时计10分,接着又出现食物,等待被蛇吃掉。如果蛇在移动过程中,撞到墙壁或蛇头撞到自己身体游戏结束。
这个程序的关键点是表示蛇的图形以及蛇的移动。可以用一个小矩形表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用两节表示。移动时必须从蛇头开始,所以蛇不能向相反移动,也就是蛇尾不能改作蛇头。如果不按任何键,蛇自行在当前方向上前移,当游戏者按了有效的方向键后,蛇头朝指定的方向移动,一步移动一节身体,所以当按了有效的方向键后,先确定蛇头的位置,然后蛇身体随着蛇头移动,图形的实现是从蛇头的新位置开始画出蛇。这时,由于没有清屏的原因,原来蛇的位置和新蛇的位置差一个单位,所以看起来蛇会多一节身体,应将蛇的最后一节用背景覆盖。食物的出现和消失也可以用画矩形块和覆盖矩形块方法实现。为了便于理解,可以定义两个结构体:食物和蛇。
整个游戏可分为四个步骤:
1. 自行设计开始界面,按键或鼠标点击开始游戏。
2. 显示游戏界面,按游戏规则进行游戏。
3. 画面实时显示选手得分,贪吃蛇每吃一个食物,蛇身长一节。
4. 结束时给出提示和得分。
7.结论:
本文讲述了贪吃蛇游戏的实现原理,对程序的模块设计、数据结构设计做了简单分析。并通过源码分析讲述了各个模块的实现方法。在几个模块的实现过程中渗透了部分图形功能函数。通过本文的编写过程 ,掌握了以下几点知识点:
- 图形系统的初始化和关闭
- 各种画图函数的使用
- 结构体的定义
- 数组定义及应用
- 函数嵌套及调用
- 键盘操作
参考文献:
【1】姜灵芝,余健. C语言课程设计案例精编 . 清华大学出版社 2008
【2】何援军 .计算机图形学. 机械工业出版社 2002
【3】 谭浩强 .C程序设计(第三版). 清华大学出版社 2005
【4】李春葆. 数据结构教程(第二版). 清华大学出版社 2007.3