设计小游戏贪吃蛇.docx
《设计小游戏贪吃蛇.docx》由会员分享,可在线阅读,更多相关《设计小游戏贪吃蛇.docx(15页珍藏版)》请在冰豆网上搜索。
![设计小游戏贪吃蛇.docx](https://file1.bdocx.com/fileroot1/2023-1/7/7bd07f77-923e-4c18-96b8-944c30c3c08e/7bd07f77-923e-4c18-96b8-944c30c3c08e1.gif)
设计小游戏贪吃蛇
南昌航空大学
数学与信息科学学院
实验报告
课程名称:
C语言课程设计
实验名称:
设计小游戏贪吃蛇
实验类型:
验证性□综合性■设计性□
实验室名称:
数学实验室
班级学号:
090721190907212906072136
学生姓名:
王梓旭严飞翔熊文财
任课教师(教师签名):
成绩:
实验日期:
2011年11月30日
一、实验目的
通过游戏程序设计,提高编程兴趣与编程思路,巩固C语言中所学的知识,合理的运用资料,实现理论与实际相结合。
二、实验用仪器设备、器材或软件环境
计算机一台,WindowsXP,winTC.
三、实验原理、方案设计、程序框图、预编程序等
3.1程序的功能描述
贪吃蛇游戏是一个经典小游戏,一条蛇在封闭围墙里,围墙里随机出现一个食物,通过按键盘四个光标键控制蛇向上下左右四个方向移动,蛇头撞倒食物,则食物被吃掉,蛇身体长一节,同时记10分,接着又出现食物,等待蛇来吃,如果蛇在移动中撞到墙或身体叉蛇头撞倒自己身体游戏结束。
3.2设计思路及团队成员所承担的任务介绍
程序关键在于表示蛇的图形及蛇的移动。
用一个小矩形快表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用俩节表示。
移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇,这时,由于未清屏的原因,原来的蛇的位置和新蛇的位置差一个单位,所以看起来蛇多一节身体,所以将蛇的最后一节用背景色覆盖。
食物的出现与消失也是画矩形块和覆盖矩形块。
为了便于理解,定义两个结构体:
食物与蛇。
3.3程序中的函数模块功能介绍
(1)函数定义
函数定义是对各个基础函数的定义,并且设置需要运用的信息,便于调用
#defineN200
#include/*图形头文件*/
#include/*包含rand等函数*/
#include/*包含bios函数*/
#defineLEFT0x4b00/*光标左键值*/
#defineRIGHT0x4d00/*光标右键值*/
#defineDOWN0x5000/*光标下键值*/
#defineUP0x4800/*光标上键值*/
#defineESC0x011b/*ESC的ASCII码*/
inti,key;/*图形坐标变量及按键变量*/
intscore=0;/*得分*/
intgamespeed=10000;/*游戏速度自己调整*/
structFood
{
intx;/*食物的横坐标*/
inty;/*食物的纵坐标*/
intyes;/*判断是否要出现食物的变量*/
}food;/*食物的结构体*/
structSnake
{
intx[];/*蛇的横坐标*/
inty[];/*蛇的纵坐标*/
intnode;/*蛇的节数*/
intdirection;/*蛇移动方向*/
intlife;/*蛇的生命,0活着,1死亡*/
}snake;
voidInit(void);/*图形驱动*/
voidClose(void);/*图形结束*/
voidDrawK(void);/*画界面函数*/
voidGameOver(void);/*结束游戏*/
voidGamePlay(void);/*玩游戏具体过程*/
voidPrScore(void);/*输出成绩*/
voidmain(void)/*主函数*/
(2)主函数main()
主函数是程序的主流程,首先定义使用到的常数、全局变量及函数原型说明,然后初始化图形系统,调用函数DrawK()画出开始画面,调用函数GamePlay(),即玩游戏的具体过程,游戏结束后调用Close()关闭图形系统,结束程序
voidmain(void)/*主函数*/
{
Init();/*图形驱动*/
DrawK();/*开始画面*/
GamePlay();/*玩游戏具体过程*/
Close();/*图形结束*/
}
voidInit(void)/*图形驱动*/
{intgd=DETECT,gm;initgraph(&gd,&gm,"c:
\\tc");/*第一个参数表示图形适配器的类型,第二个为在该类型下图形的显示模式,第三个参数指定驱动程序所在目录。
*/
cleardevice();
}
(3)画界面函数DrawK()
主界面是一个封闭的围墙,用两个循环语句分别在水平和垂直方向输出连续的宽度和高度均的矩形方块,表示围墙,为了醒目,设置为白色。
voidDrawK(void)/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/
{
setbkcolor(0);/*设置当前背景颜色*/
setcolor(YELLOW);/*设置当前画线颜色*/
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);/*右边*/
}
}
(4)游戏具体过程函数GamePlay()
这是游戏的主要组成部分,他采用将前一节的坐标赋给后一节,用背景颜色将最后节去除,当蛇头的坐标与食物的坐标相等时,表示食物被吃掉了。
voidGamePlay(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];}switch(snake.direction)/*定义1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/
{
case1:
snake.x[0]+=10;break;
case2:
snake.x[0]-=10;break;
case3:
snake.y[0]-=10;break;
case4:
snake.y[0]+=10;break;
}
for(i=3;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;/*-20表示尾巴长一节*/
/*新的一节先放在看不见的位置,下次循环就取前一节的位置*/
snake.node++;/*蛇的身体长一节*/
food.yes=1;/*画面上需要出现新的食物*/
score+=10;
PrScore();/*输出新得分*/
}
setcolor(4);for(i=0;irectangle(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;
elseif(key==UP&&snake.direction!
=4)/*判断是否往相反的方向移动*/
snake.direction=3;
elseif(key==RIGHT&&snake.direction!
=2)
snake.direction=1;
elseif(key==LEFT&&snake.direction!
=1)
snake.direction=2;
elseif(key==DOWN&&snake.direction!
=3)
snake.direction=4;
}/*endwhile
(1)*/
}
(5)游戏结束函数GameOver()
游戏结束,清除屏幕,输出分数,显示游戏结束信息。
voidGameOver(void)/*游戏结束*/
{
cleardevice();
PrScore();
setcolor(RED);
settextstyle(0,0,4);
outtextxy(200,200,"guojian");
getch();
}
voidPrScore(void)/*输出成绩*/
{
charstr[10];
setfillstyle(SOLID_FILL,WHITE);
bar(50,15,200,35);
setcolor(6);
settextstyle(0,0,2);
sprintf(str,"score:
%d",score);
outtextxy(55,20,str);
}
voidClose(void)/*图形结束*/
{
getch();closegraph();
}
3.4程序的数据结构的分析
1)函数定义是要做到顾名思义是很重要的,它对读程序的人正确认识程序十分重要,在修改这个程序的过程中也能很快找到程序各模块的作用,大大增加了程序的可读性。
2)分析函数先从main()函数入手。
Main()函数是C源程序编译时的开始,从main()函数开始读函数可将其他函数的功能理解得更透彻。
3)在做程序的时候先列框架,将这个程序所要达到的目的(功能)分析出来,选择正确的数据结构然后在将程序模块化,按照模块编写函数更加简单合理。
4)我还了解了很多的库函数的作用,如字符串函数中有很多对字符串进行处理的函数,起功能我都有所了解。
3.5源程序代码
#defineN200
#include
#include
#include
#defineLEFT0x4b00
#defineRIGHT0x4d00
#defineDOWN0x5000
#defineUP0x4800
#defineESC0x011b
inti,key;
intscore=0;/*得分*/
intgamespeed=50000;/*游戏速度自己调整*/
structFood
{
intx;/*食物的横坐标*/
inty;/*食物的纵坐标*/
intyes;/*判断是否要出现食物的变量*/
}
food;/*食物的结构体*/
structSnake
{
intx[N];
inty[N];
intnode;/*蛇的节数*/
intdirection;/*蛇移动方向*/
intlife;/*蛇的生命,0活着,1死亡*/
}
snake;
voidInit(void);/*图形驱动*/
voidClose(void);/*图形结束*/
voidDrawK(void);/*开始画面*/
voidGameOver(void);/*结束游戏*/
voidGamePlay(void);/*玩游戏具体过程*/
voidPrScore(void);/*输出成绩*//*主函数*/
voidmain(void)
{
Init();/*图形驱动*/
DrawK();/*开始画面*/
GamePlay();/*玩游戏具体过程*/
Close();/*图形结束*/
}/*图形驱动*/
voidInit(void)
{
intgd=DETECT,gm;
initgraph(&gd,&gm,"c:
\\tc");
cleardevice();
}/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*
voidDrawK(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);/*右边*/
}
}/
*玩游戏具体过程*/voidGamePlay(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)
{
case1:
snake.x[0]+=10;break;
case2:
snake.x[0]-=10;break;
case3:
snake.y[0]-=10;break;
case4:
snake.y[0]+=10;break;
}
for(i=3;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;irectangle(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;
elseif(key==UP&&snake.direction!
=4)/*判断是否往相反的方向移动*/
snake.direction=3;
elseif(key==RIGHT&&snake.direction!
=2)
snake.direction=1;
elseif(key==LEFT&&snake.direction!
=1)
snake.direction=2;
elseif(key==DOWN&&snake.direction!
=3)
snake.direction=4;
}/*endwhile
(1)*/
}
/*游戏结束*/
四、实验过程中需要记录的实验数据表格
包含程序运行结果的截图,及截图说明
五、实验中存在的问题及解决方案
将已改好的程序复制到win-TC时,由于软件的内容过多会出现右移,以致大部分的内容无法复制到win-TC的界面上,最后导致软件无法运行。
解决方法:
在改程序时应该把格式设置好,注意左对齐,同时一行的语句尽量的短,最好是一个语句占一行。
在将程序输入到TC中,对源程序进行编译、运行,发现程序存在的多处错误,可以按照程序运行的错误提示对原程序进行修改,在调试过程中有时也会遇到不懂的问题,我去图书馆或上网查阅一些资料或者是向同学请教也解决了一些问题一一修改直到运行成功。
6、心得体会
经过短短两天的C语言的学习,让我对C程序有了一个更深的了解,以前总认为C语言很枯燥,认为那些我们所设计的程序没有什么用处,但现在通过设计贪吃蛇游戏这个程序使我懂得了如何将所学的知识运用于生活当中。
虽然在刚开始设计程序时不太明白如何去设计这程序,但当我看完《C语言课程设计案例精编》并用C语言做出这个贪吃蛇程序后,让我深深感受到C程序的神奇。
在设计这个程序中我主要学会了如何运用以下有关C语言的知识。