《俄罗斯方块实验报告(共33页).doc》由会员分享,可在线阅读,更多相关《俄罗斯方块实验报告(共33页).doc(33页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上程序设计实践报告(2012/2013学年 第2学期)题 目: 俄罗斯方块游戏设计 专 业 学 生 姓 名 班 级 学 号 指 导 教 师 指 导 单 位 软件工程系 日 期 2013.03.27 成绩评定参考标准:程序设计实践环节评分为五级制,即:优秀、良好、中等、及格、不及格。根据程序设计实践过程中学生以下表现评定:学习态度是否端正、实验课前准备是否充分、是否实现课题要求的功能、算法设计是否合理、程序设计语言使用是否熟练、用户界面设计是否科学、程序设计实践报告完成情况(包括:内容是否详实、文字表达是否流畅、格式是否符合规范、程序注释是否具体)、答辩表现、考勤等。简
2、短 评 语教师签名: 2013 年 3月 27日评分等级俄罗斯方块游戏设计一、 课题内容和要求本程序的主要任务就是编写简单的俄罗斯方块游戏,要求设计比较美观和健全的游戏界面,可以实现方块预览、方块的控制、显示更新、分数更新以及帮助等基本功能,减少程序本身的错误,增强游戏的可操作性。程序的设计将结合一些有关C语言图形界面设计的内容,该部分是之前没有接触过的,要求利用这次机会,比较简约地了解相关内容及其简单应用。本程序的实现是选用Windows XP/7操作系统 以及 Microsoft Visual Studio 2008 C+为编译器,用C语言完成程序设计的实践。使用Win32 控制台应用程序
3、,最终在DOS界面下形成程序的主界面。二、概要设计struct /此结构体数表是打印各个方块的依据 /是该程序设计的灵魂 int vary_x4; int vary_y4; vary= 0, 2, 4, 6,0, 0, 0, 0,0, 0, 0, 0,0,-1,-2,-3,0, 2, 2, 0,0, 0,-1,-1,0,-2,-2,-4,0 ,0,-1,-1, 0, 0, 2, 2,0,-1,-1,-2,0, 2, 2, 4,0, 0,-1,-1, 0, 0,-2,-2,0,-1,-1,-2,0, 0, 2, 4,0,-1, 0, 0, 0, 0, 0, 2,0,-1,-2,-2,0, 0,-
4、2,-4,0,-1,-1,-1, 0, 2, 2, 2,0, 0,-1,-2,0, 2, 4, 4,0, 0, 0,-1, 0,-2,-2,-2,0, 0,-1,-2,0, 0, 2, 4,0,-1,-1,-1, 0, 0, 0,-2,0,-1,-2,-2,0 ,2, 4, 2,0, 0, 0,-1, 0, 0, 2, 0,0,-1,-1,-2,0,-2, 0, 2,0,-1,-1,-1, 0, 0,-2, 0,0,-1,-1,-2,;本程序中关于方块的颜色、运动的速度都采用的数组常量的形式,数组的编号分别对应方块形状的编号,这样就使得“方块形状方块颜色运动速度”一一对应起来,更直观和方便地实
5、现动态管理。const int col=11,15,12,12,10,10,9; /控制方块的颜色const int speed=0,12,9,6,3,1; /控制方块的下落速度const int number=0,2,3,5,7,11,15; /对应方块的类型编号本程序的主体部分是由多个函数的循环多层调用来实现的,主要由以下的九个函数构成: void PrintNext ( int pkind)/该函数控制“下一个图形预览”中的方块样式,是整个程序的“引导者”、“开拓者”,将引导程序的动态实现,将决定着下面几个函数的调用 void StraightFall (int depth)/该函数控制
6、方块的降落,是在整个程序中发挥着至关重要的作用,是整个动态过程的“纽带”将具体分功能的实现连串起来。void ChoiceDirection (int *prev_count)/该函数实现键盘对小方块的控制,在小方块降落的过程中要时刻“监视”,因此,在函数中,每当一些变量发生变化时,即要调用该函数 void Revolve(int *prev_count)/该函数控制方块的旋转。该函数必须依附于,即每次有键盘的按动时,都要检验是否按了“”如果按了,立即执行该函数,实行方块的翻转void LevelMove() /该函数控制方块的移动方向。该函数类似于第四个函数,也是依附于 void GetDe
7、pth(int *pdepth)/该函数可以得到小方块已累积的高度,从而判断小方块是否已经落下。该函数是一个在多处都需要调用的函数void CheckBoundary() /该函数可以控制、防止方块越过边界。一旦可能越过边界,则之前的方向控制无效,在方块左右移动、变化形状时都需要调用该函数void CheckFull(int *pscore)/检验是否有一行完全被覆盖,若有一行全部被排满的,即刻整体下移。在函数的最后,立刻调用该函数 void GameOver() /即当depth 为0时,游戏结束,显示动态结束画面。在函数的最开始,立刻调用该函数程序流程图大致如下: 说明:该程序的流程图略显
8、复杂,但其实质,依旧是顺序、选择、循环的使用,唯一复杂的就是循环的主体不再是简单的程序语句而是比较复杂的函数,这样就会使得程序的结构比较冗杂,但如果把流程图画出来,就会清晰地看到问题依旧是很简单。四、关键源码 for(i=0;i=0;i-) /用两层循环来实现主界面方块的打印 for(int j=0;j17;j+) gotoxy(36-j*2,3+i); puts(); Sleep(5); /延时函数的调用,使得最终的程序界面更有动感 color(back); for(int j=0;j31;j+) for(int i=0;i17;i+) boardij.having=0; gotoxy(4+
9、2*i,j+3); puts(); Sleep(5); void Revolve(int *prev_count) /控制方块的旋转,该函数是整个程序中最难的一部分代码int i;before.x=current.x;before.y=current.y;(*prev_count)+;(*prev_count)%=connectionpri_kind.sum;current.x=current.x+connectionpri_kind.connection_x*prev_count;current.y=current.y+connectionpri_kind.connection_y*prev
10、_count;CheckBoundary(); /调用检验边界函数,防止方块在旋转过程中越出程序界面for(i=0;i16|m31)current.x=current.x-connectionpri_kind.connection_x*prev_count;current.y=current.y-connectionpri_kind.connection_y*prev_count;revolve=0;(*prev_count)-;before.x=current.x;before.y=current.y;return ;color(back); /用背景色把旋转前的方块覆盖for(i=0;i2
11、)gotoxy(before.x+varykind.vary_xi,before.y+varykind.vary_yi);puts( );kind=numberpri_kind+*prev_count;color(colpri_kind); /打印旋转后的新的方块for(i=0;i2)gotoxy(current.x+varykind.vary_xi,current.y+varykind.vary_yi);puts();Sleep(speedrank); /根据等级来决定旋转、下落的速度before.x=current.x;before.y=current.y;int main() /主函数是
12、将一切子函数连串在一起的工具srand(unsigned long)time(0);gotoxy(5,5);printf(一切准备就绪,游戏是否开始?n);gotoxy(4,6);printf(开始游戏请按S键,否则按任意其他键退出。n);char c;c=getchar();if (c!=S) exit(0); system(CLS);system(color 24); /设置背景颜色int score=0; /检验文件是否能够成功打开FILE *fp=fopen(C:els.txt,r);if(fp=NULL)fp=fopen(C:els.txt,w);fprintf (fp,%d,sco
13、re);fclose(fp);PrintGarphy(); /打印程序的边界和基本框架以及其中的文字kind=rand()%7; /随机函数来随机确定方块的形状int depth;while(1) /是一个无限循环,不断地重复着游戏的过程int pkind=rand()%7;PrintNext(pkind);current.x=20; /方块初始出现的位置current.y=2;GetDepth(&depth);if(depth=0) GameOver(); /当剩余的高度为0时,游戏结束 score=0; rank=1; pri_kind=kind;if(kind=6) kind=15,cu
14、rrent.x-=2;else if(kind=5) kind=11;else if(kind=4) kind=7;else if(kind=3) kind=5;else if(kind=2) kind=3,current.x+=2;else if(kind=1) kind=2;else kind=0,current.x-=2;StraightFall(depth); /调用方块下落函数for(int i=0;i4;i+)int m=(current.x-4+varykind.vary_xi)/2;int n=current.y-3+varykind.vary_yi;boardmn.havin
15、g=1;boardmn.color=colpri_kind;CheckFull(&score); /检验是否有满行的出现,若有,整体下呀,并加分kind=pkind;return 0;五、测试数据及其结果分析程序正式运行前所给的提示信息 这是程序主界面,由PrintGarphy() 打印生成 程序主界面 运行过程中的程序界面 这是游戏结束时,动态界面的一瞬间截图 六、程序设计实践中的关键技术难题以及解决办法【问题1】在左右方向改变方块的位置时,若一直按住左键或右键,会出现方块部分或整体越过程序界面的现象。【分析】在程序中层已经定义和调用了函数void Getdepth() 用来计算已经累计的高
16、度,并由depth的值是否为0来判断是否游戏结束,是否方块已经降落。因此,在程序中还应当定义另一个函数,用来判断是否方块越界,并在其变换和左右移动时调用,以防止方块的越界。【解决方法】在主程序中定义一个新的函数 void CheckBoundary(),其定义如下:void CheckBoundary() int i,n,m;for(i=0;i4;i+) m=current.x+varykind.vary_xi;if(m36)current.x+=(m4?2:-2);i=0;for(i=0;i4;i+) m=(current.x+varykind.vary_xi-4)/2;n=current.
17、y+varykind.vary_yi-3;if(n31|boardmn.having)if(level=1) current.x+=2;else if(level=2) current.x-=2;level=0;break;【问题2】在程序的调用中,发现程序每一次运行,“最高分”都会从0开始记。即使我把 HighScore 设为全局变量,依旧是出现该问题。 【分析】程序的每一次运行,都会把每一个变量初始化。尽管全局变量的作用域是从变量定一开始一直到程序结束,然而,依旧不是“永久”,随着程序的结束而覆灭。因而,解决的办法就是,及时的把最高分写到计算机的文件中,来求得“永久”的保存。【解决方法】在
18、程序中添加以下代码,一旦有新的最高分生成,则立刻写入文件C:els.txt.FILE *fp=fopen(C:els.txt,r)fscanf (fp,%d,&t);fclose(fp);if(*pscoret)fp=fopen(C:els.txt,w);fprintf (fp,%d,*pscore);fclose(fp);color(43);gotoxy(51,16);printf(%d,*pscore); fclose(fp);七、总结与展望两周的编程实践,对于自身编程水平是个不小的提高。实践是认识的来源、实践是认识发展的动力,第一次接触实践课,让我深刻感受到了实践出真知的道理。因此,在以
19、后的学习中,要树立实践的意识,提高把理论知识上升为实践的能力。做成事情的前提是有一个合理可行的规划。在本次程序设计实践的开始阶段,由于编译器的选择问题(即Visual C 和Turbo C),项目几乎停滞不前,导致许多时间白白浪费。因此在以后的实践中,要在任务正式开展之前,就要做好充分的规划,避免手忙脚乱。适当的借鉴和对案例的充分分析加之对书本、互联网等工具的充分使用,才能把一项比较庞大的工程做好。在这次的程序设计中,我在互联网上找到了至少30个有关俄罗斯方块的例子,其中能够无差错运行的少之又少。本人花费了很大的功夫仔细地研究了那六七个案例,体悟它们程序实现的方法,找到之间的区别和相同之处。在
20、阅读每一个程序时,多多少少都会有不完全理解甚至是根本看不懂的地方,这个时候,书本网络就是一个极好的工具。在两周的时间里,除了思考和面对电脑,剩余的时间几乎就在图书馆里找资料,在追求知识的过程中,也有了许多新的发现。独立的思考是一切成功的基础。把一切的感知和灵感都要归咎与自己的思考。每一个案例的分析都是我独立思考的结果,以后的学习生活中都要善于思考、勤于思考。分部编写各个函数,并对其逐一进行测试,化大为小,是本次实践的一大收获,是编写较复杂程序的有效方法。这样有利于条理的清晰,避免错误。合作与交流是成功的捷径。与同课题的同学合作甚至是与不同课题同学的交流,都会让我产生思想的火花,在困惑自己许久的
21、问题上带来突破。在程序中,本人很想再编写一个计时器,用来计量游戏已经运行的时间,几经尝试都没有成功。初步猜想,可能需要多线程的控制,下一步在这个问题上力求有所突破。源代码:/* Copyright (C) 2013,ZhangXu,Nanjing University of Posts and Telecommunications* All rights reserved.* 当前版本:1.2.1* 作 者:ZhangXu* 完成日期:2013年3月29日*/#include #include #include #include const int back=34;const int col=
22、11,15,12,12,10,10,9; /用数组记录不同方块的颜色const int speed=0,12,9,6,3,1; /用数组记录不同的降落速度const int number=0,2,3,5,7,11,15;int kind;int pri_kind;int rank=1; /等级状态标记,由此确定下落的速度int revolve=0;int level=0;structint x;int y;current,before;structint x;int y;int color;bool having;board1732;structint vary_x4;int vary_y4;
23、 vary=0, 2, 4, 6,0, 0, 0, 0,0, 0, 0, 0,0,-1,-2,-3,0, 2, 2, 0,0, 0,-1,-1,0,-2,-2,-4,0 ,0,-1,-1,0, 0, 2, 2,0,-1,-1,-2,0, 2, 2, 4,0, 0,-1,-1,0, 0,-2,-2,0,-1,-1,-2,0, 0, 2, 4,0,-1, 0, 0,0, 0, 0, 2,0,-1,-2,-2,0, 0,-2,-4,0,-1,-1,-1,0, 2, 2, 2,0, 0,-1,-2,0, 2, 4, 4,0, 0, 0,-1,0,-2,-2,-2,0, 0,-1,-2,0, 0, 2,
24、 4,0,-1,-1,-1,0, 0, 0,-2,0,-1,-2,-2,0 ,2, 4, 2,0, 0, 0,-1,0, 0, 2, 0,0,-1,-1,-2,0,-2, 0, 2,0,-1,-1,-1,0, 0,-2, 0,0,-1,-1,-2,;structint sum;int connection_x5;int connection_y5;connection=2,-2,2,0,1,1,0,0,2,2,-2,0,0,2,-2,2,0,0,4,-2,0,4,-2,0,0,-1,1,4,-4,2,-2,4,0,0,-1,1,4,-2,2,0,0,0,0,0,0,;void gotoxy(i
25、nt 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) ;void PrintGarphy()color(1593); /初始化控制台窗口,获取窗口句柄,设置边框颜色int i
26、,j;gotoxy(2,2); /确定光标从第二行第二列开始,以下开始打印边框for(i=0;i28;i+) printf();gotoxy(2,35);for(i=0;i28;i+)printf();for(i=0;i33;i+)gotoxy(2,3+i);printf();for(i=0;i33;i+)gotoxy(38,3+i);if(i=7|i=18)printf();else printf();for(i=0;i33;i+)gotoxy(56,3+i);printf(); /至此,完成主框架的打印 int t; FILE *fp=fopen(C:els.txt,r);fscanf (
27、fp,%d,&t);fclose(fp);color(45); /以下开始打印框架内的文字gotoxy(40,4);printf(下一个图形预览:n);gotoxy(40,11);color(43);printf(最高纪录:n);color(44);gotoxy(42,13);printf( %d,t);color(46);gotoxy(40,16);printf(当前得分:0n);color(44);gotoxy(40,18);printf(等级:n);color(39);gotoxy(40,23);puts( 请使用键盘的);gotoxy(40,24);puts(以下按键来控制:);got
28、oxy(40,26);puts( );gotoxy(40,28);puts( 按空格 暂停);gotoxy(40,29);puts( 按 ESC 退出);gotoxy(40,34);puts( 版本号:V1.2.1);color(back); /使游戏区域全为背景颜色,初始化游戏界面for(i=0;i17;i+)for(j=0;j32;j+)boardij.x=4+2*i;boardij.y=3+j;boardij.having=0;gotoxy(boardij.x,boardij.y);puts( );void PrintNext(int pkind) /控制“下一个图形预览”中的方块int
29、 i;int x=46,y=7;color(back);for(i=0;i4;i+)gotoxy(x-3,y+i-2);puts( );pri_kind=pkind;if (pkind=6) pkind=15,x-; /调用随机函数来决定下一个出现的方块的形状else if(pkind=5) pkind=11,x-;else if(pkind=4) pkind=7,x-;else if(pkind=3) pkind=5,x-=2;else if(pkind=2) pkind=3,x+=2;else if(pkind=1) pkind=2,x-;else pkind=0,x-=3;color(c
30、olpri_kind);for(i=0;i4;i+)gotoxy(x+varypkind.vary_xi,y+varypkind.vary_yi);puts();void GetDepth(int *pdepth) /统计方块已经累积后,所剩余的高度*pdepth =31;for(int j=0;j4;j+)int sum=0;int n=(current.x+varykind.vary_xj-4)/2;int m=current.y+varykind.vary_yj-3;if(m0) m=0;for(m+;m=0&n=0&m32)sum+;elsebreak;if(sum=0;i-)for(
31、int j=0;j17;j+)gotoxy(36-j*2,3+i);puts();Sleep(5);color(back);for(int j=0;j32;j+)for(int i=0;i17;i+)boardij.having=0;gotoxy(4+2*i,j+3);puts();Sleep(5);gotoxy(45,18);while(rank-)printf( );color(46);gotoxy(50,16);puts( ); /清空分数显示void CheckBoundary() /控制、防止方块越过边界。一旦可能越过边界,则之前的方向控制无效int i,n,m;for(i=0;i4;i+)m=current.x+varykind.vary_xi;if(m36)current.x+=(m4?2:-2);i=0;for(i=0;i4;i+) m=(current.x+varykind.vary_xi-4)/2;n=current.y+varykind.vary_yi-3;if(n31|boardmn.having)if(level=1)