贪吃蛇软件设计.docx
《贪吃蛇软件设计.docx》由会员分享,可在线阅读,更多相关《贪吃蛇软件设计.docx(21页珍藏版)》请在冰豆网上搜索。
贪吃蛇软件设计
《软件开发》
课程设计报告
题目:
贪吃蛇游戏设计
院(系):
专业班级:
学生姓名:
学号:
指导教师:
评分:
1课程设计的目的1
2总体设计2
3详细设计3
3.1游戏开始模块3
3.2初始化模块7
3.3游戏运行模块8
3.4游戏结束模块11
4调试与测试13
5总结14
参考文献15
1课程设计的目的
贪吃蛇起源于西方,来自于夏娃和亚当偷吃禁果的神话。
人们为了说明蛇的一个“贪”字,开始开发贪吃蛇这个游戏。
选择这个题目的一是:
一直以来贪吃蛇这个小游戏就蛮吸引人,游戏的实现对于我们而言很神秘,希望运用所学的知识真真正正了解它的实质和精髓;二是更进一步的掌握C语言以及数据结构的理论知识和实际应用,熟悉基本的游戏软件开发过程。
在这个游戏中,环境为密闭的围墙内,在围墙内随机出现一个食物,通过按键盘上四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,这时蛇的身体长一节,同时计10分,接着又出现食物,等待被蛇吃掉。
如果蛇在移动的过程中蛇撞到墙的任何一处游戏结束。
游戏的关键在于蛇的移动和蛇吃了食物后的增长。
游戏过程中,通过控制方向,蛇开始移动,通过从蛇尾开始向前复制给蛇尾的前一节一直到蛇头复制给前一节然后清空蛇尾实现对蛇的移动。
蛇吃了食物增长的过程,首先是判断是否吃到食物,吃到食物后蛇尾增加一节,从这一节开始复制给前一节,蛇运动。
食物的出现和消失,分数的增加,蛇尾都是定义数组的方式,通过调用各个模块函数实现整个游戏的过程。
功能需求:
1.初始化:
通过init()函数实现。
2.画面颜色:
通过color()函数实现。
3.蛇运动:
通过Move()函数和memcpy()函数实现。
4.判断蛇出界:
通过Block()函数实现。
5.吃食物:
通过Eat()函数实现。
6.蛇身变长:
通过Draw()函数实现
7.运行界面设置:
通过Manual()函数实现。
8.历史最高分设置:
通过File_in()函数取记录分数。
9.是否闯关成功设置:
通过File_out()函数存取的数据实现。
10.释放空间设置:
通过Free()函数实现。
11.按键停止设置:
通过kbhit()函数实现。
12.结束游戏:
通过exit()函数实现。
2总体设计
.整体框图如下:
二.将此系统化分为如下模块:
1.游戏开始:
首先从main()函数开始运行,调用各个函数。
2.初始化设置模块:
用init()函数实现,初始化程序和设置游戏的一些前期准备。
1墙面设计:
通过if语句。
2定位蛇身:
通过定义Snake[]数组。
3画出食物:
通过定义apple[]数组。
3.游戏运行的具体过程:
1蛇移动:
通过调用Draw()函数实现。
2吃食物:
通过调用Eat()函数实现。
3蛇身变长:
通过定义蛇尾tail[]数组实现。
4判断死亡:
通过调用Block()函数判断是否出界。
4.游戏结束:
调用Manual()函数,实现运行界面设置。
1分数显示:
通过定义score[]数组记录分数。
2历史最高分:
通过调用File」n()函数取File_out()函数存取的记录分数。
3文字说明:
通过调用Manual()函数设置运行界面来显示。
3详细设计
3.1游戏开始模块
.主函数main()
主函数是程序的主流程,首先定义使用得到的常量、全局变量及函数类型说明,然后初始图形系统。
intmain(void)
{
intlen;//
随机数发生器的初始化函数(使用系统函数指向空指针)
color(11);//调用颜色函数为淡青
File_in();//调用函数记录分数
init(a,&snake,&len);//init()函数开始初始化,返回值为显示分数数组
Manual();//
while(ch!
=0x1B)/*
{
Draw(snake,len);//
if(!
apple[2])//
{
a[],蛇的地址和蛇身地址调用函数游戏运行界面开始启动按ESC结束*/
调用蛇运动函数,返回值为蛇头和蛇身
如果apple[2]返回值为0,则食物被吃掉
apple[0]=rand()%N+1;//
apple[1]=rand()%N+1;//apple[2]=1;//
}
Sleep(200-score[3]*10);//
即随机产生食物的横坐标
即随机产生食物的纵坐标
即食物未被吃掉
速度设置固定值
setbuf(stdin,NULL);//
if(kbhit())//
{
gotoxy(0,N+2);//ch=getche();//
}
清空内存缓冲区
判断是否按键
snake=Move(snake,ch,&len);//if(Block(snake[0])==1)//
{
移向屏幕此处坐标
输出所按的字母
调用蛇运动函数,返回值为数组蛇,字符g,蛇长的地址如果数组Snake[0]赋1值则蛇撞墙
gotoxy(N+2,N+2);//puts("File_out();//Free(snake,len);//getche();//exit(0);//
光标移到此坐标上
你输了");//输出文字“你输了”调用存分数的函数,输出得分释放存储蛇与蛇长的内存空间输出按键的字母退出主函数
对应流程图如下:
.输出坐标gotoxy
)函数
voidgotoxy(intx,inty)//{
COORDpos;//pos.X=x;//pos.Y=y;
函数名为gotoxy,返回值为整形变量x,y
一个字符在控制屏幕上的坐标
分别将屏幕上的横、纵坐标赋给x,y
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}//使光标到(x,y)这个位置的函数
.颜色color()函数
voidcolor(intb)/*颜色函数*/
{
HANDLEhConsole=GetStdHandle((STD_OUTPUT_HANDLE));//屏幕输出
SetConsoleTextAttribute(hConsole,b);//背景色
}
四.界面设置函数Manual()
voidManual()/*运行界面设置*/
{
gotoxy(N+30,2);//光标移向此处
color(10);//"按WSAD移动方向""按space键暂停"颜色设置为淡绿色
printf("按WSAD移动方向");
gotoxy(N+30,4);
printf("按space键暂停");
gotoxy(N+30,8);
color(11);//"历史最高分为:
""你现在得分为:
0"颜色设置为淡青色
printf("历史最高分为:
");
color(12);
gotoxy(N+44,8);
printf("%d",score[1]*10);//最高分的分数颜色设置为红色
color(11);
gotoxy(N+30,12);
printf("你现在得分为:
0");
3.2初始化模块
初始化函数init()
voidinit(charplate[N+2][N+2],char***snake_x,int*len)/*初始化程序,
给一些初始值赋上值*/
{
inti,j;
char**snake=NULL;//蛇头赋空
*len=3;//蛇身起始长度为3
score[0]=score[3]=3;//分数起始为3
snake=(char**)realloc(snake,sizeof(char*)*(*len));//为snake
动态分配一个二维的字符数组
for(i=0;i<*len;++i)snake[i]=(char*)malloc(sizeof(char)*2);//为蛇分配内存
for(i=0;i<3;++i)//
{
snake[i][0]=N/2+1;//
snake[i][1]=N/2+1+i;
}
for(i=1;i<=N;++i)//for(j=1;j<=N;++j)plate[i][j]=1;//apple[0]=rand()%N+1;//apple[1]=rand()%N+1;apple[2]=1;
for(i=0;i蛇头开始出现的位置(固定值)
设置蛇的起始位置在墙内的中心坐标
苹果开始随机出现在墙内的位置
定义墙内的坐标数组
随机出现食物
蛇运动内的21X21墙设置成淡蓝色的框
{
gotoxy(0,i);
for(j=0;jswitch(plate[i][j])//
{
判断是否为墙内的数组坐标
case0:
color(12);
printf("□");//color(11);continue;
不是,则设置墙的边界为红色的空框
case1:
printf("■");//
continue;
是,设置墙的内部为淡青的实框
default:
;}
}putchar('\n');
}
for(i=0;i<(*len);++i)〃循环,蛇头开始的每一节都打印成^
{
gotoxy(snake[i][1]*2,snake[i][0]);//光标移向蛇的坐标数
组
printf("★");//打印蛇身为★
}
putchar('\n');
*snake_x=snake;
}
3.3游戏运行模块
一.判断出界函数Block()
intBlock(charhead[2])//蛇头出界则死亡,游戏结束
{
if((head[0]<1)||(head[0]>N)||(head[1]<1)||(head[1]>
N))//蛇头数组head[0]为蛇头横坐标,head[1]为纵坐标,1,N分别为墙边界如果蛇头超出墙四边界任何一处,则蛇停止运动,打印分数和文字说明return1;
return0;
}
二.蛇吃食物函数Eat()
intEat(charsnake[2])/*吃了食物*/
{
if((snake[0]==apple[0])&&(snake[1]==apple[1]))
//snake[0]、nake[1]分别表示蛇头的横纵坐标,
apple[0]apple[1]分别表示食物的横纵坐标。
如果分别相等,则蛇吃到食物。
{
apple[0]=apple[1]=apple[2]=0;//食物数组赋给0,
则食物消失gotoxy(N+44,10);
color(13);
printf("%d",score[0]*10);//加十分打印分数
color(11);//设置分数为淡青色
return1;//吃了食物返回1
}
return0;
}
三.蛇移动函数Draw()
voidDraw(char**snake,intlen)/返回值为蛇头指针,蛇长
{
if(apple[2])//如果返回值为1,则食物被吃掉
{
gotoxy(apple[1]*2,apple[0]);/*产生食物*/
color(12);//食物颜色为红色
printf("•");
color(11);//其他区域为淡青色
}
蛇尾坐标*2,蛇尾变成两个
gotoxy(tail[1]*2,tail[0]);//
if(tail[2])//蛇尾如果变长后tail[2]等于1
{color(14);//蛇身颜色设置为黄色
printf("★");//则输出一节蛇
color(11);//其他区域为淡青色
}
else
printf("■");//否则输出背景框图,蛇移动
gotoxy(snake[0][1]*2,snake[0][0]);
color(14);
printf("★");
color(11);putchar('\n');
}
四.控制蛇运动函数Move()
char**Move(char**snake,chardirx,int*len)//函数返回值为蛇头指针,方向,蛇的长度
{定义变量i和full=蛇吃到食物memcpy(tail,snake[(*len)-1],2);//该函数的功能为把蛇运动过程的
蛇尾前一节复制到蛇尾实现蛇身的运动过程
循环,将蛇身的每一节都复制给
蛇在运动
蛇整体向上移动蛇整体向下移动蛇整体向左移动蛇整体向右移动
for(i=(*len)-1;i>0;--i)//
前一节
memcpy(snake[i],snake[i-1],2);//switch(dirx)//控制蛇运动的方向{
case'w':
case'W':
--snake[0][0];break;//
case's':
case'S':
++snake[0][0];break;//
case'a':
case'A':
--snake[0][1];break;//
case'd':
case'D':
++snake[0][1];break;//default:
;
}if(full)//蛇吃到食物后
{
snake=(char**)realloc(snake,sizeof(char*)*((*len)+1));
//为snake动态分配一个二维的字符数组,存储增加的蛇长snake[(*len)]=(char*)malloc(sizeof(char)*2);memcpy(snake[(*len)],tail,2);
++(*len);//蛇身的长度加1++score[0];//分数也加10
if(score[3]<16)
++score[3];//起始分数加1
tail[2]=1;//蛇尾已经变长
}
else
tail[2]=0;//蛇尾没有变长
returnsnake;
}
3.4游戏结束模块
一.取记录分数的函数File_in()和存数据的函数File_out()intFile_in()/*取记录的分数*/
{
FILE*fp;//声明fp是指针,指向FILE类型的对象
if((fp=fopen("C:
\\tcs.txt","a+"))==NULL)
{
gotoxy(N+18,N+2);
printf("文件不能打开\n");
exit(0);
}
if((score[1]=fgetc(fp))!
=EOF);
else
score[1]=0;//否则次关得分为0
return0;
}
intFile_out()/*存数据*/
{
FILE*fp;
if(score[1]>score[0])//历史最高分大于此关得分,
则输出"闯关失败加油耶"{gotoxy(10,10);
color(12);
puts("闯关失败加油耶");
gotoxy(0,N+2);
return0;
}
if((fp=fopen("C:
\\tcs.txt","w+"))==NULL)
{
printf("文件不能打开\n");exit(0);
}
if(fputc(--score[0],fp)==EOF)printf("输出失败\n");
gotoxy(10,10);
color(12);
puts("恭喜您打破记录");//历史最高分小于此关得分,则输出"恭喜您打破记录"gotoxy(0,N+2);
return0;
}
二.释放snake存储空间函数Free()
voidFree(char**snake,intlen)//释放空间,返回值为蛇头指针,蛇长
{
inti;
for(i=0;ifree(snake);
}
4调试与测试
2.蛇初始有三节,蛇在运动的过程中吃第一个食物变成四节,分数变为30分,以后每次吃一个食物加十分。
蛇在运动过程中撞墙而亡,历史最高分为110,当前为30分,故输出“闯关失败加油耶”。
■■■■■■■■■■■■■■■■■■■★■_
□■■■■■■■■■■■■■■■■■■■“I
□□□□□□□□□□□□□□□□□□□□□[
LPressanykeyCocontinue了
5总结
(1)课程设计中遇到的主要问题和解决方法;
现在得分坐标输入错误,改动程序语句gotoxy(N+44,12);
printf("%d",score[0]*10);
历史最高分为二90
40
你现在得分为:
0
历史最高分为=90
你现在得分为:
锄
(2)创新和特色之处;设计中存在的不足,需进一步改进的设想
特色:
这个贪吃蛇的设计中,运用了color()函数对整个游戏的界面进行了美化使各个区域看起来也更加清晰明了。
也运用了File」n()和File_out()对历史的分数进行了记录和调用,增加了一个与历史最高分比较的功能。
不足:
在这个程序并没有涉及到对速度的选择。
参考文献
[1]谭浩强.C语言程序设计(第四版)•北京:
清华大学出版社,2010.
[2]严蔚敏,吴伟民.数据结构(C语言版)[M].北京:
清华大学出版社,2007.
[3]孙秀梅,曹飞飞.C语言项目案例分析.北京:
清华大学出版社,2012.
[4]曹计昌,卢萍.C语言与程序设计.北京:
电子工业出版社,2008.
⑸程海英.数据结构(C语言版).北京:
清华大学出版社,2014.
附录代码清单
#include
#include
#include
#include
#include
#defineN21
intapple[3];
charscore[3];
chartail[3];
voidgotoxy(intx,inty)//输出坐标
{
COORDpos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);}
voidcolor(intb)//颜色函数
{
HANDLEhConsole=GetStdHandle((STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(hConsole,b);
}
intBlock(charhead[2])//判断出界
{
if((head[0]<1)||(head[0]>N)||(head[1]<1)||(head[1]>N))return1;
return0;
}
intEat(charsnake[2])//吃了苹果{
if((snake[0]==apple[0])&&(snake[1]==apple[1])){
apple[0]=apple[1]=apple[2]=0;gotoxy(N+44,10);
color(13);printf("%d",score[0]*10);
color(11);
return1;
}
return0;
}
voidDraw(char**snake,intlen)//蛇移动
{
if(apple[2]){gotoxy(apple[1]*2,apple[0]);color(12);
printf("•");
color(11);
}
gotoxy(tail[1]*2,tail[0]);
if(tail[2])
{color(14);
printf("★");
color(11);
}
else
printf("■");
gotoxy(snake[0][1]*2,snake[0][0]);
color(14);
printf("★");
color(11);
putchar('\n');
}
char**Move(char**snake,chardirx,int*len)//控制方向
{
inti,full=Eat(snake[0]);memcpy(tail,snake[(*len)-1],2);
for(i=(*len)-1;i>0;--i)memcpy(snake[i],snake[i-1],2);
switch(dirx)
{
case'w':
case'W':
--snake[0][0];break;
case's':
case'S':
++snake[0][0];break;
case'a':
case'A':
--snake[0][1];break;
case'd':
case'D':
++snake[0][1];break;default:
;
}
if(full)
{
snake=(char**)realloc(snake,sizeof(char*)*((*len)+1));snake[(*len)]=(char*)malloc(sizeof(char)*2);
memcpy(snake[(*len)],tail,2);++(*len);
++score[0];if(score[3]<16)
++score[3];
tail[2]=1;
}
else
tail[2]=0;
returnsnake;
}
voidinit(charplate[N+2][N+2],char***snake_x,int*len)//初始化
{
inti,j;char**snake=NULL;
*len=3;score[0]