QT版连连看制作的实验报告Word文件下载.docx
《QT版连连看制作的实验报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《QT版连连看制作的实验报告Word文件下载.docx(27页珍藏版)》请在冰豆网上搜索。
可移植性、易用性、执行速度快等特点。
(2)QT的优势
●XML支持。
●大量的开发文档
●支持2D/3D图形渲染,支持OpenGL
●优良的跨平台特性,Qt支持下列操作系统:
MicrosoftWindows95/98,MicrosoftWindowsNT,Linux,Solaris,SunOS,HP-UX,DigitalUNIX(OSF/1,Tru64),Irix,FreeBSD,BSD/OS,SCO,AIX,OS390,QNX等等。
●面向对象,Qt的良好封装机制使得Qt的模块化程度非常高,可重用性较好,对于用户开发来说是非常方便的。
Qt提供了一种称为signals/slots的安全类型来替代callback,这使得各个元件之间的协同工作变得十分简单。
●丰富的API,Qt包括多达250个以上的C++类,还提供基于模板的collections,serialization,file,I/Odevice,directorymanagement,date/time类。
甚至还包括正则表达式的处理功能。
2.2游戏功能需求
本次设计是在传统的连连看上设计实现对战的连连看,玩家通过达到一定的积分来获得继续闯关的机会,还有机会开启神秘的应藏关,以此来增加游戏的可玩性。
游戏的基本规则:
程序随机产生任意成对的图片,当定点击开始游戏时,电脑根据时间参数随机生成固定的成对图片,游戏再次开始,玩家可通过鼠标上的左键,自由的点两张图片。
如果点击两次时,两张图片相同,且满足程序的算法则这两张图片可消去。
消去图片后,游戏可给玩家加分,若在规定的时间内,玩家没有消掉所有的图片则游戏失败。
由于是闯关模式,达到一定分数的玩家可以继续挑战新的游戏,游戏的难度会相应增加,并且还增加了新玩法。
具体的游戏功能如下:
游戏界面需求:
设计良好的游戏界面可以让玩家充分感受到游戏带来的娱乐性,游戏的背景取自网上中的图片,体现了游戏的挑战性。
鼠标处理事件需求:
通过点击主窗体中相应的按钮,可以实现游戏的开始、暂停、结束,通过点击选项设置中相应的按钮,可设置声音的大小及方向键↓的功能。
显示需求:
当两次点击的图片相同且满足算法可以消去,当达到一定分数的时候,游戏会进入下一关,并有障碍了。
游戏闯关设计需求:
随着游戏的难度不同,玩法会发生改变,需要在游戏中设置障碍,蒙手游戏。
如果玩家能到达并完成最后一关,则玩家挑战成功,游戏结束。
最后游戏效果如下:
三.游戏总体设计
3.1总体设计
整体设计思想:
进入游戏后,有三个按钮可供玩家选择:
开始游戏,游戏设置,退出游戏,在进入相应子菜单后也可返回到主菜单,每个菜单的具体设计将在后面介绍,以下是总体的游戏流程图。
3.2游戏核心模块的设计
3.2.1连连看所要求的是:
1.两个目标是相同的;
2.两个目标之间连接线的折点不超过两个。
(连接线由x轴和y轴的平行线组成)那么分析一下连接的情况可以看到,一般分三种情况:
(1)直线相连;
(2)一个折点;
(3)两个折点。
可以发现,如果有折点,每个折点必定有且至少有一个坐标(x或者y)是和其中一个目标点是相同的,也就是说,折点必定在两个目标点所在的x方向或y方向的直线上。
所以设计思路就是:
假设目标点p1,p2,如果有两个折点分别为z1,z2那么,所要进行的是:
Ø
如果验证p1,p2直线连线,则连接成立
搜索以p1,p2的x,y方向四条直线(可能某两条直线会重合)上的有限点,每次取两点作为z1,z2,验证p1到z1/z1到z2/z2到p2是否都能直线相连,是则连接成立。
3.2.2连连看消去算法实现
在检验两张图片能否消掉的时候,我们要让两张图片同时满足两个条件才行,就是两者配对并且连线成功。
分3种情况:
(从下面的这三种情况,我们可以知道,需要三个检测,这三个检测分别检测一条直路经。
这样就会有三条路经。
若这三条路经上都是空按钮,那么就刚好是三种直线(两个转弯点)把两个按钮连接起来了)
(1)相邻
(2)若不相邻的先在第一个按钮的同行找一个空按钮。
1).找到后看第二个按钮横向到这个空按钮所在的列是否有按钮。
2).没有的话再看第一个按钮到与它同行的那个空按钮之间是否有按钮。
3).没有的话,再从与第一个按钮同行的那个空按钮竖向到与第二个按钮的同行看是否有按钮。
没有的话路经就通了,可以消了.
(3)若2失败后,再在第一个按钮的同列找一个空按钮。
1).找到后看第二个按钮竖向到这个空按钮所在的行是否有按钮2).没有的话,再看第一个按钮到与它同列的那个空按钮之间是否有按钮。
3).没有的话,再从与第一个按钮同列的那个空按钮横向到与第二个按钮同列看是否有按钮。
没有的话路经就通了,可以消了。
若以上三步都失败,说明这两个按钮不可以消去。
四.具体方案
4.1视图层设计
4.1.1图形的产生
加载图块图片资源,调用图片库用函数DrawArea:
:
loadPixmap()来实现。
函数如下设计:
voidDrawArea:
loadPixmap()
{
background.load("
/background/background.png"
);
background=background.scaled(size());
QPixmappix("
/pattern/pattern.png"
intnum=pix.height()/PIX_SIZE;
for(inti=1;
i<
num;
++i){
qrealy=PIX_SIZE*i;
QPixmapp=pix.copy(0,y,PIX_SIZE,PIX_SIZE);
pixmap.push_back(p);
}
}
4.1.2判段消掉图片
如果两个图片一样,我们进行消块,并进行加分操作。
消块操作如下:
if(hitTimer)
killTimer(hitTimer);
hitTimer=startTimer(INTERVAL_HIT_TIMER);
++multiHit;
emithit(multiHit);
lineTimer=startTimer(INTERVAL_LINE_TIMER);
4.2逻辑层设计
僵局考虑
判断是否已经进入死局,死局条件:
在回合尚未结束的情况下遍历面板,无法找到一对可销图块则判定为死局。
若找到一对可销图块,则将其记录为hintA和hintB,以供hint()函数利用。
设计代码如下:
boolDrawArea:
isDead()
inti,j,x,y;
if(!
pairLeft)
returntrue;
for(i=0;
xMax;
for(j=0;
j<
yMax;
++j){
if(board[i][j]){
for(x=i;
x<
++x){
if(x==i)y=j+1;
elsey=0;
for(;
y<
++y){
if(board[x][y]==board[i][j]){
if(isPosLinkable(i,j,x,y)){//如果消块成功,那么这里就变成了0
hintA.x=i;
hintA.y=j;
hintB.x=x;
hintB.y=y;
returnfalse;
}
4.3其它相关技术的实现
键盘事件响应
连连看是通过鼠标左键来控制游戏的运行,那么是具体如何实现的呢?
这就需要用到键盘的左击事件,通过响应鼠标的按下事件来实现。
玩家通过鼠标左键来控制图片的点击。
具体代码实现:
通过重新实现虚函数GameWindow:
keyPressEvent(QKeyEvent*event)来响应相应的键盘按键事件。
五.游戏的测试
5.1选项按钮的功能测试
(1)点击“游戏开始”:
游戏正常开始,结果正常;
(2)点击“退出游戏”:
游戏正常退出,结果正常;
(3)点击“暂停”:
游戏停止,“暂停”变为“取消暂停”,再点击“取消暂停”:
游戏继续,结果正常;
(4)点击“返回主菜单”:
游戏退回到主菜单界面,结果正常;
5.2按键事件的功能测试
(1)两次点击相同图片,若满足算法,图片消失,则结果正常;
(2)图片点击测试:
游戏过程中,点击鼠标左键:
图片在没有其他图片阻挡的情况下可变色,结果正常;
5.3图片消失测试
(1)当点击两张相同图片:
两站图片同时消失,结果正常;
(2)当图片消失,且满足一条直线时分数增加10分。
5.4声音和显示测试
(1)进入游戏时:
背景音乐正常播放,图片消失时,有背景音乐播放;
(2)在游戏过程中,游戏区域背景颜色不断改变;
在开始最后一关时:
游戏区域越来越大,结果正常;
5.5测试结果分析
经过测试,本游戏实现了基本的连连看的功能,运行比较稳定,不过有些细节方面可能需要改进,游戏在很多方面还需要进一步完善。
六.小结
游戏设计与实践是一项复杂而庞大的工作,在选题之后,我才意识到过程的艰难,因为以前从来都没有接触过游戏设计,刚开始有点迷茫和彷徨。
后来通过翻阅书籍和在网上查阅资料,逐渐找到了一些感觉。
本次设计让我初步懂得了电子游戏涉及到的有关技术、方法,包括电子游戏选题、构思、设计步骤等。
并实现一些可演示的游戏软件,其中有很多应用了学习的相关技术,并且做到了界面、声音都能实际演示。
此次设计过程中印象最深的收获有:
1、学到了很多新知识,并且对老知识进行了回顾。
经过长时间的学习,更进一步熟悉了Qt编程、通过不断上机实验,调试程序,总结经验,从对课题的不理解到能够开始动手去做,提出新问题并自己想办法去解决问题,自己多实践,所以增强了动手能力。
2、提高了中、英文资料的检索能力。
这次专业设计过程中我查阅了多资料,包括一些期刊、杂志,还有网络中的电子文档、电子书籍、网页及下载的视频教学课程;
不但有中文资料还有英文资料。
这些资料,使我的眼界更开阔,对课题的认识更加深刻,编写程序的时候思路更加清楚,少走了很多弯路。
回顾此次设计过程,我学到了许多书本上没有学到的知识。
通过这次自己制作的软件,丰富了自己的实践技能,扩张了本专业的知识面,使我受益匪浅,同时也体验到了搞软件开发的难度。
在这次设计的同时,由于我对这样的软件开发还只是一个开始,了解的不多,这其中或许还有很多的不足,有些模块做得不是很好,有些功能还不能够完全的实现,如播放背景音乐时,只能播放一遍,因为游戏Qt类库中封装的东西太多,有些函数它底层的具体实现可能还没有真正的理解,所以,这也许就是本次游戏设计的不足之处。
七.源码(部分代码):
/*drawarea.cpp*/
#include"
drawarea.h"
#include<
iostream>
QMouseEvent>
QTimerEvent>
QPainter>
QLabel>
QDir>
QFileInfo>
stdio.h>
assert.h>
constintINTERVAL_LINE_TIMER=200;
constintINTERVAL_HIT_TIMER=2000;
constintPIX_SIZE=46;
constintAREA_WIDTH=Y_MAX*PIX_SIZE;
constintAREA_HEIGHT=X_MAX*PIX_SIZE;
DrawArea:
DrawArea(QWidget*parent):
QWidget(parent)
loadPixmap();
drawArea=newQLabel(this);
drawArea->
setGeometry(0,0,AREA_WIDTH,AREA_HEIGHT);
setPixmap(background);
isHintUsed=false;
QSizeDrawArea:
size()const
returnQSize(AREA_WIDTH,AREA_HEIGHT);
sizeHint()const
returnsize();
/*初始化关卡*/
initLevel(constMap&
mapData)
lastX=mapData.xMax;
lastY=mapData.yMax;
lineTimer=0;
hitTimer=0;
multiHit=0;
pairLeft=0;
xMax=mapData.xMax;
yMax=mapData.yMax;
for(inti=0;
++i)
for(intj=0;
board[i][j]=mapData.map[i][j];
if(board[i][j])
++pairLeft;
if(pairLeft%2!
=0){
emiterrorNotify(tr("
地图数据错误,地图存在不成对的块数"
));
return;
if(pairLeft==0){
地图数据为空"
pairLeft=pairLeft/2;
disorder(mapData.disorderCount);
//刚开局就判断死局,一个是初始化上帝之手,
//再一个最主要原因是为hint图块对赋值
//上帝之手的初始化必须在地图数据加载之后进行
if(isDead()){
godTouch=true;
emitgodTouchOn();
}else
godTouch=false;
isLevelOver=false;
drawBoard();
//[Test]从文件加载地图及相关配置信息。
loadMapFromFile(stringfileName)
intnDisorder;
FILE*mapFile;
mapFile=fopen(fileName.c_str(),"
r"
mapFile)
exit(-1);
if(fscanf(mapFile,"
%d%d"
&
nDisorder,&
pairLeft)==EOF){
Test:
地图数据加载失败"
%d"
board[i][j])==EOF){
地图数据无法成功加载"
fclose(mapFile);
disorder(nDisorder);
//根据指定的打乱次数nDisorder对面板内的非零数据进行交换
disorder(intnDisorder)
srand(clock());
//基本实现:
将非零数据加入到一个足够长的数组中,随机产生两个
//坐标进行交换
intpos[xMax*yMax][2];
intnBlock=0;
pos[nBlock][0]=i;
pos[nBlock][1]=j;
++nBlock;
for(inti=nDisorder;
i;
--i){
intpos1=rand()%nBlock;
generatePos2:
intpos2=rand()%nBlock;
if(pos1==pos2)
gotogeneratePos2;
intx1=pos[pos1][0];
inty1=pos[pos1][1];
intx2=pos[pos2][0];
inty2=pos[pos2][1];
std:
swap(board[x1][y1],board[x2][y2]);
/*加载图块图片资源*/
background.load("
background=background.scaled(size());
QPixmappix("
intnum=pix.height()/PIX_SIZE;
for(inti=1;
qrealy=PIX_SIZE*i;
QPixmapp=pix.copy(0,y,PIX_SIZE,PIX_SIZE);
pixmap.push_back(p);
//给玩家生成一对提示,并将其高亮显示
hint()
isHintUsed=true;
//将找到的一对图块画上边框
lastX=hintA.x;
lastY=hintB.y;
/*Timerevents.
*/
timerEvent(QTimerEvent*event)
if(event->
timerId()==lineTimer){
killTimer(lineTimer);
lineTimer=0;
timerId()==hitTimer){
multiHit=0;
killTimer(hitTimer);
/*接受鼠标按下的消息并将其发生的相对屏幕坐