(完整word版)贪吃蛇软件设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《软件开发》
课程设计报告
题目:贪吃蛇游戏设计院(系):
专业班级:
学生姓名:
学号:
指导教师:
评分:
目录
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 ()函数实现,初始化程序和设置游戏的一些先期准
备。
①墙面设计:经过if语句。
②定位蛇身:经过定义Snake[] 数组。
③画出食品:经过定义apple[]数组。
3.游戏运转的详细过程:
①蛇挪动:经过调用Draw()函数实现。
②吃食品:经过调用Eat ()函数实现。
③蛇身变长:经过定义蛇尾tail[]数组实现。
④判断死亡:经过调用Block ()函数判断能否出界。
4.游戏结束:调用 Manual() 函数,实现运转界面设置。
①分数显示:经过定义score[]数组记录分数。
②历史最高分:经过调用File_in()函数取File_out()函数存取的记录分数。
③文字说明:经过调用Manual() 函数设置运转界面来显示。
3详尽设计
3.1游戏开始模块
一.主函数 main()
主函数是程序的主流程,第一定义使用获得的常量、全局变量及函数种类说明,而后
初始图形系统。
int main(void)
{
int len; //定义蛇长
char ch = 'g';//定义字符g
char a[N+2][N+2] = {{0}};//定义初始的分数为0
char **snake;//定义蛇头
srand((unsigned)time(NULL));//随机数发生器的初始化函数( 使用系统函数
指向空指针 )
color(11);//调用颜色函数为淡青
File_in(); //调用函数记录分数
init(a, &snake, &len);//init()函数开始初始化,返回值为显示分数数组
a[] ,蛇的地点和蛇身地点
Manual(); //调用函数游戏运转界面开始启动
while (ch != 0x1B) /*按ESC结束*/
{
Draw(snake, len);//调用蛇运动函数,返回值为蛇头和蛇身
if (!apple[2]) //假如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); //调用蛇运动函数,返回值为数
组蛇,字符 g, 蛇长的地点if (Block(snake[0])==1) //假如数组Snake[0]赋1值则蛇撞墙{
gotoxy(N+2, N+2);//光标移到此坐标上
puts("你输了 ");//输出文字“你输了”
File_out();//调用存分数的函数,输出得分
Free(snake, len);//开释储存蛇与蛇长的内存空间
getche();//输出按键的字母
exit(0); //退出主函数
}
}
对应流程图以下:
开始
设置蛇头地点开端分数
初始化界面及调用颜色
搁置食品
蛇开始运动
N
N蛇吃到食品?
Y
蛇增添
蛇出界?
Y
输出“你输了”
退出界面
二.输出坐标 gotoxy ()函数
void gotoxy(int x, int y) //函数名为gotoxy,返回值为整形变量x,y
{
COORD pos; //一个字符在控制屏幕上的坐标
pos.X = x; //分别将屏幕上的横、纵坐标赋给x,y
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
} //使光标到(x,y)这个地点的函数
三.颜色 color ()函数
void color(int b)/*颜色函数*/
{
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;//屏幕输出
SetConsoleTextAttribute(hConsole,b) ; //背风景
}
四.界面设置函数Manual()
void Manual() /*运转界面设置*/
{
gotoxy(N+30,2);//光标移向此处
color(10); //"按W S A D挪动方向""按space键暂停"
颜色设置为淡绿色
printf("按 W S A D 挪动方向 ");
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()
void init(char plate[N+2][N+2], char ***snake_x, int *len) /*初始化程序,
给一些初始值赋上值
*/
{
int i, 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 < N + 2; ++i) //蛇运动内的21×21 墙设置成淡蓝色的框□
{
gotoxy(0, i);
for (j = 0; j < N + 2; ++j)
{
switch (plate[i][j]) //判断能否为墙内的数组坐标
{
case 0:
color(12);
printf(" □ ");//不是,则设置墙的界限为红色的空框
color(11);
continue;
case 1:
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 ()
int Block(char head[2]) //蛇头出界则死亡,游戏结束
{
if ((head[0] < 1) || (head[0] > N) || (head[1] < 1) || (head[1] >
N))
//蛇头数组 head[0] 为蛇头横坐标, head[1] 为纵坐标, 1,N 分别为墙界限假如蛇头高出墙四界限任何一处,则蛇停止运动,打印分数和文字说明
return 1;
return 0;
}
二.蛇吃食品函数Eat ()
int Eat(char snake[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);//设置分数为淡青色
return 1;//吃了食品返回1
}
return 0;
}
三. 蛇挪动函数 Draw()
void Draw(char **snake, int len) /返回值为蛇头指针,蛇长
{
if (apple[2])//假如返回值为1,则食品被吃掉
{
gotoxy(apple[1] * 2, apple[0]);/*产生食品*/
color(12);//食品颜色为红色
printf("● ");
color(11);//其余地区为淡青色
}
gotoxy(tail[1] * 2, tail[0]);//蛇尾坐标*2,蛇尾变为两个
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, char dirx, 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;//蛇尾没有变长
return snake;
}
3.4游戏结束模块
一.取记录分数的函数 File_in() 和存数据的函数 File_out()
int File_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
return 0;
}
int File_out() /*存数据*/
{
FILE *fp;
if(score[1] > score[0]) //历史最高分大于此关得分,
则输出 " 闯关失败加油耶 "
{gotoxy(10,10);
color(12);
puts("闯关失败加油耶");
gotoxy(0,N+2);
return 0;
}
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);
return 0;
}
二.开释 snake 储存空间函数 Free ()
void Free(char **snake, int len) //开释空间,返回值为蛇头指针,蛇长{
int i;
for (i = 0; i < len; ++i)
free(snake[i]);
free(snake);
}
4调试与测试
1.游戏开始,运转界面启动,显示墙面,蛇头,随机出现的食品以及四周的文字说明。
2. 蛇初始有三节,蛇在运动的过程中吃第一个食品变为四节,分数变为30 分,此后每次吃一个食品加十分。
蛇在运动过程中撞墙而亡,历史最高分为110,目前为 30 分,故输出“闯关失败加油耶”。
3.蛇在运动过程中撞墙而亡。
历史最高分为 60 分,目前分数为 90 分,故输出“恭贺你打破记录”。
5总结
(1)课程设计中碰到的主要问题和解决方法;
此刻得分坐标输入错误,变动程序语句gotoxy(N+44,12);
printf("%d",score[0]*10);
(2)创新和特点之处;设计中存在的不足,需进一步改良的假想。
特点:
这个贪吃蛇的设计中,运用了 color() 函数对整个游戏的界面进行了美化使各个地区看起来也更为清楚了然。
也运用了 File_in() 和 File_out() 对历史的分数进行了记录和
调用,增添了一个与历史最高分比较的功能。
不足:
在这个程序并无波及到对速度的选择。
参照文件
[1]谭浩强 .C 语言程序设计(第四版) . 北京:清华大学第一版社, 2010.
[2]严蔚敏 , 吴伟民 . 数据构造 (C 语言版 )[M]. 北京 : 清华大学第一版社 ,2007.
[3]孙秀梅,曹飞飞 .C 语言项目事例剖析 . 北京 : 清华大学第一版社, 2012.
[4]曹计昌,卢萍 .C 语言与程序设计 . 北京 : 电子工业第一版社, 2008.
[5]程海英 . 数据构造( C语言版) . 北京 : 清华大学第一版社, 2014.
附录代码清单
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define N 21
int apple[3];
char score[3];
char tail[3];
void gotoxy(int x, int y) //输出坐标
{
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); }
void color(int b)//颜色函数
{
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
SetConsoleTextAttribute(hConsole,b) ;
}
int Block(char head[2]) //判断出界
{
if ((head[0] < 1) || (head[0] > N) || (head[1] < 1) || (head[1] > N))
return 1;
return 0;
}
int Eat(char snake[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);
return 1;
}
return 0;
}
void Draw(char **snake, int len) //蛇挪动{
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, char dirx, int *len) //控制方向
{
int i, 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;
return snake;
}
void init(char plate[N+2][N+2], char ***snake_x, int *len) //初始化
{
int i, j;
char **snake = NULL;
*len = 3;
score[0] = score[3] =3;
snake = (char **)realloc(snake, sizeof(char *) * (*len));
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 < N + 2; ++i)
{
gotoxy(0, i);
for (j = 0; j < N + 2; ++j)
{
switch (plate[i][j])
{
case 0:
color(12);printf("□");color(11);continue;
case 1: 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;
}
void Manual()
{
gotoxy(N+30,2);
color(10);
printf("按 W S A D 挪动方向 ");
gotoxy(N+30,4);
printf("按 space键暂停");
gotoxy(N+30,8);
color(11);
printf("历史最高分为 : ");
color(12);
gotoxy(N+44,8);
printf("%d",score[1]*10);
color(11);
gotoxy(N+30,12);
printf("你此刻得分为 : 0");
}
int File_in() //取记录的分数
{
FILE *fp;
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;
return 0;
}
int File_out() //存数据
{
FILE *fp;
if(score[1] > score[0])
{gotoxy(10,10);
color(12);
puts("闯关失败加油耶");
gotoxy(0,N+2);
return 0;
}
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);
return 0;
}
void Free(char **snake, int len) //开释空间{
int i;
for (i = 0; i < len; ++i)
free(snake[i]);
free(snake);
}
int main(void)
{
int len;
char ch = 'g';
char a[N+2][N+2] = {{0}};
char **snake;
srand((unsigned)time(NULL));
color(11);
File_in();
init(a, &snake, &len);
Manual();
while (ch != 0x1B) //按ESC结束
{
Draw(snake, len);
if (!apple[2]) {
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)
{
gotoxy(N+2, N+2);
puts("你输了 ")
File_out();
Free(snake, len);
getche();
exit(0);
}
}
Free(snake, len);
exit(0);
}
项目比率得分平常成绩(百分制记分)30%
成
绩
业务查核成绩(百分制记分)70%
评
定
总评成绩(百分制记分)100%
评定等级优良中及格不及格指导教师(署名):
20年月日。