贪吃蛇项目报告.doc_第1页
贪吃蛇项目报告.doc_第2页
贪吃蛇项目报告.doc_第3页
贪吃蛇项目报告.doc_第4页
贪吃蛇项目报告.doc_第5页
已阅读5页,还剩51页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言项目设计报告 贪吃蛇游戏课程:标准C语言指导老师:XXX项目:贪吃蛇游戏班级:XXXX班组员:XXX、XXX、XXX、XXX姓名:XXX学号:XXXXXXX日期:2012/7/7目录一项目开发文档(3)1 项目基本分析(3) 1.1项目目标(4) 1.2功能描述(4) 1.3小组分工(7)2 总体设计报告(8) 2.1 函数分块(9) 2.2 接口设计(9)3 详细设计报告(14) 3.1 程序结构(14) 3.2 算法流程(17)4 操作指南(29) 4.1 运行及结果截图(29)5 项目总结(32) 5.1 优点与不足(32) 5.2 我的收获与总结()(33)二项目代码(36) 贪吃蛇游戏一 项目开发文档 1 项目基本分析在我进行编写贪吃蛇游戏之前,我所做的必须是可行性分析,因为一旦进行贪吃蛇游戏项目的开发,就必须保证自己在规定的时间内能够独立的完整整个程序的所有功能,而且必须是最优的,因此,在开发贪吃蛇游戏之前,我必须要做的是可行性分析。通过查找相关文档和技术支持,了解了VS环境下的开发过程,熟悉了C语言的开发技巧,通过以下几个方面,进行可行性分析:1. 参考文献 :贪吃蛇游戏用户描述文档、在网上找了相关源代码,确定自己能够在自己能力范围内开发出这个贪吃蛇游戏项目。2. 功能要求:在进行整个项目开发之前,我必须要做的就是确定贪吃蛇游戏的主要功能,必须明确贪吃蛇游戏的功能,因为要进行游戏功能可行性分析,经过自己的查阅相关资料,我确定了贪吃蛇游戏的具体功能,详见后续部分详细设计。3. 性能需求:必须保证自己开发的贪吃蛇游戏能够整体尽可能做到高效快速,不占用大量的使用资源,因为我做的是一个应用窗体控制台的游戏开发项目,必须要考虑资源使用情况,要求尽可能少用资源,在有限的资源范围内实现最大的可利用价值。4. 运行环境:VS2010上编写并进行调试,经过安装软件,确定可以进行项目程序的编写。5. 界面要求:采用Win7应用窗体标准界面,只需要使用键盘。6. 完成期限,一个学期完成整个系统,包括程序的编写以及最终的调试,测试阶段。1.1 项目目标1 熟悉函数的调用与程序的模块化设计,加深对所学知识的理解2 加强自学能力,遇到不了解的函数或者方法,通过图书及网络资源学习,提高学习能力3 完成贪吃蛇游戏,通过小项目来检验一学期的学习效果,增加学习兴趣1.2 功能描述该游戏在继承传统同类游戏规则的基础上,我们添加了我们自己的想法与功能,设计如下:游戏规则包括蛇的运动范围、蛇的生命周期问题、分数统计、关卡判断。其中蛇的运动范围是一个15*15的数组呢,蛇运动的地图抽象成为一个15*15的二维整形数组,每个数组值代表一个小方块的坐标值,这样,蛇只能在规定好的二维数组内运动当蛇遇到数组左右边界值(我们在这里抽象成为上、下、左、右四个边界,其中上边界坐标值中纵坐标都是0,横坐标任意,下边界为纵坐标是15,同理横坐标不变,左边界为横坐标为0,纵坐标任意,同理右边界为横坐标为15,纵坐标任意)时,宣告蛇生命周期结束(上下边界不限定),贪吃蛇死亡,这个是第一个规则;另外,当蛇自己吃到自己身体的某一部分时,也宣告游戏结束,在程序里通过循环判断蛇头下一个前进方向的节点是不是蛇身上的某一部分节点即可,如果是那么蛇死亡,否则继续运行游戏。 分数统计算法的思想是每次蛇吃到一个果实时,相加的分数为一个定值10来记录分数,这样可以随着游戏难度的增加,分数值也随之增多。关卡功能设置通过与分数相关联而体现的,初始化游戏分数为0,关卡障碍物选择由玩家键入,当玩家玩到一定的分数时(例如是100)关卡加一,变为第二关,同时,蛇前进速度相应增加一个等级,障碍物的设置也变化,这样就实现了不同关卡,不同速度的贪吃蛇,从而增加了游戏的难度。 蛇: 1、能够实现贪吃蛇自动前线移动,也就是贪吃蛇能够“活动”的外观效果,根据相同的时间间隔,每一次将贪吃蛇自身的蛇头向前移动一个小格子,同时蛇尾向前移动一个小格子,移动方向为贪吃蛇行走的方向。2、每当一个食物时,蛇长度增加一格3、蛇头碰到自身时则游戏结束4、通过键盘来控制蛇的移动食物:1、 每当蛇吃到食物时,重置食物2、 吃到特定食物时,蛇的长度能够缩短边界和障碍物:1、 遇到边界和障碍物则游戏终止成绩统计:1、当贪吃蛇吃到果实时,玩家的分数就应该随着吃到的果实而增加,增加的规则就是每一个吃到一个食物则乘以10得到分数。2、能够与历史成绩进行比较,显示高分排行榜输入与输出:1、 通过键盘选择障碍物关卡数2、 通过键盘选择蛇的速度3、 显示游戏指南4、 能够即时显示当次游戏的关卡数及游戏分数5、 显示游戏界面贪吃蛇的总体功能图1.3小组成员分工小组成员XXXXXXXXXXXX功能分析小组讨论,确定项目题目和基本方案,组员提出想实现的功能,分析可行性讨论建议整理方案分工安排接口实现成绩,特效蛇的基本功能障碍物功能边界问题关卡递进最初源代码添加注释基本功能添加边界成绩存档食物重置特殊效果障碍物关卡功能 汇总整理测试改进2 总体设计报告考虑到要实现的功能太多,所以宜采用模块化设计,把功能分块(在介绍功能时已经按这个方式介绍了),然后设计各个模块之间参数的传递,衔接起来,最后实现每个功能的算法。首先我们定义了所需要的数据类型1. Node(结点)型定义用来作为蛇的头,身,尾的数据类型以及障碍物的数据类型每个成员的设计已在注释中注明,其中蛇和障碍物均用链表结构表示struct Node int x; /*蛇某一节的横坐标*/ int y; /*蛇某一节的纵坐标*/ struct Node *pre; /*蛇某一节的前驱结点*/ struct Node *next; /*蛇某一节的后继结点*/; 2Food(食物)型定义 用来储存食物的横纵坐标及显示的字母3.Player(玩家)型定义储存玩家的姓名和成绩2.1函数分块 总的来说,我们把所有功能分成了以下几个大块: main snake food barrier and block grade共五个大块,分别实现相应功能,见名知意,各块的功能显而易见,依次实现主要的运行(main),蛇的控制、移动、增减(snake),食物的重置(food),障碍物的设置及边界的判断(barrier and block),成绩的统计与存档(grade)每个模块均存在一个CPP中,截图如下:2.2接口设计下面分别介绍每个大块的内部函数接口设计main: 主函数:int main()其中main函数里定义了游戏必须的一些变量输入函数:int input(char*pname,int*barrierkind)第一个形参为char*类型,用来接收main函数里面的玩家名字,便于输入赋值,因为要进行写操作修改其值,所以定义成一级指针;第二个形参为障碍物类型,即初始化的障碍物分布,同样要在input里赋值,所以用int*型。返回值为速度值,是一个整数,游戏通过这个数来控制蛇前进的速度,所以定义为int屏幕显示函数:void screenshow(int score,int stage,Node*head,Node*firstbar,Food*food)要显示当前的分数和关卡,所以传两个整型参数score和stage;又要通过二位数组扫描,根据横纵坐标来看输出“”(空格)还是蛇“ ”,或障碍物“”,或食物,所以要传结构体参数Node*和FoodSnake:蛇的初始化函数:void initalsnake(int*grade,Node*head,Node*rear)顺便把成绩也初始化,所以传了个int型参数grade;然后由于要修改main函数中Node*head目标空间的的横纵坐标,所以这里用了一个二级指针,否则,若设计成Node*型,则形参改的值只在该函数有效,对main函数里的head无影响(此处曾调试很久,在5.2.2心得体会里在详细说明)方向输入函数:char directioninput(char c)由键盘键入一个值,传回有效值,故返回值类型为char, 由主函数传过来而不内部定义时避免输入无效值时出错,所以此处相当于输入无效值则还是原值(内部最后一句为return c)。蛇移动函数:void snakeheadmove(char c,Node*head)传前进的方向,为字母值,用char,头要移动,需要改值,所以用二级指针添加和删除结点函数:void addpoint(Node*head,Node*rear)void deletepoint(Node*head,Node*rear)由于用的是双向链表,所以要传头尾两个参数,需改值,故用二级指针Food:食物重置函数:void foodreset(char c,Food*food,Node*head,Node*firstbar)当玩到最后蛇身较长时,重置多次可能还不行,所以会内定为在蛇前进方向的前两个出食物,所以要传前进方向,用char;需改变食物的横纵坐标及显示字母,故第二个参数用一级指针;要判断食物是否重置到蛇身或障碍物上,所以传二者参数,由于只是判断不需要改值,所以一级指针即可barrier and block:障碍物初始化函数:void initalbarrier(int barrierkind,Node*firstbar,Node*lastbar)要调用障碍物重置函数void barrierset(int barrierkind,Node*firstbar,Node*lastbar),需要主函数里的实参,所以第一个参数用int,便于内部传值调用其他函数;要修改主函数中firstbar和lastbar的目标空间的值,所以用二级指针;判断出界函数int Block(Node *head)看头部的坐标是否出界,所以只需Node*即可;对判断结果进行记录,返回0或1,所以用int;障碍物重置函数void barrierset(int barrierkind,Node*firstbar,Node*lastbar)接收关卡数,故第一个参数定义为int; 要修改主函数中firstbar和lastbar的目标空间的值,所以用二级指针;判断游戏结束函数:int Gameover(Node*head,Node*firstbar)需要判断头是否触到障碍物,所以传参数Node*;对判断结果进行记录,返回0或1,所以用int;Grade:成绩插入函数:void scorecompare(Player*top,Player*player)把该次的成绩与原来的前十名成绩进行比较,需要记录名字,所以传结构体Player*;历史成绩复制函数:void fileinital(Player*topplayer)由于要把文件中的历史成绩赋值给主函数的结构体数组,所以传一级指针Player*成绩存档函数:void file(Player*top)把排序后的新的TOP10的成绩写入文档,由于是一维数组,所以只能传指针;参数传递图: main grade snakebolck fileinitalInputinitalsnakeinitalbarrierderectioninputBlocksnakemovemainbarriersetaddpointgameoverdeletepointscorecomparefilescreenshow注明:单项箭头的指向为参数传递的方向; 双向箭头说明有传递返回值; 主要采取指针参数改动值,所以很少有返回值;3 详细设计报告3.1程序结构程序流程图3.1.1各种宏定义以及说明#define boundary 15 /* 边界定义为15*15 */#define N 10 /* 只存取和展示前10名玩家 */3.1.2主要函数声明如下int input(char*,int*);显示最初的提示界面,实现难度和关卡的选择输入;void foodreset(char c,Food*food,Node*head,Node*firstbar);实现食物的随机重置;void initalsnake(int*,Node*,Node*);给蛇头动态分配空间,顺便初始化成绩;void initalbarrier(int,Node*,Node*);给障碍物初始化空间,同时调用食物重置函数;void barrierset(int,Node*,Node*);根据现在的关卡信息重置障碍物;int Block(Node*head) ;判断头是否出界char directioninput(char);方向控制键入函数;从键盘过去键入值;void snakeheadmove(char,Node*);根据键入的值执行蛇头移动;void addpoint(Node*,Node*);吃到食物时增加结点,蛇身增长;void deletepoint(Node*,Node*);吃到特定食物蛇身变短;int Gameover(Node*,Node*);判断游戏是否终止;void screenshow(int,int,Node*,Node*,Food*);显示游戏界面;void scorecompare(struct Player*,struct Player*);每个玩家游戏结束即时排序插入高分榜;void fileinital(Player*);文件初始化;void file(Player*);成绩存档;3.2算法流程3.2.1 main模块的函数算法:int main()/初始化信息,调用文件初始化函数;while(1) /玩家循环(外循环) 定义必要的变量; 初始化该玩家信息(姓名“XXX”,0分); 清屏; 调用输入函数,返回速度值; 调用蛇和障碍物的初始化函数; 利用time函数产生随机数; While(1) /游戏的进程循环(内循环) if(蛇头吃到食物)(字母“o”)?(减短):(增长);调用食物重置函数;玩家成绩增加; if(有键盘输入) 调用方向输入函数;pt=rear;while(pt不指向蛇头)将蛇头后面的结点分别等于前驱结点;/相当于前移调用蛇头移动函数;if(游戏过关) 速度延时减(20毫秒*关卡等级),直到为零; 释放障碍物空间; 重置障碍物;if(游戏结束) 输出鼓励的话; 跳出本次循环;调用屏幕显示函数;调用Sleep函数延时;/内循环结束释放蛇头空间;释放障碍物空间;调用分数插入函数;调用文件存档函数;延时一秒;清屏;显示英雄榜;判断继续游戏还是退出; /外循环结束return 0;int input(char*pname,int*barrierkind) 定义速度变量; printf(欢迎来到贪吃蛇游戏); printf(请输入名字); scanf(%s,pname); (后面是类似的输入障碍物类型和难度) return speed*50;void screenshow(int score,int stage,Node*head,Node*firstbar,Food*food) 定义要用的变量; 清屏; 输出提示游戏规则的话; for(i=1;iboundary;i+) printf(); printf(n);/上边界输出 for(i=0;iboundary;i+) printf(|);for(j=1;jboundary;j+) if(是蛇的坐标) 是蛇头,printf(); 是蛇身,printf();if(障碍物坐标) printf();if(食物坐标)显示食物的字母;都不是则printf(“ ”); /j循环完printf(|); putchar(n); /i的循环完 printf( ); for(i=1;iy+=1;if(*head)-y=boundary) (*head)-y-=boundary;break; (后面几个同理)void addpoint(Node*head,Node*rear) struct Node *pt,*p; p=(struct Node *)malloc(sizeof(struct Node); pt=*head; /*分配结点p的地址空间并将其指向蛇头结点*/ while(pt-next!=NULL) pt=pt-next ; /*当p的next域不为空时将p指向下一个结点*/ p-pre= pt; pt-next = p; p-next=NULL; *rear=p; /*将p结点插到蛇链表的末尾,后插法*/void deletepoint(Node*head,Node*rear)(*head)-next=*rear; (*rear)-pre=*head; /删除所有节点,只留首尾3.2.3 food模块的函数算法:void foodreset(char c,Food*food,Node*head,Node*firstbar) 定义变量; 重置食物; for(t=0,flag=1;flag=1;t+) for(pt=head;pt!=NULL;pt=pt-next)if(食物坐标等于蛇身坐标) 重置食物; break; for(pt=firstbar;pt!=NULL;pt=pt-next) if(食物坐标等于蛇身坐标) 重置食物; break; if(t5) /*当5次重置,食物坐标均等于蛇的坐标,则将食物置于蛇的前进方向的前一格*/ switch(c) case d:food-x=head-x+1; food-y=head-y; if(food-x=boundary) food-x-=boundary; break; (后面的选项类似) 3.2.4 block and barrier模块函数算法:void initalbarrier(int barrierkind,Node*firstbar,Node*lastbar) *firstbar=new Node5; /用new运算动态分配空间 (*firstbar)-x=10; /设置初始坐标 (*firstbar)-y=10; (*firstbar)-pre=NULL; (*firstbar)-next=NULL; *lastbar=*firstbar; barrierset(barrierkind,firstbar,lastbar); /调用障碍物设置函数int Block(Node *head) if(蛇头坐标出界)return 1; else return 0;void barrierset(int barrierkind,Node*firstbar,Node*lastbar)定义变量; for(i=0;inext!=NULL) pt=pt-next ; p-pre= pt; pt-next = p; p-next=NULL; *lastbar=p; switch(barrierkind) /给障碍物赋坐标值 case 1: (*lastbar)-x=(*lastbar)-pre-x-1; (*lastbar)-y=(*lastbar)-pre-y; break; case 2: (*lastbar)-x=(*lastbar)-pre-x; (*lastbar)-y=(*lastbar)-pre-y-1; break; default: (*lastbar)-x=(*lastbar)-pre-x-1; (*lastbar)-y=(*lastbar)-pre-y-1; int Gameover(Node*head,Node*firstbar)定义变量;for(pt=head-next;pt!=NULL;pt=pt-next) if(蛇头坐标等于蛇身的坐标) return 1; for(pt=firstbar;pt!=NULL;pt=pt-next) if(蛇头坐标等于障碍物坐标) return 1; if (Block(head) /调用Block函数 return 1; return 0;3.2.5 grade模块函数的算法:void scorecompare(Player*top,Player*player) 定义变量; 遍历top数组比较大小,标记下player的成绩的位置; 从后往前遍历,把player的信息插入到标记的位置;(详细代码见源代码,此处只写算法和思路)void fileinital(Player*topplayer)FILE*fp; /定义结构体FILE型的指针if(打开的只读文件为空) if(打开的只写文件为空) /此处一般不为空,因为打开只写没有的话会自动创建 提示运行错误; exit(0);Player initalN; /定义结构体Pint i;for(i=0;ix=rand()%(boundary);看似不错,但有0这个隐患,直接加1的话又会超出上界,最后我想出了这样处理: food-x=rand()%(boundary-2)+1;即余数的最大值比原来小二,而加一的话下届又加一了,所以不会出现食物BUG了。这是最后一天调试出来了,很幸运。5.2.3 总结这次项目我真的学到了很多东西,很多功能我基本自己独立编写的,大大提高了我的C语言编写能力,而且我还学习了链表和文件储存。其实有个小秘密就是,这个代码我们改了很久,分几个阶段。1. 找到源代码时什么附加功能都没有,而且一个主函数包罗所有信息,很庞杂,于是我花了一个晚上把找的代码看懂并根据功能剥离出各个函数; 2. 当时对参数掌握的不是特别好,所以就把那几个结构体指针的变量全部定义为外部全局变量;在各分CPP里面用extern来说明;同时,策划并添加我们自己设计的一些功能,如关卡,障碍物,吃“o”变短,成绩统计等。3. 后来觉得全局变量影响了函数的独立性,所以我又一个个把函数根据功能重新设计接口,从而去掉了全局变量,感觉改的比较成功。备注:闪屏问题我们还没解决,我觉得只能通过图形界面来实现,我暑假会尽量自学图形界面,尽量实现。(完)特别鸣谢老师一学期来的无私敬业!二 项目代码附原代码:头文件:game.h#include stdafx.h#include #include #include #include #include #define boundary 15#define N 10struct Node int x; /*蛇某一节的横坐标*/ int y; /*蛇某一节的纵坐标*/ struct Node *pre; /*蛇某一节的前驱结点*/ struct Node *next; /*蛇某一节的后继结点*/; /*蛇的某一节*/struct Food int x; /*食物的横坐标*/ int y; /*食物的纵坐标*/ char c; /*用字母表示食物*/; /*食物*/struct Playerchar name20; /*玩家姓名*/int grade; /*成绩*/;int input(char*,int*);/输入 void foodreset(char,Food*food,Node*head,Node*firstbar);/食物重置void initalsnake(int*,Node*,Node*);/蛇头重置void initalbarrier(int,Node*,Node*);/障碍物初始化空间int Block(Node*head) ;/判断出界 char directioninput(char);/方向输入void snakeheadmove(char,Node*);/蛇头移动void addpoint(Node*,Node*);/增加结点int Gameover(Node*,Node*);/游戏结束条件void screenshow(int,int,Node*,Node*,Food*);/屏幕显示void scorecompare(struct Player*,struct Player*);/成绩排序void fileinital(Player*);/初始化文件及提取成绩void file(Player*);/文件储存成绩void barrierset(int,Node*,Node*);/障碍物重置void deletepoint(Node*,Node*);/删除结点 /头尾和临时结点的结构体指针源文件:main.cpp#include stdafx.h#include game.hint main()struct Node *firstbar=NULL,*lastbar=NULL,*pb; /* 障碍物的首尾结点,为Node*型 */ struct Food food=2,2,A; /*食物,为Food型 */ struct Node *head=NULL,*p,*rear=NULL,*pt; /*蛇的头尾,为Node*型*/ int aboundaryboundary=0; int number=0,speed=0; structPlayertopplayerN; fileinital(topplayer); while(1) char c=d; /*d为蛇右进的控制键,即默认为向右前进*/int gameover=0,STAGE=1,flag=0; /定义游戏结束,关卡,标记符变量int barrierkind=0; /定义障碍物选择变量struct Player player=xxx,0; /初始化此次玩家信息 system(cls); /清屏 speed=input(,&barrierkind);/调用输入函数,返回速度值initalsnake(&player.grade,&head,&rear); /调用蛇初始化函数 initalbarrier(barrierkind,&firstbar,&lastbar); /初始化障碍物 srand(unsigned)time(NULL); /*利用time函数产生随机数*/ while(1) if(food.x=head-x) & (food.y=head-y) /*当蛇头吃到食物*/ if(food.c=O)deletepoint(&head,&rear);else; addpoint(&head,&rear); foodreset(c,&food,head,firstbar); /*调用食物重置*/ player.grade+=STAGE*10; if(kbhit() /*用kbhit()函数判断是否有键盘输入*/ c=directioninput(c); /*调用方向输入函数*/ pt=rear; /*将pt指向蛇尾结点*/ while(pt!=head ) /*当pt不指向蛇头时,将蛇头后面的结点坐标分别等于前驱结点,相当于蛇向前移一格*/ pt-x=pt-pre-x; pt-y=pt-pre-y; pt=pt-pre; snakeheadmove(c,&head); /*改变蛇头坐标*/ /*判断游戏过关或失败*/int tempSTAGE=STAGE; /如果升级,增加难度STAGE=player.grade/100+1;if(tempSTAGE-STAGE)speed=(speed-STAGE*10)0?(speed-STAGE*10):0;delete firstbar; initalbarrier(STAGE,&firstbar,&lastbar); else;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论