c++课程设计俄罗斯方块游戏1_毕业论文
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
课程设计报告
课程名称:面向对象程序设计C++
设计题目:俄罗斯方块游戏___________ 专业:计算机科学与技术______________ 姓名:_________________
学号:____________
指导教师:________
2015年12 月25日
目录
一、需求分析 (3)
1.1 系统概述 (3)
1.2 游戏特色 (3)
1.3 功能需求 (3)
二、总体设计 (4)
2.1 系统模块 (4)
2.2 系统业务处理流程 (5)
三、详细设计 (5)
3.1 砖块预显示 (5)
3.2 分数统计 (6)
3.3 砖块移动和游戏暂停的实现 (7)
3.4 播放背景音乐 (8)
3.5 游戏设置与帮助 (8)
3.6 背景位图的插入 (9)
3.7 砖块三维化 (9)
3.8 俄罗斯方块双人版的实现 (10)
四、测试与结果 (11)
4.1 整个游戏运行界面图 (11)
4.2 游戏设置与帮助页面图 (11)
五、总结 (12)
一、需求分析
1.1 系统概述
《俄罗斯方块》玩家通过键盘控制方块的形状样式和速度,组成相连的1 行或1 行以上方块会自动消除,方块消除到一定数量后会得到一定的分数,玩家可以升级,从而难度加大,也就是速度加快,玩家还可以通过消除一组方块,使得到的分数翻倍等到更多的分数,造成更强的分数效果。
游戏中玩家可以和其他玩家1V1 对战。
1.2 游戏特色
《俄罗斯方块》是基于pc 休闲平台上的单机对战休闲游戏,这就要求游戏本身不能过于庞大复杂,需要考虑到单机对战的灵活性和多变性。
在游戏中通过对方块速度的变,能够使玩家不仅仅通过自己消除方块来获胜,还可以等到更多的分数,因此获得胜利。
《俄罗斯方块》游戏在传统的俄罗斯方块当中加入了新鲜的游戏元素,例如可爱的方块的颜色,绚目的消除方块特效显示,在游戏本身的简单耐玩的基础上,大大丰富了游戏的观赏性和趣味性,令玩家有了完全的游戏体验,充分享受游戏带来的乐趣。
1.3 功能需求
(1) 实现双人俄罗斯方块
(2) 隐藏菜单栏、工具栏、状态栏
(3) 实现难度可以选择
(4) 实现下一个砖块预测功能
(5) 实现总分统计功能,和每步消除所得分数显示
(6) 实现下、左、右、旋转、暂停功能
(7) 实现背景音乐播放功能
(8) 添加游戏帮助菜单
(9) 实现砖块三维化
(10) 实现双缓冲避免屏幕闪烁
(11) 设置窗口大小,禁用最大化按钮,禁止鼠标拖动改变窗口大小
二、总体设计
2.1系统模块
图2-1
2.2系统业务处理流程
块类型与状态
随叶I :凯个码 览类變和状爲
图2-2
三、详细设计
3.1砖块预显示
砖块预显示的原理就是在第一次生成砖块的时候,一次生成 2个砖块。
然后 将第2个砖块预显示,第1个砖块掉下来。
接着将预显示的砖块掉下来,新随机 生成的砖块预显示。
这样的话,我们用 flagl 标记是不是第一次产生砖块
随1机牛一曲
啊专 块类型和
狀态
设锐砖块棘赳
<>J 卜落
否戟
输出固
■■/宦块/
置顶砖块 将時诀眾£挟 贝遴牆时数纽
诀/|:拦
N
置顶砖块
祥时川数据乂
厂倾显示砖块生成部分代码: if (1 ==
bTypel - (rand() % NUM_BRICK_TYPES) + l;//rand()%7:随机产生數字& iOrientl ■ (unsigned int)
(rand() % 4);//随机状态左七flagl = 0i
}
brickType - bTypel^//rand()K7:趣机卢生0-6ffi動宇*
InitOrientation = iOrientl;// 随机状态FF
if (9 “ flael)//2
{
bTypel - (rand() % HL h'_BRICK_TYPE5) + l;//rand(: <7:隨机产生•甜獨!宇* iOrientl ■ (unsigned int}
(rand() %斗);"随机状态日订
if (bTypel ■■ 1)
activeB-ickyi = new CISrick; /FE腌多态性的体现
else if (bTypel =- 2)
acti veBrickYl * new CLBrick;
else if (bTypel == 3) activeBrickYl - nth CSBrick;
"...省略4,5忑昇
a ctivtBr 1 ck¥1 ->SE K O1 our((un$i gned char)bTypel);,设贵砖块两色activeBr让kYlTpuUtTupliOLiEntl,
binJidth 2);畫顶bi nYl - >eet I mage (output Ina百亡丫1); //将固定块拷贝到制寸数组
activeBrickVl*>&perator>>(outputIfrageYl); 将冈I]左生的加入.
3.2分数统计
这里实现了,显示每次消除所得的分数和游戏总共所得的分数。
由于,我们有一个返回消除了多少行的函数removeFullLines(),所以我们将这个返回值乘以积分规则里面的值,就实现了显示每次消除所得的分数。
然后游戏总分就是累加每次得到的分数值。
因为砖块最多就是消除4行,所以这里用个switch()语
句来实现。
m_num是一个成员变量,保存的就是removeFullLi nes()的返回值。
"分數统计部分代码:
switch^rr_nurr2)
£
case 0:
{
m_num2 = m_nu[n2*0; nun)Lines2 += m_nuin2;
Jbreak;
case 1:
{
m_num2 = m_numi*5Q;n uniLines 2 += m_num2;
}break;
"...省略打3
case 4:
{
m_num2 = m_num2*1000; num^inesi += m_num2;
Jbreak;
default: break;
3.3砖块移动和游戏暂停的实现
这里原本是需要响应键盘按下事件的,所以需要添加WM_KEYDOW息响应然后将函数传进来的nChar,也就是你按的键盘值,和你游戏中设定的移动按键比较。
从而执行相应的操作。
同时这里也要熟悉一下虚拟按键码。
但是由于我们添加了位图按钮,导致键盘按键事件响应不了,我们这里就重载了PreTranslateMessage函数,在这个函数里面拦截按键消息,从而响应。
①一键下落:这里用了一个循环,直到下落到砖块与边界或者其他砖块产生冲突才停止下落。
②空格暂停:暂停的原理就是关闭定时器,KillTimer(l);// 关闭定时器
③空格继续:SetTimer(O,difficulty,NULL);〃继续恢复原来的下落速度
"具体代码如下:
BOOL CTetris View: : PreTrans latere a sage p f-'sg)
if (pPsg->Te5sage " EyDC'i.N)
{
//, , i
if (VK_ESCAPE ==pMs£*>wParam)//ESCjEi±i
{ PostQuitMessage (0 };
}
if (VK_SPACE == p^5E->wPara(n && n_Stop 1) {
KillTiiner(l);//^ 闭定时器
KillTiner(2);//^ 闭定时器m_Stop 工0;
}
else if(n_Stop -- 0)
<
SetTimertl^ifficulty^NULL};//^续
SetTimer (2, difficulty? HULL); ■绻续m_Stop = 1;
}
}
return 匚Vieu : : PreT ^anslate^- essagei p K,sg);
3.4播放背景音乐
添加头文件:#inelude <mmsystem.h> //播放音乐。
然后在工程->设置->链接-> 对象/库模块里面添加winmm.lib
然后就将已经准备好的.wav格式的音乐引入VC中。
这里可以自己先去下载.mp3格式的音乐,然后用格式工厂转换一下格式,我就是这么干的。
心耳体爵战昔乐和关闭音乐的代颐下:
PlaySDund( (LPCT5TR]IQH_WAVE1±Af InstanceHandl« (} SND_RE SOURCE | ENQ_AS¥WC) ; } J逵加在71 财壬我里面
PlaySounfKNULL, NULL^SND.FILEHAME);音乐
3.5游戏设置与帮助
这里就是调用了一个对话框,用来做一些解释说明。
实现步骤:
①插入一个对话框
②给对话框关联一个类
③在需要弹出对话框的函数里面定义一个对话框的对象,然后DoModal().弹出模态对话框。
静态文本超链接颜色和鼠标样式:
由于静态文本是不能响应鼠标点击事件的,所以我们要现将静态文本的ID 改掉口:
IDC STATIC Bl然后在样式中将通知勾选上。
这样就可以响应鼠标点
//TWO F Add your spscislizei cadThere BHct/or cell ■the class
击事件了。
Gmt £,应「二寸J;
接着就是要实现鼠标移动到超链接上面显示一个手的形状,这里我们需要载入一个手型的光标。
本来是载入这个:IDC_HAND就可以了,但是当我载入它的时候,编译,提示'TDC_HAN未定义。
查了一下原来是版本的问题,不支持手型的。
后来谷歌上找到了一个可以载入手型的方法:
m_hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(32649));
if (pHi f -.x > Mct.l■静u P V 4 Ftrt-riftit u p*f3<- <y > mct’tap *t pftfi-^pr-^ < r<ct pbonoB j
就是用一个全局的载入光标函数来载入。
光标载入好之后,添加一个鼠标移动事件的响
应,当鼠标移动到指定区域,显示手型光标。
return CZ-ldl-j t P- eT- -:ii ;
3.6背景位图的插入
这个就是界面美化神器了,就是因为这张背景整个游戏才变得比原来的美观了几倍。
第一次做的单文档,白色背景,是在是太不友好了。
这个背景图片是我从4399上面截图下来的,然后用ps制作了一下,使其符合我的要求。
"插入背杲囹片的代冯
CBitrrap bmp;
binp. ^oadBitmapdDB.BITKLAPl); / / /■加载f立圏I
m_brushBackground * Cre^tePatternBrush (ibmp); 创建位图画刷
CRect rect;
GetClientRect (&rect 容户IK 大小
pDC- >Fi 11 Rett (rec t 广u百hBxIcg广ourid); 〃将拒形区域用位图填充
3.7砖块三维化
这里用到函数Draw3dRect()实现砖块三维化,其中需要3个参数参数:
1.矩形区域;参数2:RGB() 参数3:RGB():
void Draw3dRect(LPCRECr IpRect f COLORREF clrTopLe-Ft t COLORREF clrBottonlUEht);
其中后面两个参数,由下面这两个函数返回。
具体代码如下:
COLORREF 匚TetrisView::6etLightColor(COLORREF m_crBody) {
BYTE r = GetRValue(ir_crBody);
BYTE g = GetGValue(m_crBody);
BYTE b = QetBValue(m_crBody);
r -:r + COLOR_CHA^GE>25S?255: r+CDLOR_CHANGE;
g = g + COLOR_CHANGE>255?255:g4-COLOR_CHANGE;
b - b + COLOR_CHANGE>255?255:b+COLOR_CHAMGE;return RGB(r,g?b);
}
COLORREF CTetrisView::GetDerkColor(COLORREF T_trBod>0
BYTE r 二GetRVelue(fn_crBody);
BYTE g = GetGValue(m_crBody);
BY f t b = GetBValu^(m_crBody);
r = r -匚OLOR_CHANGE<0?0:r-COLOR.CHAHGE;
g - E -匚OLOR_CHANGE<0?9:g-COLOR_CHANCE;
b = b - COLOR_CHANGE<0:b-COLOR_CHANGE; return RGB(rj g^b)J
3.8俄罗斯方块双人版的实现
其实实现双人版的很简单,就是将FillRect()填充区域右移一定距离就实现
了双人版的。
当然,是在你将第二个游戏的代码也编写好的前提下,不然只是把左边玩家的界面再显示一次,那没得意思。
同理,预显示也就是这么实现的,就是调整了一下砖块显示的位置。
/ M坪航家上辅戏面橫显示的牝码=
for (i < i < height;卄行的画薛境
£
for (j ® &i j < nidthj ++j)
(
rd = €Rect(J*riS12e+149a i*nSlze+70, (i*l)*ri5ize+7@);
rc2 = WectCi^nSil^SSj PnSiEe+7^ (ji+l>*n5iM+«S5j (i+i)*n$lw+TO)j
打综制面扳
//^SlLplayer
if (B != ImsEO[i][j])
{
pK- >FillRect(rclj iCBrush(0rickColar[iragel[i] [ j ]])),;打画临时直块(运纳中)
pDC- >Drnn3-dRect(r t<l a GietLi£ht€olD!!B(Bi fc i.ckCclof i[iTia£el[i J[ J]] L Get DarkCol or (Br lekCc 10^( i mfleel [ £J [ J J ])) j } //畀面2p layer
if (0 !- iiMge2[i][j])
pDC- >Fillftect(rc2J SCBnishf BriekColor [1 1 ] [j j ]))/画临旳鹫块(运动申)
pK ・ > Drawl dRect (rc2p6Bt LightCnl nr(Br icKCQlar[ image2 GetDarkCDlor (Br LcfcCalor( image2 [i)[ j]]
四、测试与结果
4.1整个游戏运行界面图
其中Next是预显示,Point是每次固定块后所得的分数,X0用于播放/暂停背景音乐,a,b,c用于选择游戏难度。
START点击开始游戏。
下面还有个总分统计栏。
图4-1
4.2游戏设置与帮助页面图
口
Qs
■ -
START
图4-2
五、总结
这次编写双人版俄罗斯方块,主要参照了VC+实验指导书,界面主要就是插入了一个位图背景,图是从4399上面截图下来的,然后ps成自己需要的大小并转化成.bmp格式。
插入后,再就是在适当的地方显示砖块和分数统计,这样一个界面就做好了。
界面上的按钮,我是用位图按钮CBitmapButton实现的,这里有个小插曲,就是4张图片的大小问题,我本来的意思是想让鼠标点击的时候就显示一张小一点的图片,从而达到按钮的效果,所以我就做了4张大小不同的位图,导致了后来的白边的产生。
另外,由于添加了位图按钮导致了按键事件WM_KEYDOW鼠标点击事件WM_LBUTTONDOW晌应,我也不知道是为什么。
好在MFC中消息都要经过翻译后再发送,所以我就在PreTranslateMessage实现了按键和鼠标点击事件,开始不知道pMsg->pt传送进来的是相对于桌面的坐标。
另外还有一个问题就是关于CRect的问题,女口:我定义了一个CRect rect(10,10,100,100); 然后我将rect.top, rect.left …转换成CString 类型,
然后pDC->TextOut输出出来确是(0,0,99,99)不明白这是什么原因。
总之,这次小游戏的编写,让我自己学到了不少的东西,对MFC勺操作也更加熟练了。