c语言课程设计,一条蛇该怎么办?
贪吃蛇游戏是一款经典的小游戏。一条蛇在封闭的墙壁里,一种食物随机出现在墙壁里。通过按键盘上的四个光标键,控制蛇上下左右移动。蛇头击倒食物,食物被吃掉,蛇身增长10点。然后,食物就会出现,等着蛇来吃。如果蛇在运动过程中撞到墙壁或穿过身体,游戏就结束了。
2.2程序总体设计描述
一个游戏应该有开始部分、运行部分和结束部分(其实开始部分和运行部分是一体的)。
2.2.1设计思路
这个程序的关键是表现蛇的形状和它的运动。一个小矩形用来代表蛇身体的一部分。对于身体的每个部分,添加一个矩形块,蛇头用两个部分表示。移动时必须从蛇头开始,所以蛇不能反方向移动,也就是不能把蛇尾变成蛇头。如果不按任何键,蛇会自己朝当前方向前进。当玩家按下有效方向键时,蛇头会向指定方向移动,一次移动一个身体。所以按下有效方向键后,会先确定蛇头的位置,然后蛇身会随着蛇头移动。图形的实现是从蛇头的新位置开始画蛇。此时由于缺少清平,原蛇的位置与新蛇的位置相差一个单位,所以看起来不一样。食物的出现和消失也是绘制和覆盖矩形块。
2.2.2数据结构设计和使用说明?
开始部分:
游戏是在图形模式下运行的,所以第一步必须是初始化图形模式,然后必须有一个启动界面。就像一本书有封面一样,我设置了游戏的标题屏,除了游戏的标题屏,我还设置了欢迎屏。标题画面之后,需要初始化游戏的运行部分,包括绘制游戏的运行背景,初始化游戏的一些重要变量。
运行部件:
作为游戏的核心部分,这里有很多功能,也就是有很多模块。先来模拟一下蛇的游戏模式:某个世界突然出现一条蛇,它身材矮小,运动神经异常,无法阻止它的多动症。在它的世界里,只有食物,它饥饿而贪婪;同样,不知什么原因,食物从天而降,可惜没有落到嘴里;饥饿的英雄,不管有没有毒,不问食物的来历,径直爬向食物;它吃过食物,超乎想象的同化能力让食物很快成为自己身体的一部分,身体变长。它吃第一个食物的时候,上帝没有给它第二个,它就吃了第二个,然后变长了,然后就有了第三个?它的身体一直在加长。它并不在意自己长身体的麻烦——不方便转身继续吃。现在它只是打开了吧台,让食物可以有绿色通道。但是有一天下午,它咬了自己一口,它才想起来那是一条毒蛇,于是就晕倒了(不是中毒);或者当它冲向食物时,它失去了控制,撞到了墙上。
第一个循环:第一步,食物出现;第二步,蛇继续移动;第三步,检查蛇是撞自己还是撞墙;从第四步开始,游戏有两个分支(A和B):
答:第四步,蛇不碰自己也不碰墙,蛇继续前进,画出蛇的动作;第五步,判断蛇是否吃过食物。如果蛇吃过食物,它的身体会变长,原有的食物会消失。步骤6,让玩家输入控制指令,使蛇在下一个循环的第二步改变移动方向;第七,第二循环的第一步,重复第一步;
b:第四步,蛇触碰自己或墙壁,终止游戏。
结尾部分:
游戏结束时显示“游戏结束”,这是既定规则,我的游戏也不例外。除了游戏结束画面,我还设置了一个游戏退出画面,“开始好,结束好”。
有了上面的大致划分,我把整个程序分成了(13+2)个模块(其实就是函数)。
程序结构(流程图)
图2.1流程图
根据要处理的任务需求,规划输入数据和输出结果,确定存储数据的数据结构。
C语言的数据结构集中在数据类型上,所以用C语言编程时,变量、数组、指针等。程序中使用的及其类型应统筹规划。这一点非常重要。如果在此期间选择了不合适的变量或数组,以后要修改就非常困难了。
现在分析贪吃蛇游戏中的元素,然后在程序中得到它们对应的描述:
蛇:
基本描述:长度、颜色和位置。
对应的数据和数据类型:长度——虽然可以用坐标表示,但这种情况下,运算量会很大,所以换算成更大的单位——段数,用每个段固定长度来描述;坐标-整数;颜色-整数;位置-x,y坐标。
补充说明:蛇的运动方向,蛇的生命。
对应的数据和数据类型:这些描述被设计成与程序的键输入部分和游戏的判定结束部分相关联。只有四个方向:上、下、左、右。可以设置4个对应的整数:3,4,2,1。人生只有两种情况:死或生,对应0或1。
食物:
基本描述:颜色,位置。
对应数据和数据类型:既然颜色设置为固定,就不再讨论了。位置-x,y坐标。
补充说明:食物的存在。
对应数据和数据类型:这个是为了避免食物重复而设置的,和画食物的功能有关。只有两个值:0或1(无食或食)。
其他元素:墙壁,因为是作为背景存在于显示器中的,所以没什么好说的,实际的墙壁是由四条直线组成的边界,用坐标来描述。
还需要变量:键盘输入的键值(作为全局变量,整数);经常使用的循环变量;自定义填充图案;描述文本的字符数组;游戏的分数;游戏的速度(蛇的速度)。
图2.2蛇不停运动的关键算法流程图。
2.2.4各模块的功能和程序描述
阐述了主要模块的实现思路和算法流程图:
关键点-Snakemove():
蛇一直在动,就是蛇的下一段的位置替换了上一段,在电脑里,蛇的下一段的位置坐标就变成了上一段的位置坐标。在上面,已经定义了蛇的位置坐标是数组类型,并且一组坐标对应于一个部分的位置。假设有i+1段,从0到I段,I段坐标取i-1段坐标,i-1段坐标取i-2段坐标?取0段坐标,直到1段。第0段的坐标,也就是蛇头的坐标,会随着蛇每一段的长度而发生一定方向的变化。蛇的坐标旋转需要一个循环语句来继续。?
程序结果
运行程序,得到如下初始界面图:
图2.3程序结果图
一个小矩形用来代表蛇身体的一部分。对于身体的每个部分,添加一个矩形块,蛇头由两个部分表示:
图2.4程序结果图
蛇没有碰到自己或墙壁,它继续前进:
图2.5程序结果图
游戏结束时,显示“游戏结束”。
图2.6程序结果图
2.3程序源代码和注释
#定义N 200
# include & ltgraphics.h & gt
# include & ltstdlib.h & gt
# include & ltdos.h & gt
#定义左0x4b00
#定义右0x4d00
#向下定义0x5000
#定义高达0x4800
#定义ESC 0x011b
int i,key
int得分= 0;/*分数*/
int gamespeed = 50000/*自己调整游戏速度*/
结构食品
int x;/*食物横坐标*/
int y;/*食物的纵坐标*/
int yes/*判断食物的变量是否会出现*/
}食物;/*食物的结构*/
结构蛇{
int x[N];
int y[N];
int节点;/*蛇的结数*/
int方向;/*蛇的移动方向*/
int life/*蛇的命,0是活的,1是死的*/
}蛇;
void Init(void);/*图形驱动程序*/
void Close(无效);/*图表结束*/
void DrawK(无效);/*开始屏幕*/
void game over(void);/*结束游戏*/
void玩法(void);/*玩游戏的具体流程*/
void PrScore(void);/*输出结果*/
/*主函数*/
无效主(无效){
init();/*图形驱动程序*/
DrawK();/*开始屏幕*/
游戏性();/*玩游戏的具体流程*/
close();/*图形结束*/}
/*图形驱动程序*/
void Init(void){
int gd=DETECT,GM;
registerbgidriver(EGA VGA _ driver);
init graph(& amp;gd,& ampgm," c:\ \ program files \ \ winyes \ \ tc20h \ \ bgi ");
clear device();}
/*开始屏幕,左上角坐标为(50,40),右下角坐标为(610,460 */
void DrawK(void){
/*setbkcolor(浅绿色);*/
set color(11);
setlinestyle(SOLID_LINE,0,THICK _ WIDTH);/*设置线型*/
for(I = 50;我& lt=600;I+=10)/*画栅栏*/?{
矩形(I,40,i+10,49);/*高于*/
矩形(I,451,i+10,460);/* Below */?}
for(I = 40;我& lt=450;i+=10)?{
矩形(50,I,59,I+10);/*左*/
矩形(601,I,610,I+10);/* Right */}}
/*玩游戏的具体流程*/
无效游戏(无效){
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();/*输出分数*/
而(1)/*可以反复玩游戏,按ESC结束*/?{
而(!Khit ())/*蛇不按按钮就自己移动*/?{
If(food.yes==1)/*需要新的食物*/{
food . x = rand()% 400+60;
food . y = rand()% 350+60;
而(food.x%10!=0)/*食物随机出现后,食物必须在整个格子里,蛇才能吃*/
food . x++;
而(food.y%10!=0)
food . y++;
food . yes = 0;/*屏幕上有食物*/}
If(food.yes==0)/*如果屏幕上有食物,将显示*/{
setcolor(绿色);
矩形(food.x,food.y,food.x+10,food . y-10);}
for(I = snake . node-1;我& gt0;I-)/*蛇的每一个环节都向前移动,这是蛇的关键算法*/{
snake . x[I]= snake . x[I-1];
snake . y[I]= snake . y[I-1];}
/*1,2,3,4表示右,左,上,下,这个判断可以移动蛇头*/
开关(蛇形方向){
case 1:snake . x[0]+= 10;打破;
案例二:snake . x[0]-= 10;打破;
案例三:snake . y[0]-= 10;打破;
案例四:snake . y[0]+= 10;打破;}
for(I = 3;我& ltsnake .节点;I++)/*从蛇的第四节判断是否打中自己,因为蛇头有两节,第三节不可能转身*/{
if(snake . x[I]= = snake . x[0]& amp;& ampsnake.y[i]==snake.y[0]) {
game over();/*显示失败*/
snake . life = 1;
打破;} }
if(snake . x[0]& lt;55 | | snake . x[0]& gt;595 | | snake . y[0]& lt;55||
snake . y[0]& gt;455)/*蛇有没有撞到墙上*/{
game over();/*这个游戏结束了*/
snake . life = 1;/*蛇死了*/}
If(snake.life==1)/*以上两个判断后,如果蛇死了,跳出内循环重新开始*/
打破;
if(snake . x[0]= = food . x & amp;& ampSnake.y[0]==food.y)/*吃完饭*/{
set color(0);/*从图片中移除食物*/
矩形(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;/*新食物需要出现在屏幕上*/
得分+= 10;
PrScore();/*输出新分数*/}
set color(4);/*画一条蛇*/
for(I = 0;我& ltsnake .节点;i++)
矩形(snake.x[i],snake.y[i],snake.x[i]+10,
snake . y[I]-10);
延迟(gamespeed);
set color(0);/*用黑色去掉蛇的最后一段*/
矩形(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)/*如果蛇死了,跳出循环*/
打破;
key = BIOS key(0);/*接收按钮*/
If(key==ESC)/*按ESC退出*/
打破;
其他
if(key = = UP & amp;& amp蛇,方向!=4)
/*判断是否向相反方向移动*/
snake . direction = 3;
其他
if(key = = RIGHT & amp;& amp蛇,方向!=2)
snake . direction = 1;
其他
if(key = = LEFT & amp;& amp蛇,方向!=1)
snake . direction = 2;
其他
if(key = = DOWN & amp;& amp蛇,方向!=3)
snake . direction = 4;
}/*endwhile(1)*/}
/*游戏结束*/
void GameOver(void){
clear device();?
PrScore();
setcolor(红色);
settextstyle(0,0,4);
outtextxy(200,200,“游戏结束”);
getch();}
/*输出结果*/
void PrScore(void){?
char str[10];
setfillstyle(SOLID_FILL,黄色);
吧(50,15,220,35);
set color(6);
settextstyle(0,0,2);
sprintf(str," score:%d ",score);
outtextxy(55,20,str);}
/*图表结束*/
void Close(void){?
getch();
closegraph();
}