模拟俄罗斯方块面向对象程序设计c课程设计报告.docx
《模拟俄罗斯方块面向对象程序设计c课程设计报告.docx》由会员分享,可在线阅读,更多相关《模拟俄罗斯方块面向对象程序设计c课程设计报告.docx(26页珍藏版)》请在冰豆网上搜索。
![模拟俄罗斯方块面向对象程序设计c课程设计报告.docx](https://file1.bdocx.com/fileroot1/2022-12/29/ca5ab76b-e4ae-4116-8447-2d65fb079166/ca5ab76b-e4ae-4116-8447-2d65fb0791661.gif)
模拟俄罗斯方块面向对象程序设计c课程设计报告
郑州轻工业学院本科
面向对象程序设计c++
课程设计总结报告
设计题目:
模拟俄罗斯方块
学生姓名:
系别:
专业:
班级:
学号:
指导教师:
2010年1月8日
郑州轻工业学院
课程设计任务书
题目模拟俄罗斯方块
专业、班级学号姓名
程序在文本窗口下输出特定字符模拟游戏俄罗斯方块的运行。
在游戏过程中,每次能随机产生一种方块并自动下落,根据按键控制进行相应的平移、变形和加速下落。
消去满行后,根据行数累计分数。
分数达到一定值后,等级提升,下落速度加快。
游戏区域积满后,游戏结束。
同时能响应退出按键,提示是否退出游戏。
指导教师签名:
课程负责人签名:
2010年1月8日
俄罗斯方块的设计与实现
第一章引言4
1.1.关于题目4
1.1.1.题目要求4
1.1.2.选题背景4
1.2.关于编译软件4
1.3.关于稳定性4
第二章程序设计5
2.主要功能设计5
2.1.程序流程5
第三章程序实现7
3.类设计声明7
3.1.view类7
3.2.squar类7
3.3.主要功能的实现8
3.3.1.游戏界面8
3.3.2.生成方块9
3.3.3.方块变形9
3.3.4.方块显示10
3.3.5.障碍判断11
3.3.6.消行计分12
3.3.7.暂停退出13
第四章程序测试14
4.游戏测试14
总结与体会15
附录:
16
引言
关于题目
题目要求
利用MicrosoftVisualC++编写一个文本窗口下的俄罗斯方块游戏。
要求:
利用类和多文件编写。
能够记录游戏得分和等级。
可暂停/继续游戏,使玩家在不愿游戏时退出。
信息提示时显示颜色变化。
选题背景
俄罗斯方块是家喻户晓的益智小游戏,选择这个题目一是为了将自己的所学知识加以运用,二是俄罗斯方块是我第一个接触到的游戏,它的实现方法也吸引着我。
我希望通过探索实践去实现它,在这次学习中从实践和实际的项目中提高自己的编程能力。
因此我选定了这个题目。
关于编译软件
本程序采用MicrosoftVisualC++6.0的英文版本进行编译。
VisualC++6.0是Microsoft公司推出的基于Windows操作系统的可视化C++编程工具,尽管Microsoft公司推出了.NET平台的集成开发环境,但由于其良好的界面和可操作性,加上支持标准C/C++规范,但仍有相当多的编程人员使用VisualC++6.0进行应用系统的开发。
关于稳定性
经测试,本程序可以在windows操作系统中稳定运行,较为稳定。
程序设计
主要功能设计
根据分析,俄罗斯方块这个程序一共要实现如下几个功能,开始游戏、游戏的暂停\继续、游戏控制和退出游戏。
其中游戏控制最为主要和重要,它控制着整个游戏的画面和有关数据的操作,是游戏的核心部分。
暂停和退出功能做成一体,在退出的提示下不做任何操作即可实现暂停的功能。
程序结构如图2-1所示。
图2-1程序结构图
程序流程
根据分析后的程序结构图设计出相应的流程图。
俄罗斯方块的内容主要包括游戏开始,画背景和边框,显示分数等级和下一个方块的预览图;根据速度没隔一定时间方块自动下落,当有按键操作时,根据相应按键执行动作,每次动作前要判断是否动作可以执行。
下落方块满一行时,消去该行,根据消去行数得到相应分数。
分数达到一定程度,等级提升,速度加快。
同时可以响应Esc按键,提示是否退出程序。
图2-2流程图
程序实现
类设计声明
根据程序的结构,将俄罗斯方块需要实现的功能细化为相应的类成员函数。
程序有两个类,一个view类,用于背景相关操作。
一个squar类,用于方块相关操作。
view类
classview
public:
view;//类的缺省构造函数
intgetbgdataint,int;//取得数组x,y点的数据值
voidscoreaddint;//得分增加,根据消去行数
voidscorereset;//得分清零,用于升级后
voidlevelup;//等级提升,当分数达到规定值后执行
intgameover;//游戏结束
voidrowdelete;//消除满行
voidpreviewsetint*p[4];//设置预览方块的形状数据
voidpreviewreset;//预览方块数据清零
voidsetdataint*[2];//设置主游戏区数据值
voiddatareset;//主游戏区数据清零
voiddrawpreview;//显示预览方块
private:
intdata[25][26];//主游戏区数组
intpreview[4][4];//预览方块数组
introwsdelete;//每次消除行数变量
intscore;//得分变量
intscorelevel;//升级规定值变量
intlevel;//等级变量
booloverflag;//结束标记变量
voidscorelevelup;//升级规定值提升;
squar类
classview;//先向引用声明
classsquar
public:
squar;//类的缺省构造函数
squarsquar&;//拷贝构造函数
friendvoidcursorint,int;//友元函数控制光标位置
voidgetcursorint&,int&;//取得位置记录坐标
voidmake;//随机产生一个方块
voidgetmakeint*p[4];//取得方块数据值
voiddraw;//显示主方块
voiddropview&;//方块下落
voidchange;//方块变形
intmeetint;//判断方块周围是否有障碍
voidtorecordint*[2];//传送需要记录的数据
voidreset;//方块数组清零
intmoveflag;//方块运动标记变量
private:
voidmove;//方块运动
intshape[4][4];//方块形状数据
intx,y;//坐标
intshapeindex;//方块形状序号
intchangeindex;//变形序号变量
intspeed;//下落速度变量
;
主要功能的实现
游戏界面
俄罗斯方块的游戏界面包括游戏区域边框、下落方块绘制、右部计分和预览图显示等。
游戏区域边框的绘制比较简单,循环中确定光标的位置输出特定字符,即可完成边框绘制。
游戏区方块的绘制,循环从数据数组中依次读出数据,根据读到的数据显示“?
”,最后组成方块的形状,完成方块的绘制。
计分和预览图部分先画出一个矩形区域,然后控制光标在其中显示分数、等级、预览图和提示信息。
具体界面如图3-1所示。
图3-1
生成方块
本程序中生成的方块有六种形状,如图3-2所示。
每一种方块以shapeindex标记,在程序运行生成方块时,调用shapeindexrand%5+1;语句,确定当前要显示的是哪一个方块形状。
而在实际运行中,第一次需要调用两次生成方块函数make,将先产生的赋给游戏当前方块,第二个赋给预览图方块。
以后每次产生一个方块,把预览方块赋给当前方块,把新产生的赋给预览方块。
图3-2
方块变形
俄罗斯方块的特点就在于通过方块的变形拼满整行来消去该行方块从而使游戏可以继续下去,很难想象不能变形的俄罗斯方块是什么样子。
而变形的过程就是根据当前方块形状改变方块的相对位置,这样就可以改变方块的形状了。
在程序中每当按下Up键,程序判断可以变形后,根据当前方块的形状序号shapeindex和变化形状序号changeindex调用相应的方块数值赋给draw函数,通过刷新重画就可以显示变化后的方块了。
具体形状变化如图3-3所示。
图3-3
方块显示
以上方块的操作都是数据层面的操作,而真正要在游戏窗口中看到数据的变化,还必须把方块不断的绘制出来。
这就是draw函数的作用。
把当前运动的方块对应节点存储在一个4*4数组里,变形和生成方块的过程就是更新该数组数据的过程。
然后在draw函数里检测数组的各个值,并控制光标跳到一定位置,画出“?
”组成方块。
具体方块对应数组数值关系如图3-4所示。
图3-4
障碍判断
障碍判断,就是在方块运动中或者变形中判断周围是否有障碍阻碍下落、移位、变形。
当方块下落遇到下面有方块或者到达下边界则应停止下落并记录数据,存入背景数据数组。
变形时应判断这个变形是否可以进行,如果有障碍则不能变形。
例如当方块达到右边界,而若变形则会越过边界,那么这个变形的命令是不应执行的。
所有这些判断都由meet函数进行,根据是否有障碍返回1或0,再由其他函数接收执行相应操作。
具体一些障碍情况如图3-5所示。
图3-5
消行计分
游戏玩家拼满一行后,程序消去满行,并计分。
中当一个方块下落停止后,程序检查方块是否充满了游戏区域,如果是结束游戏。
不是,则判断是否构成消行条件,从下落方块的最低点依次向上检查是否可以消行,根据消去行数分数增加。
分数达到一定程度,等级提升,速度加快。
如图3-6,图3-7,图3-8所示。
图3-6
图3-7
图3-8
暂停退出
游戏的友好性在于能考虑用户的需要,随时可以暂停/继续游戏,在不愿继续游戏时退出游戏。
本程序可以在用户需要的时候响应Esc按键,提示是否退出游戏,如果不做选择即可暂停游戏,等待选择。
界面如图3-9所示。
图3-9
程序测试
游戏测试
经过调试和修改,程序完全实现设计要求,成功模拟了俄罗斯方块的运行过程和游戏效果,只是界面略微简陋,但已从程序层面上实现了游戏,达到了这次实训的要求和目的。
程序正常生成方块,根据速度值每隔一定时间自动下落,如有操作按键按下,根据按键实现位移和变形。
当方块满一行后,可以消除该行,同时记录分数和等级。
按下Esc键红色提示信息正常显示,可以响应F1,F2键决定是否退出游戏。
总结与体会
通过这次课程设计,我收获了很多。
首先把所学知识加以利用和巩固,其次在实践中遇到问题去探索和学习,更增加了新知识。
在程序设计编写过程中两个类的数据交换是个比较麻烦的过程,这个类的定义过程中要用到另一个类做参数类型,而在后一个类中亦需要第一个类做参数类型,出现了互相调用的情况。
编译提示未定义,只好在两个类外定义函数负责两个类函数的数据交换。
实践证明达到了预期的目的,积累了经验。
由于程序是用文本窗口模拟的图形,界面比较简陋,如果使用MFC用C++来实现,那么界面将会非常好,只是由于所学知识有限,只有下一步去探索了。
附录:
程序主要模块源代码
squar:
:
squar
forinti0;i4;i++
forintj0;j4;j++
shape[i][j]0;
x22;
y0;
shapeindex1;
changeindex1;
speed1000;
moveflag1;
downtoearth0;
voidsquar:
:
make
srandinttime0;
shapeindexrand%6+1;
switchshapeindex
case1:
reset;
shape[1][0]1;
shape[1][1]1;
shape[1][2]1;
shape[1][3]1;
break;
case2:
reset;
shape[0][1]1;
shape[1][1]1;
shape[2][1]1;
shape[2][2]1;
break;
case3:
reset;
shape[0][2]1;
shape[1][2]1;
shape[2][1]1;
shape[2][2]1;
break;
case4:
reset;
shape[0][1]1;
shape[1][1]1;
shape[1][2]1;
shape[2][2]1;
break;
case5:
reset;
shape[0][2]1;
shape[1][1]1;
shape[1][2]1;
shape[2][1]1;
break;
case6:
reset;
shape[1][1]1;
shape[1][2]1;
shape[2][1]1;
shape[2][2]1;
break;
voidsquar:
:
draw
forinti0;i4;i++
forintj0;j4;j++
ifshape[i][j]
cursorx+j*2,y+i;
cout"?
";
intsquar:
:
meetintdirection
//遇见返回1;
intxxx/2,yyy;
switchdirection
case1:
//direcleft
yy+1;
switchshapeindex
case1:
//line
switchchangeindex
case1:
ifgetdatayy+1,xx-1
return1;
else
return0;
case2:
ifgetdatayy,xx||getdatayy+1,xx||getdatayy+2,xx||getdatayy+3,xx
return1;
else
return0;
case2:
//curlr
switchchangeindex
case1:
ifgetdatayy,xx||getdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case2:
ifgetdatayy+1,xx+2||getdatayy+2,xx
return1;
else
return0;
case3:
ifgetdatayy,xx||getdatayy+1,xx+1||getdatayy+2,xx+1
return1;
else
return0;
case4:
ifgetdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case3:
//curll
switchchangeindex
case1:
ifgetdatayy,xx+1||getdatayy+1,xx+1||getdatayy+2,xx
return1;
else
return0;
case2:
ifgetdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case3:
ifgetdatayy,xx||getdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case4:
ifgetdatayy+1,xx||getdatayy+2,xx+2
return1;
else
return0;
case4:
//s
switchchangeindex
case1:
ifgetdatayy,xx||getdatayy+1,xx||getdatayy+2,xx+1
return1;
else
return0;
case2:
ifgetdatayy+1,xx+1||getdatayy+2,xx
return1;
else
return0;
case5:
//dis
switchchangeindex
case1:
ifgetdatayy,xx+1||getdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case2:
ifgetdatayy+1,xx||getdatayy+2,xx+1
return1;
else
return0;
case6:
//disc
ifgetdatayy+1,xx||getdatayy+2,xx
return1;
else
return0;
case2:
//direcright
yy+1;
switchshapeindex
case1:
//line
switchchangeindex
case1:
ifgetdatayy+1,xx+4
return1;
else
return0;
case2:
ifgetdatayy,xx+2||getdatayy+1,xx+2||getdatayy+2,xx+2||getdatayy+3,xx+2
return1;
else
return0;
case2:
//curlr
switchchangeindex
case1:
ifgetdatayy,xx+2||getdatayy+1,xx+2||getdatayy+2,xx+3
return1;
else
return0;
case2:
ifgetdatayy+1,xx+4||getdatayy+2,xx+4
return1;
else
return0;
case3:
ifgetdatayy,xx+3||getdatayy+1,xx+3||getdatayy+2,xx+3
return1;
else
return0;
case4:
ifgetdatayy+1,xx+4||getdatayy+2,xx+2
return1;
else
return0;
case3:
//curll
switchchangeindex
case1:
ifgetdatayy,xx+3||getdatayy+1,xx+3||getdatayy+2,xx+3
return1;
else
return0;
case2:
ifgetdatayy+1,xx+2||getdatayy+2,xx+4
return1;
else
return0;
case3:
ifgetdatayy,xx+3||getdatayy+1,xx+2||getdatayy+2,xx+2
return1;
else
return0;
case4:
ifgetdatayy+1,xx+4||getdatayy+2,xx+4
return1;
else
return0;
case4:
//s
switchchangeindex
case1:
ifgetdatayy,xx+2||getdatayy+1,xx+3||getdatayy+2,xx+3
return1;
else
return0;
case2:
ifgetdatayy+1,xx+4||getdatayy+2,xx+3
return1;
else
return0;
case5:
//dis
switchchangeindex
case1:
ifgetdatayy,xx+3||getdatayy+1,xx+3||getdatayy+2,xx+2
return1;
else
return0;
case2:
ifgetdatayy+1,xx+3||getdatayy+2,xx+4
return1;
else
return0;
case6:
//disc
ifgetdatayy+1,xx+3||getdatayy+2,xx+3
return1;
else
return0;
case3:
//direcdown
switchshapeindex
case1:
//line
switchchangeindex
case1:
ifgetdatayy+2,xx||getdatayy+2,xx+1||getdatayy+2,xx+2||getdatayy+2,xx+3
return1;
else
return0;
case2:
ifgetdatayy+4,xx+1
return1;
else
return0;
case2:
//curlr
switchchangeindex
case1:
ifgetdatayy+3,xx+1||getdatayy+3,xx+2
return1;
else
return0;
case2:
ifgetdatayy+3,xx+1||getdatayy+3,xx+2||getdatayy+3,xx+3
return1;
else
return0;
case3:
ifgetdatayy+1,xx+1||getdatayy+3,xx+2
return1;
else
return0;
case4:
ifgetdatayy+2,xx+2||getdatayy+2,xx+3||getdatayy+3,xx+1
return1;
else
return0;
case3:
//curll
switchchangeindex
case1:
ifgetdatayy+3,xx+1||getdatayy+3,xx+2
return1;
else
return0;
case2:
ifgetdatayy+3,xx+1||getdatayy+3,xx+2||getdatayy+3,xx+3
return1;
else
return0;
case3:
ifgetdatayy+1,xx+2||getdatayy+3,xx+1
return1;
else
return0;
case4:
ifgetdatayy+2,xx+1||getdatayy+2,xx+2||getdatayy+3,xx+3
return1;
else
return0;
case4:
//s
switchchangeindex
case1:
ifgetdatayy+2,xx+1||getdatayy+3,xx+2
return1;
else
return0;
case2:
ifgetdatayy+3,xx+1||getdatayy+3,xx+2||getdatayy+2,xx+3
return1;
else
return0;
case5:
//dis
switchchangeindex
case1:
ifgetdatayy+2,xx+2||getdatayy+3,xx+1
return1;
else
return0;
case2:
ifgetdatayy+2,xx+1||getdatayy+3,xx+2||getdatayy+3,xx+3
return1;
else
return0;
case6:
//disc
ifgetdatayy+3,xx+1||getdatayy+3,xx+2
return1;
else
return0;
case4:
//direcup
switchshapeindex
case1:
//line
switchchangeindex
case1:
ifgetdatayy+1,xx||getdatayy+1,xx+2|