《C++俄罗斯方块课程设计(共23页).doc》由会员分享,可在线阅读,更多相关《C++俄罗斯方块课程设计(共23页).doc(23页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上 华科学院计算机科学与技术系 软件工程课程设计报告 -俄罗斯方块游戏 (2011/2012学年 第一学期) 学生姓名: 王奥辉 专业班级: 信息管理H 学生学号: 7 指导教师: 王艳 2011年12月30日专心-专注-专业 目录第一章 系统概述1 . 1 课程设计的目的和要求-11 . 2 课程设计任务内容-11 . 3 关于编译软件-1第二章 详细设计说明-22 . 1 程序设计-2 2 .1 .1 主要功能设计-2 2 .1 .2 程序流程图-22 . 2 参数说明-3 2 .2 .1 类设计声明(view类)-3 2 .2 .2 类设计声明(squar类)-4
2、2 . 3 函数功能说明-5 2 .3 .1 游戏界面-5 2 .3 .2 生成方块-5 2 .3 .3 方块变形-6 2 .3 .4 方块显示-6 2 .3 .5 障碍判断-7 2 .3 .6 消行计分-7 2 .3 .7 暂停退出-72 . 4 程序调试-92 . 5 软件使用说明-9第三章 心得与体会-10附录1-11附录2-11 第一章 系统概述1.1课程设计的目的和要求 俄罗斯是家喻户晓的益智小游戏,选择这个题目一是为了将自己的所学知识加以运用,二是俄罗斯方块是我第一个接触到的游戏,它的实现方法也吸引着我。我希望通过探索实践去实现它,在这次学习中从实践和实际的项目中提高自己的编程能力
3、。因此我选定了这个题目。C+课程所学的概念、理论和方法,按照C+程序设计的基本步骤,设计出一个适当规模的程序来实现设计课程内容中的全部功能;设计主控模块程序对给出的程序源代码要给出各部分的详细注释自己根据能力及需要添加相应功能模块,增强模拟系统功能。1.2课程设计任务内容利用Microsoft Visual C+编写一个文本窗口下的俄罗斯方块游戏。要求:(1)利用类和多文件编写。(2)能够记录游戏得分和等级。(3)可暂停/继续游戏,使玩家在不愿游戏时退出。(4)信息提示时显示颜色变化。1.3关于编译软件本程序采用Microsoft Visual C+6.0的英文版本进行编译。VisualC+6
4、.0是Microsoft公司推出的基于Windows操作系统的可视化C+编程工具,尽管Microsoft公司推出了.NET平台的集成开发环境,但由于其良好的界面和可操作性,加上支持标准C/C+规范,但仍有相当多的编程人员使用VisualC+6.0进行应用系统的开发。关于稳定性,经测试,本程序可以在windows操作系统中稳定运行,较为稳定。 第二章 详细设计说明2.1程序设计2.1.1主要功能设计根据分析,俄罗斯方块这个程序一共要实现如下几个功能,开始游戏、游戏的暂停继续、游戏控制和退出游戏。其中游戏控制最为主要和重要,它控制着整个游戏的画面和有关数据的操作,是游戏的核心部分。暂停和退出功能做
5、成一体,在退出的提示下不做任何操作即可实现暂停的功能。程序结构如图2.1所示。 图2.1 2.1.2 程序流程图根据分析后的程序结构图设计出相应的流程图。俄罗斯方块的内容主要包括游戏开始,画背景和边框,显示分数等级和下一个方块的预览图;根据速度没隔一定时间方块自动下落,当有按键操作时,根据相应按键执行动作,每次动作前要判断是否动作可以执行。下落方块满一行时,消去该行,根据消去行数得到相应分数。分数达到一定程度,等级提升,速度加快。同时可以响应Esc按键,提示是否退出程序。如图2.2所示。 图2.2 2.2参数说明根据程序的结构,将俄罗斯方块需要实现的功能细化为相应的类成员函数。程序有两个类,一
6、个view类,用于背景相关操作。一个squar类,用于方块相关操作。2.2.1类设计声明(view类)class viewpublic:view();/类的缺省构造函数int getbgdata(int,int);/取得数组x,y点的数据值void scoreadd(int);/得分增加,根据消去行数void scorereset();/得分清零,用于升级后void levelup();/等级提升,当分数达到规定值后执行int gameover();/游戏结束void rowdelete();/消除满行void previewset(int (*p)4);/设置预览方块的形状数据void pr
7、eviewreset();/预览方块数据清零void setdata(int (*)2);/设置主游戏区数据值void datareset();/主游戏区数据清零void drawpreview();/显示预览方块private:int data2526;/主游戏区数组int preview44;/预览方块数组int rowsdelete;/每次消除行数变量int score;/得分变量int scorelevel;/升级规定值变量int level;/等级变量bool overflag;/结束标记变量void scorelevelup();/升级规定值提升;2.2.2类设计声明(squar类
8、)class view;/先向引用声明class squarpublic:squar();/类的缺省构造函数squar(squar &);/拷贝构造函数friend void cursor(int,int);/友元函数 控制光标位置void getcursor(int &,int &);/取得位置记录坐标void make();/随机产生一个方块void getmake(int (*p)4);/取得方块数据值void draw();/显示主方块void drop(view &);/方块下落void change();/方块变形int meet(int);/判断方块周围是否有障碍void tor
9、ecord(int (*)2);/传送需要记录的数据void reset();/方块数组清零int moveflag;/方块运动标记变量private:void move();/方块运动int shape44;/方块形状数据int x,y;/坐标int shapeindex;/方块形状序号int changeindex;/变形序号变量int speed;/下落速度变量;2.3函数功能说明2.3.1游戏界面俄罗斯方块的游戏界面包括游戏区域边框、下落方块绘制、右部计分和预览图显示等。游戏区域边框的绘制比较简单,循环中确定光标的位置输出特定字符,即可完成边框绘制。游戏区方块的绘制,循环从数据数组中依
10、次读出数据,根据读到的数据显示“”,最后组成方块的形状,完成方块的绘制。计分和预览图部分先画出一个矩形区域,然后控制光标在其中显示分数、等级、预览图和提示信息。2.3.2生成方块本程序中生成的方块有六种形状,每一种方块以shapeindex标记,在程序运行生成方块时,调用shapeindex=rand()%5+1;语句,确定当前要显示的是哪一个方块形状。而在实际运行中,第一次需要调用两次生成方块函数make(),将先产生的赋给游戏当前方块,第二个赋给预览图方块。以后每次产生一个方块,把预览方块赋给当前方块,把新产生的赋给预览方块。具体如图2.3所示。 图2.32.3.3方块变形俄罗斯方块的特点
11、就在于通过方块的变形拼满整行来消去该行方块从而使游戏可以继续下去,很难想象不能变形的俄罗斯方块是什么样子。而变形的过程就是根据当前方块形状改变方块的相对位置,这样就可以改变方块的形状了。在程序中每当按下Up键,程序判断可以变形后,根据当前方块的形状序号shapeindex和变化形状序号changeindex调用相应的方块数值赋给draw()函数,通过刷新重画就可以显示变化后的方块了。具体形状变化如图2.4所示。2.3.4方块显示 以上方块的操作都是数据层面的操作,而真正要在游戏窗口中看到数据的变化,还必须把方块不断的绘制出来。这就是draw()函数的作用。把当前运动的方块对应节点存储在一个4*
12、4数组里,变形和生成方块的过程就是更新该数组数据的过程。然后在draw()函数里检测数组的各个值,并控制光标跳到一定位置,画出“”组成方块。具体方块对应数组数值关系如图2.5所示。 图2.42.3.5障碍判断障碍判断,就是在方块运动中或者变形中判断周围是否有障碍阻碍下落、移位、变形。当方块下落遇到下面有方块或者到达下边界则应停止下落并记录数据,存入背景数据数组。变形时应判断这个变形是否可以进行,如果有障碍则不能变形。例如当方块达到右边界,而若变形则会越过边界,那么这个变形的命令是不应执行的。所有这些判断都由meet()函数进行,根据是否有障碍返回1或0,再由其他函数接收执行相应操作。2.3.6
13、消行计分游戏玩家拼满一行后,程序消去满行,并计分。中当一个方块下落停止后,程序检查方块是否充满了游戏区域,如果是结束游戏。不是,则判断是否构成消行条件,从下落方块的最低点依次向上检查是否可以消行,根据消去行数分数增加。分数达到一定程度,等级提升,速度加快。如图2.6所示。2.3.7暂停退出游戏的友好性在于能考虑用户的需要,随时可以暂停/继续游戏,在不愿继续游戏时退出游戏。本程序可以在用户需要的时候响应Esc按键,提示是否退出游戏,如果不做选择即可暂停游戏,等待选择。界面如图2.7所示。 图2.5 图2.6 图2.72.4 程序调试经过调试和修改,程序完全实现设计要求,成功模拟了俄罗斯方块的运行
14、过程和游戏效果,只是界面略微简陋,但已从程序层面上实现了游戏,达到了这次实训的要求和目的。程序正常生成方块,根据速度值每隔一定时间自动下落,如有操作按键按下,根据按键实现位移和变形。当方块满一行后,可以消除该行,同时记录分数和等级。按下Esc键红色提示信息正常显示,可以响应Y,N键决定是否退出游戏。2.5 软件使用说明 打开俄罗斯方块游戏后,通过控制方向区域的“上”、“下”、“左”、“右”来控制,“上”键代表变形转换,“下”、“左”、“右”均代表方向键,而“空格”代表“沉底”,也可以通过“W”、“S”、“A”、“D”来控制方向;“esc”代表退出游戏键。若想暂停游戏,也可通过“esc”键,当初
15、来询问框是,可不做选择,则可达到暂停的效果。 第三章 总结与体会通过这次课程设计,我收获了很多。首先把所学知识加以利用和巩固,其次在实践中遇到问题去探索和学习,更增加了新知识。在程序设计编写过程中两个类的数据交换是个比较麻烦的过程,这个类的定义过程中要用到另一个类做参数类型,而在后一个类中亦需要第一个类做参数类型,出现了互相调用的情况。编译提示未定义,只好在两个类外定义函数负责两个类函数的数据交换。实践证明达到了预期的目的,积累了经验。由于程序是用文本窗口模拟的图形,界面比较简陋,如果使用MFC用C+来实现,那么界面将会非常好,只是由于所学知识有限,只有下一步去探索了。通过这次的学习设计,我发
16、现我还有许许多多的不足的地方,比如c+的程序设计,源代码的书写等等,刚开始我发现我的问题后,十分紧张,感觉很绝望,没有别人的帮助,自己动手设计曾经自己想都没想过的东西,虽然很兴奋,但想想自己无从下手,原来的兴奋劲一下子都没了,很忙然。但是,通过与王老师的交流,经过老师的耐心讲解,我慢慢感到希望又重生了,于是我通过上网查找资料,进图书馆查找书籍等,终于知道了俄罗斯方块游戏的设计概念,终于知道了设计的方法,于是,渐渐地我的游戏设计理念诞生了。通过几个礼拜的设计,我的游戏渐渐初见成效了,当我把回车键摁下的一刹那,我十分激动,眼前的既熟悉又陌生的游戏出现在了我的面前,看着自己设计的童年时代经常玩的游戏
17、,我感慨万千。通过这次设计,我学会了很多东西,例如通过网络资料来寻求帮助,自己改正错误,加强了我自己的自己动手能力,对今后的学习和生活有很大的帮助,有助于以后的课程设计顺利完成。附录1 参考文献1段钢 编著 加密与解密(第三版).电子工业出版社.2009年8月2赵树升 赵韶平.Windows信息安全原理与实现.北京:清华大学出版社.2004年3杨永国.Visual C+ 6.0实用教程.北京:清华大学出版社.2004年4唐俊明.Visual C+ 6.0 编程实例与技巧.北京:高等教育出版,2002年5潘锦平.软件系统开发技术.西安:西安电子科技大学出版社, 1997年 附录2 源程序代码#i
18、nclude #include #include / 定义常量、枚举量、结构体、全局变量/#define WIDTH 10 / 游戏区宽度#define HEIGHT 22 / 游戏区高度#define SIZE 20 / 每个游戏区单位的实际像素/ 定义操作类型enum CMD CMD_ROTATE, / 方块旋转 CMD_LEFT, CMD_RIGHT, CMD_DOWN, / 方块左、右、下移动 CMD_SINK, / 方块沉底 CMD_QUIT / 退出游戏;/ 定义绘制方块的方法enum DRAW SHOW, / 显示方块 HIDE, / 隐藏方块 FIX / 固定方块;/ 定义七种
19、俄罗斯方块struct BLOCK WORD dir4; / 方块的四个旋转状态 COLORREF color; / 方块的颜色 g_Blocks7 = 0x0F00, 0x4444, 0x0F00, 0x4444, RED, / I 0x0660, 0x0660, 0x0660, 0x0660, BLUE, / 口 0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA, / L 0x2260, 0x0E20, 0x0644, 0x0470, YELLOW, / 反L 0x0C60, 0x2640, 0x0C60, 0x2640, CYAN, / Z 0x0360,
20、0x4620, 0x0360, 0x4620, GREEN, / 反Z 0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN; / T/ 定义当前方块、下一个方块的信息struct BLOCKINFO byte id; / 方块 ID char x, y; / 方块在游戏区中的坐标 byte dir:2; / 方向 g_CurBlock, g_NextBlock;/ 定义游戏区BYTE g_WorldWIDTHHEIGHT = 0;/ 函数声明/void Init(); / 初始化游戏void Quit(); / 退出游戏void NewGame(); / 开始新游戏vo
21、id GameOver(); / 结束游戏CMD GetCmd(); / 获取控制命令void DispatchCmd(CMD _cmd); / 分发控制命令void NewBlock(); / 生成新的方块bool CheckBlock(BLOCKINFO _block); / 检测指定方块是否可以放下void DrawBlock(BLOCKINFO _block, DRAW _draw = SHOW); / 画方块void OnRotate(); / 旋转方块void OnLeft(); / 左移方块void OnRight(); / 右移方块void OnDown(); / 下移方块vo
22、id OnSink(); / 沉底方块/ 函数定义/ 主函数void main() Init(); CMD c; while(true) c = GetCmd(); DispatchCmd(c); / 按退出时,显示对话框咨询用户是否退出 if (c = CMD_QUIT) HWND wnd = GetHWnd(); if (MessageBox(wnd, _T(您要退出游戏吗?), _T(提醒), MB_OKCANCEL | MB_ICONQUESTION) = IDOK) Quit(); / 初始化游戏void Init() initgraph(640, 480); srand(unsig
23、ned)time(NULL);/ 显示操作说明 setfont(14, 0, _T(宋体); outtextxy(20, 330, _T(操作说明); outtextxy(20, 350, _T(上:旋转); outtextxy(20, 370, _T(左:左移); outtextxy(20, 390, _T(右:右移); outtextxy(20, 410, _T(下:下移); outtextxy(20, 430, _T(空格:沉底); outtextxy(20, 450, _T(ESC:退出); / 设置坐标原点 setorigin(220, 20);/ 绘制游戏区边界 rectangle
24、(-1, -1, WIDTH * SIZE, HEIGHT * SIZE); rectangle(WIDTH + 1) * SIZE - 1, -1, (WIDTH + 5) * SIZE, 4 * SIZE); / 开始新游戏 NewGame();/ 退出游戏void Quit() closegraph(); exit(0);/ 开始新游戏void NewGame() / 清空游戏区 setfillstyle(BLACK); bar(0, 0, WIDTH * SIZE - 1, HEIGHT * SIZE - 1); ZeroMemory(g_World, WIDTH * HEIGHT);
25、/ 生成下一个方块 g_NextBlock.id = rand() % 7; g_NextBlock.dir = rand() % 4; g_NextBlock.x = WIDTH + 1; g_NextBlock.y = HEIGHT - 1;/ 获取新方块 NewBlock();/ 结束游戏void GameOver() HWND wnd = GetHWnd(); if (MessageBox(wnd, _T(游戏结束。n您想重新来一局吗?), _T(游戏结束), MB_YESNO | MB_ICONQUESTION) = IDYES) NewGame(); else Quit();/ 获
26、取控制命令DWORD m_oldtime;CMD GetCmd() / 获取控制值 while(true) / 如果超时,自动下落一格 DWORD newtime = GetTickCount(); if (newtime - m_oldtime = 500) m_oldtime = newtime; return CMD_DOWN; / 如果有按键,返回按键对应的功能 if (kbhit() switch(getch() case w: case W: return CMD_ROTATE; case a: case A: return CMD_LEFT; case d: case D: re
27、turn CMD_RIGHT; case s: case S: return CMD_DOWN; case 27: return CMD_QUIT; case : return CMD_SINK; case 0: case 0xE0: switch(getch() case 72: return CMD_ROTATE; case 75: return CMD_LEFT; case 77: return CMD_RIGHT; case 80: return CMD_DOWN; / 延时 (降低 CPU 占用率) Sleep(20); / 分发控制命令void DispatchCmd(CMD _c
28、md) switch(_cmd) case CMD_ROTATE: OnRotate(); break; case CMD_LEFT: OnLeft(); break; case CMD_RIGHT: OnRight(); break; case CMD_DOWN: OnDown(); break; case CMD_SINK: OnSink(); break; case CMD_QUIT: break; / 生成新的方块void NewBlock() g_CurBlock.id = g_NextBlock.id, g_NextBlock.id = rand() % 7; g_CurBlock
29、.dir = g_NextBlock.dir, g_NextBlock.dir = rand() % 4; g_CurBlock.x = (WIDTH - 4) / 2; g_CurBlock.y = HEIGHT + 2; / 下移新方块直到有局部显示 WORD c = g_Blocksg_CurBlock.id.dirg_CurBlock.dir; while(c & 0xF) = 0) g_CurBlock.y-; c = 4; / 绘制新方块 DrawBlock(g_CurBlock);/ 绘制下一个方块 setfillstyle(BLACK); bar(WIDTH + 1) * SI
30、ZE, 0, (WIDTH + 5) * SIZE - 1, 4 * SIZE - 1); DrawBlock(g_NextBlock);/ 设置计时器,用于判断自动下落 m_oldtime = GetTickCount();/ 画方块void DrawBlock(BLOCKINFO _block, DRAW _draw) WORD b = g_Blocks_block.id.dir_block.dir; int x, y; int color = BLACK; switch(_draw) case SHOW: color = g_Blocks_block.id.color; break; c
31、ase HIDE: color = BLACK; break; case FIX: color = g_Blocks_block.id.color / 3; break; setfillstyle(color); for(int i=0; i16; i+) if (b & 0x8000) x = _block.x + i % 4; y = _block.y - i / 4; if (y HEIGHT) if (_draw != HIDE) bar3d(x * SIZE + 2, (HEIGHT - y - 1) * SIZE + 2, (x + 1) * SIZE - 4, (HEIGHT -
32、 y) * SIZE - 4, 3, true); else bar(x * SIZE, (HEIGHT - y - 1) * SIZE, (x + 1) * SIZE - 1, (HEIGHT - y) * SIZE - 1); b = 1; / 检测指定方块是否可以放下bool CheckBlock(BLOCKINFO _block) WORD b = g_Blocks_block.id.dir_block.dir; int x, y; for(int i=0; i16; i+) if (b & 0x8000) x = _block.x + i % 4; y = _block.y - i
33、/ 4; if (x = WIDTH) | (y 0) return false; if (y HEIGHT) & (g_Worldxy) return false; b = 1; return true;/ 旋转方块void OnRotate() / 获取可以旋转的 x 偏移量 int dx; BLOCKINFO tmp = g_CurBlock; tmp.dir+; if (CheckBlock(tmp) dx = 0; goto rotate; tmp.x = g_CurBlock.x - 1; if (CheckBlock(tmp) dx = -1; goto rotate; tmp.
34、x = g_CurBlock.x + 1; if (CheckBlock(tmp) dx = 1; goto rotate; tmp.x = g_CurBlock.x - 2; if (CheckBlock(tmp) dx = -2; goto rotate; tmp.x = g_CurBlock.x + 2; if (CheckBlock(tmp) dx = 2; goto rotate; return;rotate: / 旋转 DrawBlock(g_CurBlock, HIDE); g_CurBlock.dir+; g_CurBlock.x += dx; DrawBlock(g_CurB
35、lock);/ 左移方块void OnLeft() BLOCKINFO tmp = g_CurBlock; tmp.x-; if (CheckBlock(tmp) DrawBlock(g_CurBlock, HIDE); g_CurBlock.x-; DrawBlock(g_CurBlock); / 右移方块void OnRight() BLOCKINFO tmp = g_CurBlock; tmp.x+; if (CheckBlock(tmp) DrawBlock(g_CurBlock, HIDE); g_CurBlock.x+; DrawBlock(g_CurBlock); / 下移方块v
36、oid OnDown() BLOCKINFO tmp = g_CurBlock; tmp.y-; if (CheckBlock(tmp) DrawBlock(g_CurBlock, HIDE); g_CurBlock.y-; DrawBlock(g_CurBlock); else OnSink(); / 不可下移时,执行“沉底方块”操作/ 沉底方块void OnSink() int i, x, y;/ 连续下移方块 DrawBlock(g_CurBlock, HIDE); BLOCKINFO tmp = g_CurBlock; tmp.y-; while (CheckBlock(tmp) g_CurBlock.y-; tmp.y-; DrawBlock(g_CurBlock, FIX);/ 固定方块在游戏区 WORD