基于Qt的连连看游戏的设计

发布时间:

邵阳学院毕业设计(论文)

在现今电子信息高速发展的时代,电子游戏已然成为大众最受欢迎的娱乐消遣方式,经典的连连看是个老少皆宜的小游戏,它实现由各式各样的成对图片组成,然后存储在一个二维的数组中,计算机随机产生各种不同类型的图片,根据计算机时钟控制它在一定的时间内随机产生,用户可根据鼠标和回车键点击图片、若两次点击的图片一样,则消掉图片。本文用QT来设计与实现简单的连连看游戏的基本功能,玩家可以在游戏区域中通过键盘控制来选取相同的两个物件,采用特定的消除规则对它们进行消除的操作,当游戏区域中的所有方块对都被消除后玩家即可胜利。文章对该游戏的算法以及游戏图案的绘制进行详细的介绍。实现起来较简单,同时也比较实用。
关键词:Qt;游戏设计;算法;数组;信号与槽


I


邵阳学院毕业设计(论文)
ABSTRACT
In the current era of rapid development of electronic information, electronic game has become the most popular entertainment popular pastime, classic Russian square is a enjoyed by young and old little game, it achieved by four square of color piece, and then stored in a two dimensional array, computer random generation seven different types of square, according to the computer clock control it in certain time keep produced, the user can according to the keyboard four the direction key control block turns, moves left, move to the right, move down operation and the program according to the seven square are stacked into a different model. And Laura square is based on square in Russia, give the Russian square new challenge pattern, its inspiration from the network another kind of popular video games-tomb raider. Players to the identity of the adventurers into the game, players need only to a certain score, can challenge higher difficulty levels of the game, of course, if you are good, you will have the chance to open the mysterious hide organs, the more full of imagination and stimulation of play will wait for you take your challenge. Key wordsQt; Game design; Algorithm; Array;Signals and slots.

II


邵阳学院毕业设计(论文)
目录
.................................................... I ABSTRACT ................................................ II 第一章 ............................................. 3 1.1 游戏背景 .......................................... 3 1.2 游戏概述 .......................................... 3 第二章 方案论证 .......................................... 5 2.1 选择开发语言 ...................................... 5 第三章 需求分析 ......................................... 13 3.1软硬件需求 ....................................... 13 3.2游戏功能需求...................................... 13 第四章 游戏总体设计 ..................................... 15 4.1 总体设计 ......................................... 15 4.2 游戏开始模块设计 ................................. 15 4.3 游戏设置模块设计 ................................. 16 4.4 游戏核心模块的设计 ............................... 16 第五章 具体实现 ......................................... 18 5.1模型层设计 ....................................... 18 5.2 视图层设计 ....................................... 18 5.3 其它相关技术的实现 ............................... 19 第六章 游戏测试 ......................................... 20 6.1 按键事件的功能测试 ............................... 20
1


邵阳学院毕业设计(论文)
6.2 图片消失测试 ..................................... 20 6.3 声音和显示测试 ................................... 20 6.4 测试结果分析 ..................................... 21 ................................................... 21 ................................................... 23 参考文献 ................................................ 24 附录 源代码 ............................................. 25






2


邵阳学院毕业设计(论文)
第一章
1.1 游戏背景
说到连连看,就不得不从经典小游戏说起,连连看是一款古老的风靡全球的经典游戏,它最早出现在PC机上,我国的用户都是通过红白机了解、喜欢上它的,相信有很多人到现在还是对它念念不忘的。无可争议,《连连看》是有史以来最伟大的游戏之一。在曾经发布过的所有游戏中,《连连看》还被认为是仅有的一个能够真正吸引广泛人群的作品,曾今造成的轰动与经济价值可以说是游戏史上的一件大事,它看似简单却变化无穷,令人着迷,相信大多数玩家都还记得为它痴迷得茶饭不思的那个连连看时代。但是随着网络信息的高速发展,连连看也要跟随时代的发展,以满足大众的需要。到如今,网络上已经出现了各种不同版本的连连看,它赋予玩家冒险家的角色,不断挑战你的想象,其全新的设计,创新的玩法,为经典的连连看蒙上了一层更加神秘的色彩。

1.2 游戏概述 1.2.1 游戏简介
游戏连连看顾名思义就是找出相关联的东西,这个连连看在网上基本是用在小游戏中,就是找出相同的两样东西,在一定的规则之内可以做为相关联处理。连连看的发展经历了从桌面游戏、在线游戏、社交游戏三个过程。

游戏连连看是源自台湾的桌面小游戏,自从流入大陆以来风靡一时,也吸引众多程序员开发出多种版本的连连看。这其中,顾方编写的阿达连连看以其精良的制作广受好评,这也成为顾方阿达系列软件的核心产品。并于2004年,取得了国家版权局的计算机软件著作权登记证书。 随着Flash应用的流行,网上出现了多种在线Flash版本连连看。如水晶连连看果蔬连连看等,流行的水晶连连看以华丽界面吸引了一大批的女性玩家。
2008年,随着社交网络的普及和开放平台的兴起,连连看被引入了3

邵阳学院毕业设计(论文)
社交网络。连连看与个人空间相结合,被快速的传播,成为一款热门的社交游戏,其中以开发者JoneveyManyou开放平台上推出的宠物连连最为流行。
1.2.2 游戏功能
本次设计连连看主要是在原连连看对战的基础上设计挑战模式,具体的功能如下所述:
1 游戏运行界面简单美观,操作简单,运行稳定;
2
能够根据不同的等级模式播放不同的游戏背景音乐,包括操作方向键、消行时的声音,音量由玩家操作控制;
3
设计不同的游戏难度,当玩家达到一定的积分,可以进入相关难度的等级;
玩家可直接操作界面上的相关按钮来控制游戏的开始、暂停、设置、退出等功能。

4


邵阳学院毕业设计(论文)
第二章 方案论证
2.1 选择开发语言
根据自己以前所学的关于C语言、C++Java、以及Qt的相关知识,并通过网上查找相关资料,了解到 CC++VBDelphiC#Java等均可以现劳拉方块游戏的设计。下面简单介绍下VBC++JavaQt各自的特点: 2.1.1 VB的特点
全称Visual Basic,它是以Basic语言作为其基本语言的一种可视化编程工具。在中国乃至全世界都能看到它的身影,它曾是在中国最为流行的编程工具,到现在还占据着非常重要的地位,对于它的好坏大家都有一定的了解,VB作为一种较早出现的开发程序以其容易学习,开发效率较高,具有完善的帮助系统等优点曾影响了好几代编程人员,但是由于VB不具备跨平台这个特性,从而也决定了VB在未来的软件开发中将会逐渐地退出其历史舞台;它对组件技术的支持是基于COMActiveX,对于组件技术不断完善发展的今天,它也显出了它的落后性;同时VB在进行系统底层开发的时候也是相对复杂的,调用API数需声明,调用不方便,不能进行DDK编程,不可能深入Ring0编程,不能嵌套汇编;而且面向对象的特性差;网络功能和数据库功能也没有非常突出的表现,综上所述,VB作为一种可视化的开发工具由于其本身的局限性,导致了它在未来软件开发中逐步被其他工具所代替。

2.1.2 C++的特点
C/C++的哲学就不一样了,同一份程序代码,只要在该平台重新Compile成该平台的执行档,就能在该平台执行,若文字模式下的程序,的确可以跨平台,程序完全不需修改,但GUI盛行以后,由于各GUILibrary都不一样且没有标准,所以GUI程序并没办法跨平台Compile,因为各平台都有专属的
Library。但是C/C++优势就是执行速度快,若能解决GUI Library的问题,则跨平台即可解决。
除了GUI Library需要统一外,还得看该Library设计的好不好才行,Linux GUI我没写过就不说了,若在Windows平台,BorlandC++ Builder5

邵阳学院毕业设计(论文)
使用DelphiVCL LibraryMicrosoftVisual C++可以用MFC.NET Framework,首先来看BorlandC++ Builder,它使用标准的ANSI C++语言开发,利用VCL写出来的程序也算蛮漂亮的,执行速度很快,比较麻烦的是C++ Builder当初为了缩短上市时间,并没有设计自己的Library,而是藉用DelphiLibrary,导致C++ BuilderCompile时,是先用DelphiCompilerVCL compileobject file后,再用C++ Builder将你写的C++程序compileobject file最后再用Linker将所有的object file link起来,由于这都是IDE在做,对程序设计师似乎影响不大,但VCL由于是DelphiLibrary,所以若想深入研究VCLsource code时,则必须学DelphiPascal才行,否则看不懂VCL source code,这也是很多人对C++ Builder却步的原因。
再来看MicrosoftVisual C++MFC用的是完整的ANSI C++语言,所以语言部分不是问题,但若你看过用MFC写的程序,你一定会惊讶为什么这么复杂,程序代码非常冗长不好看,且MFC是有名的难学,若 Visual C++.NET Framrwork,则无法使用ANSI C++,得用其.NET平台版本的C++/CLI相信这点很多人就有意见了,不过.NET Framework由于设计的不错,所以写出来的程序相当精简漂亮,感觉和C++ Builder差不多,不过无论C++ BuilderVisual C++开发的GUI所开发出来的程序都无法跨平台,当然也无法跨平台Compile

2.1.3 Java的特点
Java具有安全性、可移植性、多线程机制以及跨平台的良好特性,但是由于本人对Java语言不是很熟悉,所以此方案也予以否决。

2.1.4 Qt的特点
Qt拥有一个单一的Library,让你开发各种不同平台的程序,目前支持WindowsLinuxMacUNIXEmbedded Linux讲白话点,就是它提供了一个Library让你开发GUI程序,写好之后,只要在各平台重新Compile后,就可以在各平台执行,而且使用完整的ANSI C++语言,且不限Compiler6

邵阳学院毕业设计(论文)
只要是C++Compiler都可以,重要的是,该Library相当漂亮,写出来的程序很像C++ Builder.NET Framework的那样精简,不会向MFC那样复杂。目前Qt已经到第四个版本GUI部分算支持的相当完整,且支持数据库、XMLMulti- ThreadSocket等方面的programming若以后台角度来说,无论后端是什么数据库,只要透过相同的Interface不同数据库的Class来实做这个Interface前端GUI的程序写法完全不用改变,同理,面对不同OS理论上只要透过相同的Interface,不同OSClass各自实做这个Interface前端GUI的程序也完全不用改变,最后只要靠Compiler将程序compile成各平台的原生程序即可,这样即可保证其执行速度,不用再靠Virtual Machine但很可惜这个理想,这么多年来都没人可以做出来,或许是我孤陋寡闻吧Qt无疑是GUI终极解决方案,有强力的ANSI C/C++语言背书,又有单一的GUI Library且精简漂亮,又能Compile成各平台的原生执行档,几乎是最完美的解决方案了。

2.1.5 方案的选择
经过以上比较好,考虑到Qt的众多良好特性,尤其是其跨平台性,加上自己最近正在学习Qt为了能够更进一步掌握Qt编程,因此决定使用Qt开发连连看游戏。

2.2 Qt关键技术的介绍

2.2.1 Qt特点的具体介绍
1. 可移植性
Qt是一个跨平台GUI工具箱,不仅适用于Unix,它同样适用于MSWindows如果开发平台是MS Windows,可能选择的GUI工具箱为MicrosoftFoundation ClassesMFC这样就会失去众多的 Unix
用户。相反,如果开发平台是 Unix可能选择其它工具箱,如Motif等,同样会失去众多的Windows 用户。如果选择的GUI工具箱为Qt则只要在不同的平台上简单的编译源代码,就可以使原程序在不同的平台上运行,从而解决丢失用7

邵阳学院毕业设计(论文)
户的问题。
Qt把在处理不同窗口系统时的潜在问题隐藏了起来。为使Qt使用方便,Qt包含了一系列类,这些类使开发人员避免了在文件处理、时间处理等方面存在的依赖操作系统方面的细节。
2. 国际化
所谓国际化,通俗的讲,就是指在某国开发的软件可以方便的被其它国家的人使用Qt为本地化应用提供完全的支持,所有用户界面文本都可以基于消息翻译表被翻译成各国语言。另外Qt完全支持双字节16 bit国际字符标准。利Qt开发跨平台的国际化软件是一个方便、增量的过程。在开发过程中,利用Qtlinguist界面工具就能方便的将开发的软件翻译成各国语言,从而实现软件的国际化。
3. 面向对象
Qt 是一个C++工具箱,它由几百个C++类构成。在程序设计中可以使用这些类,如果Qt没有提供真正适合需求的组件,则可以方便的修改现有的组件或者重新编写组件Qt具有模块设计和注重软件构件或元素的可重用性的特点。一个组件不需要知道它的内容,而通过Qt特有的signalslot机制与外界通信、交流。
使用Qt进行应用程序的开发,可以充分利用其面向对象和模块化的特征,从繁琐的编程中解脱出来,专注于应用程序本身的实现。
4. 可用户化的外观
Qt支持主题,所以基于Qt的应用软件能在Motif外观、Windows外观,以及另一些用户化的外观之间互换,甚至改变运行时间。这些应用程序不管是在 X Windows下还是在Microsoft Windows下都可以独立操作、运行。
5. 独有的Signal Slot机制
Signal Slot机制是Qt最重要的特征。在MS Windows中,程序通过消息机制和事件循环来实现图形对象行为的触发和处理;在Qt中,程序在一个类中定义多个SignalSlotSignal就相当于“事件”,而Slot就相当于响应事件的“方法”。为了实现“事件驱动”,需要将一个类的Signal和另一个类Slot连接起来(使用connect。采用这种机制是一种安全可靠的方法,它允8

邵阳学院毕业设计(论文)
许回调。并支持对象之间在彼此不知道对方信息的情况下进行合作,这使Qt常适合于真正的构件编程。
6. 开发程序的方便性
Qt提供了一个可视化的开发工具Qt Designer,使用该工具就像在Windows中使用Visual C++那样可以直接向项目中添加各种组件,而不需要一步一步地编写代码,这个特点是其它非可视化编程工具望尘莫及的Qt Designer中包含全面的联机帮助文档,包括超文本方式的Qt Manualman帮助手册页和补充指南。这些帮助不论是对于初学者还是专业人士,都是非常方便的。
7. 强大的功能
Qt的强大功能主要体现在以下几方面:拥有一套完整的组件,用户可以直接基于这些现成的组件开发出优秀的界面;拥有丰富的API函数,大概有250多个C++类;具有优越的绘画功能和2D/3D图形润色功能,Qt的绘画工具类Qpainter, 可以在任意一个绘画设备上润色图形,对于更高级的2D/3D图形可以结合使用OpenGLQt的组件,使用OpenGL就像用任意一个Qt组件一样方便,而且效果比纯粹使用OpenGL2D/3D图形更好;支持XML

2.2.2 Qt的类库
Qt类库大致可以分为三个部分:控件,框架和工具。
1. 控件
控件部分包括环境控件,主窗口控件,标准对话框, 基本的GUI控件,扩GUI控件,GUI组织控件,以及帮助系统控件。
环境控件为应用程序提供全局服务的类,包括系统设定、国际化等。例如QTranslator, Qapplication。主窗口类为应用程序提供界面框架,可以在上面添加菜单、工具条等,为应用程序提供集装箱的功能,如QMainWindow。标准对话框类是为打开/关闭文件,选择颜色等预先设计的标准对话框,如QColorDialog, QFileDialog基本控件包括所有的GUI控件,如按钮、组合框等,QPushButton扩展的控件包括树状视图、进度条等, QListView9

邵阳学院毕业设计(论文)
GUI组织类负责对各种控件进行组织以构成复杂的对话框, QGroupBox帮助系统控件是为应用程序提供在线帮助的类,QStatusBar,QToolTip
2. 框架
框架部分包括的是一些抽象的类,通常不可见,如对象模型、抽象控件、绘图、拖放、控件外观。对象模型是框架的基础,如QObject。可见的控件一般从抽象控件派生,如QButton。绘图类控制绘图, QBrush。拖放类控制拖放操作,如QDragObject。控件外观类控制控件的外观如颜色、字体等。例如QColor
3. 工具
工具部分包括时间日期和链表树等数据结构,它们和GUI无关。普通工具包括链表、堆栈、队列、树等常见数据结构,如QArray。图形处理工具控制图像的编码/解码算法。如QImageIOI/O控制工具处理I/O的一些类,如QFile时间和日期工具类处理时间和日期,Qdate, QTime另外还有其他杂类如Qsignal, QIconSet等。

2.2.3 Qt对象通讯机制
对象间通讯是面向对象程序设计的一个极其重要的内容,类似于Microsoft MFC的消息映射和事件循环Qt的对象间通讯采用的是信号—槽(signalslot机制,信号就好像是事件,而槽则是响应事件的方法。如果需要实现对象间的通讯,只需要把一个对象的信号和另外一个对象的槽使用连接(connect起来。
信号—槽机制说明:
Qt下对象间的通讯用信号—槽机制来实现。信号—槽机制是Qt的一个中心特征并且也是它与其它图形工具包的最不相同的部分。2-1直观地表示了这种机制是如何工作的。


10


邵阳学院毕业设计(论文)


2-1 信号与槽的连接原理图
在图形用户界面编程中,经常希望一个窗口部件的一个变化被通知给另一个窗口部件。更一般地,希望任何一类对象可以和其它对象进行通讯。例如,如果正在解析一个XML文件,当遇到一个新的标签时,也许要通知列表视图正在用来表达XML文件的结构。较老的工具包是使用一种被称作回调的通讯方式来实现同一目的。回调是指一个函数的指针,所以如果希望一个处理函数通知一些事件,可以把另一个函数(回调的指针传递给处理函数,处理函数在适当的时候调用回调函数。回调有两个主要缺点:首先他们不是类型安全的,从来都不能确定处理函数使用了正确的参数来调用回调;其次回调和处理函数是非常强有力地联系在一起的,因为处理函数必须知道要调用哪个回调。
Qt中有一种可以替代回调的技术:使用信号和槽。当一个特定事件发生的时候,一个信号被发射。Qt的窗口部件有很多预定义的信号,但是总是可以通过继承来加入自己定义的信号。槽就是一个可以被调用处理特定信号的函数。Qt的窗口部件有很多预定义的槽,通常也可以加入自己的槽,这样就可以处理感兴趣的信号了。
信号—槽机制是类型安全的:一个信号的签名必须与它的接收槽的签名相匹配。实际上一个槽的签名可以比它接收的信号的签名少,因为它可以忽略额外的签名。因为签名是一致的,编译器就可以帮助检测类型是否匹配。信号和槽是宽松地联系在一起的:一个发射信号的类不用知道哪个槽要接收这个信号。Qt信号和槽的机制可以保证如果把一个信号和一个槽连接起来,槽会在正确的时间使用信号的参数而被调用。信号和槽可以使用任何数量、任何类型的参数。它们是完全类型安全的,不会再有回调核心转储。
11


邵阳学院毕业设计(论文)
QObject类或者它的一个子类(比如QWidget继承的所有类都可以包含信号槽。当对象的状态发生改变的时候,信号被发送给其它对象,从而实现了该对象与其它对象的通信。对象在发射信号时,无须知道有没有槽接收它所发射的信号,而槽是正常的成员函数,一个槽不知道它是否被任何信号连接,这就是信息封装,这种封装确保了对象可以用作一个软件组件。此外,使用对象时也无须知道这种通讯机制的实现细节。在信号—槽机制实现的过程中,可以把许多信号和单一槽相连,也可以把一个信号和许多槽相连。把一个信号和另一个信号直接相连也是可以的。(这时,只要第一个信号被发射时,第二个信号立刻就被发射总体来看,信号和槽构成了一个强有力的组件编程机制。




12


邵阳学院毕业设计(论文)
第三章 需求分析
3.1软硬件需求

本次的开发环境所采用的操作系统为Linux很严格,所以硬件需求不做讨论。
操作系统的Ubuntu10.10本,编程环境是基于QT 4.7Qt creator版本,由于本游戏对硬件的要求不是3.2游戏功能需求

本次设计是在传统的连连看上设计实现对战的连连看,玩家通过达到一定的积分来获得继续闯关的机会,还有机会开启神秘的应藏关,以此来增加游戏的可玩性。
游戏的基本规则:程序随机产生任意成对的图片,当定点击开始游戏时,脑根据时间参数随机生成固定的成对图片,游戏再次开始,玩家可通过鼠标上的左键,自由的点两张图片。如果点击两次时,两张图片相同,且满足程序的算法则这两张图片可消去。消去图片后,游戏可给玩家加分,若在规定的时间内,玩家没有消掉所有的图片则游戏失败。由于是闯关模式,达到一定分数的玩家可以继续挑战新的游戏,游戏的难度会相应增加,并且还增加了新玩法。具体的游戏功能如下:
游戏界面需求:设计良好的游戏界面可以让玩家充分感受到游戏带来的娱乐性,游戏的背景取自网上中的图片,体现了游戏的挑战性。 鼠标处理事件需求:通过点击主窗体中相应的按钮,可以实现游戏的开始、暂停、结束,通过点击选项设置中相应的按钮,可设置声音的大小及方向键↓的功能。显示需求:当两次点击的图片相同且满足算法可以消去,当达到一定分数的时候,游戏会进入下一关,并有障碍了。
游戏闯关设计需求:随着游戏的难度不同,玩法会发生改变,需要在游戏中设置障碍,蒙手游戏。如果玩家能到达并完成最后一关,则玩家挑战成功,游戏13

邵阳学院毕业设计(论文)
结束。


3.1 游戏开始界面

14


邵阳学院毕业设计(论文)

第四章 游戏总体设计

4.1 总体设计

整体设计思想:进入游戏后,有三个按钮可供玩家选择:开始游戏,游戏设置,退出游戏,在进入相应子菜单后也可返回到主菜单,每个菜单的具体设计将在后面介绍,以下是总体的游戏流程图。


设置网格 设置声音
过关
过关
设置加速
第六关
第„关
失败
过关 第二关
第一关
键盘方向键控制游戏
继续
开始游戏
设置选项
暂停
主菜单


退游戏
挑战成功 返回主菜单
4-1 游戏总体流程图设计
4.2 游戏开始模块设计

此模块为本次设计的核心模块,玩家在主菜单设置好游戏选项后点击开始按钮后开始游戏,并进入游戏窗口,游戏窗口大体是这样设计的:首先最上面一栏15

邵阳学院毕业设计(论文)
显示当前处于第几关,游戏区域分为两部分,主游戏区显示当前游戏画面,其宽设置为10个单位的小方块图片的边长,高为20,游戏区域右边的上面部分设置3个功能按钮:重新开始游戏、暂停、返回主菜单按钮;游戏区域右边的下面部分则显示主菜单界面,该界面在游戏开始后处于隐藏状态,当玩家点击“返回主菜单”按钮后,主菜单会重新显示出来,同时游戏界面处于隐藏状态。在开始游戏后,当玩家获得一定积分后,会进入下一关,如果失败,则必须重新开始。玩家在顺利完成第五关后,这时,玩家就能进入神秘的隐藏关,一次来增加游戏难度(相信那将会很有趣)

4.3 游戏设置模块设计

游戏设置模块提供了3个设置选项:是否显示游戏网格、音量设置以及音效设置,这些设置的灵活性可以方便不同水平用户的自由选择,以便一步步晋级。而音效效果则可以增加用户玩游戏的乐趣。设置好游戏选项后,即可返回主菜单开始游戏,在游戏的过程中也可以随时暂停返回主菜单,再进行重新设置游戏选项,这样更加方便用户的使用。

4.4 游戏核心模块的设计
连连看所要求的是: 1:两个目标是相同的 2两个目标之间连接线的折点不超过两个。连接线由x轴和y轴的平行线组成) 那么分析一下连接的情况可以看到,一般分三种情况 1:直线相连 2:一个折点 3:两个折点:
可以发现,如果有折点,每个折点必定有且至少有一个坐标(x或者y)是和其中一个目标点是相同的,也就是说,折点必定在两个目标点所在的x方向或y方向的直线上。
所以设计思路就是:
16


邵阳学院毕业设计(论文)
假设目标点 p1 , p2 ,如果有两个折点分别为z1 , z2 那么,所要进行的是 1:如果验证p1 , p2 直线连线,则连接成立

2搜索以p1,p2x,y方向四条直线(可能某两条直线会重合)上的有限点,每次取两点作为z1,z2 ,验证p1z1/z1z2/z2p2 是否都能直线相连 是则连接成立

连连看消去算法实现
在检验两张图片能否消掉的时候,我们要让两张图片同时满足两个条件才行,就是两者配对并且连线成功。
3种情况:(从下面的这三种情况,我们可以知道,需要三个检测,这三个检测分别检测一条直路经。这样就会有三条路经。若这三条路经上都是空按钮,那么就刚好是三种直线(两个转弯点)把两个按钮连接起来了 1.相邻

2. 若不相邻的先在第一个按钮的同行找一个空按钮。1.找到后看第二个按钮横向到这个空按钮所在的列是否有按钮。2.没有的话再看第一个按钮到与它同行的那个空按钮之间是否有按钮。3.没有的话,再从与第一个按钮同行的那个空按钮竖向到与第二个按钮的同行看是否有按钮。没有的话路经就通,可以消了.
3.2失败后,再在第一个按钮的同列找一个空按钮。1.找到后看第二个按钮竖向到这个空按钮所在的行是否有按钮 2.没有的话,再看第一个按钮到与它同列的那个空按钮之间是否有按钮。3.没有的话,再从与第一个按钮同列的那个空按钮横向到与第二个按钮同列看是否有按钮。没有的话路经就通了,可以消了。
若以上三步都失败,说明这两个按钮不可以消去。


17


邵阳学院毕业设计(论文)
第五章 具体实现
5.1模型层设计
5.1.1 图形的产生
通过图形工厂类ShapeFactorygetShape(ShapeListener listener方法随机产生方块的某种状态,这里运用了工厂设计模式。 5.1.2 图形的变形
char* MyItem::itemChange(unsigned char *currentItem来实现的,该函数首先是在内存中开辟一个新的4*4数组,用来保存变化后的方块,通过两个for循环,依次将数组中个元素的横坐标与列坐标交换位置,即可使原来的方块逆时针旋转90度,达到旋转方块的目的。

5.1.3 判段消掉图片
如果两在张图片满足一个拐点,没有拐点。两个拐点则该两张图片就可以消掉,同时需要用一个全局变量fullRowNum来保存此次一共消除了多少张,以便算分,没有拐点10分,一个拐点20,二个拐点的是30分。具体是通过函数void GameArea::clearRow(来实现的。
5.2 视图层设计

5.2.1 图片的显示
方块的显示是通过调用GameArea类中的draw_currentMap(方法实现的,首先判断存储方块的数组的值,凡是值为1的成员则给该数组控制的对应游戏区域的坐标通过调用painter.drawPixmap(绘制图片,具体的坐标和范围painter.drawPixmap(painter.drawPixmap(painter.setPen(hpainter.setBrush(来实现的这样就能显示方块,而且可以18

邵阳学院毕业设计(论文)
不断的改变颜色,使游戏界面富有动感。

5.2.2 游戏区域的显示
GameArea类中的draw_gameArea(函数来实现,在该函数中调用到了绘制网格的draw_Grid(函数和显示图片的draw_currrentMap(函数,draw_Grid(函数中调用Painter类的 painter.drawLine(函数绘制网格,具体的起始点和结束点同样由传递参数获得。
首先需要设置游戏区域大小,可以通过this->gameArea->setGameAreaPi()实现,还需要安置新的坐标原点可以通过调用该函数。


5.3 其它相关技术的实现
5.3.1键盘事件响应 连连看是通过鼠标左键来控制游戏的运行,那么是具体如何实现的呢?这就需要用到键盘的左击事件,通过响应鼠标的按下事件来实现。玩家通过鼠标左键来控制图片的点击。具体代码实现:通过重新实现虚函数QWidgetkeyPressEvent来响应相应的键盘按键事件。

5.3.2 声音的实现 声音的实现在这里用到了一个单独的类MyBoxAudio来封装,声音的实现要用到库类中的Phonon类,首先创建一个媒体对象medioObject和用于输出声音的设备接口对象audioOutput,有了这两个对象以后再调用Phonon::createPath(函数生成路径,然后绑定音频文件(必须为.wav格式的)最后调用medioObject.play(函数,即可实现声音的播放。

19


邵阳学院毕业设计(论文)
第六章 游戏测试
6.1 选项按钮的功能测试
1)点击“游戏开始”:游戏正常开始,结果正常;
2)点击“游戏设置”:弹出游戏设置对话框;能够选中向下键↓选项和是否绘制网格选项,声音大小可调,点击“返回”按钮能够回到主菜单,结果正常;
3)点击“退出游戏”:游戏正常退出,结果正常;
4)点击“暂停”:游戏停止,“暂停”变为“取消暂停”,再点击“取消暂停”:游戏继续,结果正常;
5)点击“返回主菜单”:游戏退回到主菜单界面,结果正常;

6.2 按键事件的功能测试

1)两次点击相同图片,若满足算法,图片消失,则结果正常; 2)图片点击测试:游戏过程中,点击鼠标左键:图片在没有其他图片阻挡的情况下可变灰色,结果正常;

6.3 图片消失测试
1)当点击两张相同图片:两站图片同时消失,结果正常;
2当图片消失,且满足一条直线时分数增加10分,满足一个拐点分数增20分,满足两个拐点,分数增加30分;

6.4 声音和显示测试
1)进入游戏时:背景音乐正常播放,图片消失时,有背景音乐播放;
2)在游戏过程中,游戏区域背景颜色不断改变;在开始最后一关时:游戏区域越来越大,结果正常;
20


邵阳学院毕业设计(论文)

6.5 测试结果分析
经过测试,本游戏实现了基本的连连看的功能,运行比较稳定,不过有些细节方面可能需要改进,游戏在很多方面还需要进一步完善。总体的游戏界面效果如下图所示:





6.1 游戏界面效果

21


邵阳学院毕业设计(论文)

游戏设计与实践是一项复杂而庞大的工作,在选题之后,我才意识到过程的艰难,因为以前从来都没有接触过游戏设计,刚开始有点迷茫和彷徨。后来通过翻阅书籍和在网上查阅资料,逐渐找到了一些感觉,在老师的指导下,自己也手动编写了几个简单的游戏,打地鼠游戏和网络N子棋双人对战游戏,本文以连连看游戏为例予以说明。
本次设计让我初步懂得了电子游戏涉及到的有关技术、方法,包括电子游戏选题、构思、设计步骤等。并实现一些可演示的游戏软件,其中有很多应用了学习的相关技术,并且做到了界面、声音都能实际演示。此次设计过程中印象最深的收获有:1学到了很多新知识,并且对老知识进行了回顾。经过长时间的学习,更进一步熟悉了Qt编程、通过不断上机实验,调试程序,总结经验,从对课题的不理解到能够开始动手去做,提出新问题并自己想办法去解决问题,自己多实践,所以增强了动手能力。2提高了中、英文资料的检索能力。这次毕业设计过程中我查阅了多资料,包括一些期刊、杂志,还有网络中的电子文档、电子书籍、网页及下载的视频教学课程;不但有中文资料还有英文资料。这些资料,使我的眼界更开阔,对课题的认识更加深刻,编写程序的时候思路更加清楚,走了很多弯路。
回顾此次设计过程,我学到了许多书本上没有学到的知识。通过这次自己制作的软件,丰富了自己的实践技能,扩张了本专业的知识面,使我受益匪浅,同时也体验到了搞软件开发的难度。在这次设计的同时,由于我对这样的软件开发还只是一个开始,了解的不多,这其中或许还有很多的不足,有些模块做得不是很好,有些功能还不能够完全的实现,如播放背景音乐时,只能播放一遍,因为游戏Qt类库中封装的东西太多,有些函数它底层的具体实现可能还没有真正的理解,所以,这也许就是本次游戏设计的不足之处。



22


邵阳学院毕业设计(论文)

今天,毕业设计也告一段落了,也就意味着我的大学时代即将结束。回想毕业设计这几个月,回想大学这四年的时光,感慨万千。值得留恋,值得追忆的,实在太多。还有很多老师,同学,朋友要感谢。首先,要感谢我的指导老师黄同成老师,他认真负责、踏实努力的工作精神,一丝不苟、严谨治学的专业作风,给我留下了深刻的印象。黄老师教给我的不仅是科学知识,他还教给了我做人的道理,所有这些都为我今后的人生道路奠定了坚实的基础,使我受益终生。同时,也要感谢成老师,黄磊老师,感谢信息工程系所有老师四年来的悉心教诲。
我们所在的实验室是一个温暖的大集体,也要感谢我们实验室各位老师给我的帮助。也要感谢与我同寝室的同学四年来,在工作和学习中给与我的鼓励和帮助。
最后,我还要向我的父母表示最真诚的感谢和祝福,是他们的辛勤和汗水养育了我,是他们的精神鼓舞了我,使我能够不懈努力和拼搏。


致谢人:陈 2012515

23


邵阳学院毕业设计(论文)
参考文献

[1]Mark Summerfield.白建平等译.Qt高级编程[M].电子工业出版社2008.8. [2]Stanley B.Lippman等著.李师贤等译.C++ Primer中文版[M].人民邮电出版社2008.7. [3]W.Richard StevensStephen A.Rago.尤晋元等译.UNIX环境高级编程[M].人民邮电出版社2008.10. [4]Stanley b.Lippman.侯捷译.深度探索C++对象模型[M].华中科技大学出版社2001.5. [5]谭浩强著. C程序设计 第三版[M].清华大学出版社2005.7. [6]严蔚敏、吴伟民著.数据结构[M].清华大学出版社2009.9. [7]宋劲杉编著.Linux C编程一站式学习[M].电子工业出版社2009.12. [8]Kenneth A.Reek.徐波译.C和指针[M].人民邮电出版社2003.9. [9]Jasmine BlanchetteMark Summerfield.闫锋欣等译.C++ GUI Qt 4编程[M].电子工业出版社2008.8. [10]丁林松、黄丽琴编著.Qt4图形设计与嵌入式开发[M].人民邮电出版社.2009.4.

24


邵阳学院毕业设计(论文)
附录 源代码
Mainwindow.cpp #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include"udp.h" #include #include #include "llk.h" #include
using namespace std;
MainWindow::MainWindow(QWidget *parent : QMainWindow(parent, ui(new Ui::MainWindow { ui->setupUi(this; connect(this, SIGNAL(recvMessage(QString,QString, SLOT(onRecvMessage(QString,QString;
//this->setCentralWidget(link;
//link->setMaximumSize(300,300;
25

this,
邵阳学院毕业设计(论文)
ui->editChatRec->setReadOnly(true;
// link = new llk(; size=6; isLinkE = false;
sendMessage("192.168.3.255",8838,"o192.168.3.117",true; }
MainWindow::~MainWindow( { delete ui; }
void MainWindow::changeEvent(QEvent *e { QMainWindow::changeEvent(e;
switch (e->type( { case QEvent::LanguageChange: ui->retranslateUi(this; break; default: break; } }

26


邵阳学院毕业设计(论文)
void MainWindow::on_btnSend_clicked( { QString string = ui->lineEdit->text(; if(ui->radiosingle->isChecked(==true {
sendMessage(string,8838,'c' + ui->editChat->text(,true; } else
{
string = "192.168.3.255"; sendMessage("192.168.3.255",8838,'c' ui->editChat->text(,true;
} QString str =trUtf8("自己对" + string +trUtf8("发送:" + "\n" + ui->editChat->text(; ui->editChatRec->setPlainText(ui->editChatRec->toPlainText( +" \n" +str; ui->editChat->clear(;
QScrollBar *bar = ui->editChatRec->verticalScrollBar(; bar->setSliderPosition(bar->maximum(; }
Ui::MainWindow* MainWindow::getUi( { return ui; } void MainWindow::onRecvMessage(QString msg, QString ipAdd 27
+
邵阳学院毕业设计(论文)
{
// QString time = QTime::currentTime(.toString(;
QString string =time + "\n" +QString(trUtf8("收到来自" + ipAdd + trUtf8(":的消息:" + "\n" + msg.right(msg.length(-1;

switch(msg.at(0.toAscii(
{ case 'o': //如果接受的是上线消息
ui->listWidget->addItem(msg.right(msg.length(-1;
break; default: //如果接受的是普通消息
ui->editChatRec->setPlainText(ui->editChatRec->toPlainText( +"\n" + string; break; }
QScrollBar *bar = ui->editChatRec->verticalScrollBar(; bar->setSliderPosition(bar->maximum(; }

void MainWindow::on_action_begin_triggered( {
28


邵阳学院毕业设计(论文)
/* link=new llk(; link->setsize(6; link->arrayInit(6; link->Create(6; link->show(; isLinkE = true;*/ // size=4; if(isLinkE
{ //link=new llk(; //link->setsize(8; // link->arrayInit(8; //link->Create(8; link->close(; isLinkE = false; } else
{ link=new llk(; link->setsize(size; link->arrayInit(size; link->Create(size; link->show(; isLinkE = true;
} if(isLinkE==false
{

29
邵阳学院毕业设计(论文)
link=new llk(; link->setsize(size; link->arrayInit(size; link->Create(size; link->show(; isLinkE = true; } }
void MainWindow::on_action_close_triggered( { this->close(; link->close(; }

void MainWindow::on_action_pause_triggered( {
if(isLinkE link->setEnabled(false; }
void MainWindow::on_action_return_triggered( { link->setEnabled(true; }
30


邵阳学院毕业设计(论文)

void MainWindow::on_action_easy_triggered( { size=6; if(isLinkE
{ //link=new llk(; //link->setsize(8; // link->arrayInit(8; //link->Create(8; link->close(; isLinkE = false; } else
{ link=new llk(; link->setsize(6; link->arrayInit(6; link->Create(6; link->show(; isLinkE = true;
} if(isLinkE==false
{ link=new llk(; link->setsize(6;
link->arrayInit(6;

31
邵阳学院毕业设计(论文)
link->Create(6; link->show(; isLinkE = true; } }

void MainWindow::on_action_soso_triggered( { size=8; /*llk *lin;
lin = new llk(; // this->setCentralWidget(lin; //lin->setGeometry(30,30,500,500; lin->setsize(8; lin->arrayInit(8;

lin->Create(8; lin->setVisible(true; lin->close(;*/ if(isLinkE
{ //link=new llk(; //link->setsize(8; // link->arrayInit(8; //link->Create(8;
link->close(;
32


邵阳学院毕业设计(论文)
isLinkE = false; } else
{ link=new llk(; link->setsize(8; link->arrayInit(8; link->Create(8; link->show(; isLinkE = true;
} if(isLinkE==false
{ link=new llk(; link->setsize(8; link->arrayInit(8; link->Create(8; link->show(; isLinkE = true; } }
void MainWindow::on_action_diffcult_triggered(
33


邵阳学院毕业设计(论文)
{ size=10; /*llk *lin;
lin = new llk(; // this->setCentralWidget(lin; //lin->setGeometry(30,30,500,500; lin->setsize(8; lin->arrayInit(8;

lin->Create(8; lin->setVisible(true; lin->close(;*/ if(isLinkE
{ //link=new llk(; //link->setsize(8; // link->arrayInit(8; //link->Create(8; link->close(; isLinkE = false; } else
{ link=new llk(; link->setsize(10; link->arrayInit(10;
link->Create(10;
34


邵阳学院毕业设计(论文)
link->show(; isLinkE = true;
} if(isLinkE==false
{ link=new llk(; link->setsize(10; link->arrayInit(10; link->Cre
mybutton.cpp #include "mybutton.h"
MyButton::MyButton(int value, QWidget *parent { this->value = value;
this->setParent(parent; QObject::connect(this,SIGNAL(clicked(,this,SLOT(mySlot(; }

void MyButton::mySlot( { emit myClicked(this->value; }
Main.cpp
#include
35


邵阳学院毕业设计(论文)
#include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include
using namespace std;

const unsigned int MAXBUF = 1024;
void* thd_handler(void* window { MainWindow* w=(MainWindow*window;

int sockfd; struct sockaddr_in my_addr; socklen_t addrlen; char buffer[MAXBUF]; unsigned int myport = 8838;

printf("server started!\n";
36


邵阳学院毕业设计(论文)


//create a socket for udp if((sockfd = socket(AF_INET,SOCK_DGRAM,0 < 0 //attention
{ perror("socket creation failure"; exit(errno; }

//initialize sockaddr_in bzero(&my_addr,sizeof(my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(myport; my_addr.sin_addr.s_addr = INADDR_ANY;

//bind if(bind(sockfd,(struct sockaddr*&my_addr ,sizeof(struct sockaddr == -1
{ perror("bind failure"; exit(errno; }
printf("bind success\n";
addrlen = sizeof(struct sockaddr; while(true
{
bzero(buffer,MAXBUF;
int len = recvfrom(sockfd, buffer, MAXBUF, 0
37


邵阳学院毕业设计(论文)
,(sockaddr*&my_addr, &addrlen;
if (len < 0 { perror("recvfrom"; exit(errno; }

emit w->recvMessage(QObject::trUtf8(buffer,inet_ntoa(my_addr.sin_addr; }
//close connection close(sockfd; }
int main(int argc, char *argv[] {
pthread_t ntid; QApplication a(argc, argv;
MainWindow w; pthread_create(&ntid,NULL,thd_handler,&w; w.show(; return a.exec(; } udp.cpp #include"udp.h" 38

邵阳学院毕业设计(论文)
#include
#include #include #include #include #include #include #include void sendMessage(QString ipAddress,unsigned int port,QString msg,bool isBroad {
// const unsigned int MAXBUF = 1024; int sockfd; int addr_len;
int len; struct sockaddr_in dest; //char buffer[MAXBUF];

char addr[16] ; strcpy(addr,ipAddress.toAscii(;

//create a socket for udp if((sockfd = socket(AF_INET,SOCK_DGRAM,0 < 0 //attention
{ perror("socket creation failure"; exit(errno; }
if(isBroad
39


邵阳学院毕业设计(论文)

{ int broad=1;

setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad; strcpy(addr,"192.168.3.255"; }
//initialize sockaddr_in bzero(&dest,sizeof(dest; dest.sin_family = AF_INET;
dest.sin_port = htons( port; if(inet_aton(addr,(struct in_addr*&dest.sin_addr==0
{ perror("ip address format is error"; exit(errno; }
//send msg to server addr_len = sizeof(dest; // bzero(buffer,MAXBUF;
len = sendto(sockfd, msg.toLocal8Bit(, msg.toLocal8Bit(.length(, 0 ,(sockaddr*&dest, addr_len; if (len < 0
{
printf("\n\rsend error.\n\r";
40


邵阳学院毕业设计(论文)
exit(errno; }
//close connection ::close(sockfd; } llk.cpp #include "llk.h" #include #include"judge.h" llk::llk( { isFirstClick = true; llk::createBtnRerank(;
size=6;llk::createCurrentProgressBar(size;
timer = new QTimer(; currentTime=0;

QObject::connect(timer,SIGNAL(timeout(,this,SLOT(timeProcess(; }

41


邵阳学院毕业设计(论文)

void llk::xxx(int x {

clear(x; // std::cout< // mybutton[x]->setVisible(false; // Widget::arrayInit(6; // progressBar[1]->setValue(20; } void llk::addPic(QString path,int i {
labelPic[i] = new QLabel(this; labelPic[i]->setGeometry(i*100+5,30,100,120; QPixmap pixmap(path; labelPic[i]->setPixmap(path; labelPic[i]->setVisible(false;
progressBar[i] = new QProgressBar(; progressBar[i]->setGeometry(i*100+10,120,100,20; progressBar[i]->setParent(this; progressBar[i]->setValue(10; }
void llk::Create(int size { createTimeProcessBar(size*size; timer->start(1000;

42


邵阳学院毕业设计(论文)

char ss[26][20]={"begin","./icon/icon1.png","./icon/icon2.png","./icon/icon3.png","./icon/icon4.png","./icon/icon5.png", "./icon/icon6.png",

"./icon/icon7.png","./icon/icon8.png","./icon/icon9.png","./icon/icon10.png",

"./icon/icon11.gif","./icon/icon12.gif","./icon/icon13.gif","./icon/icon14.gif",

"./icon/icon15.gif","./icon/icon16.gif","./icon/icon17.gif","./icon/icon18.gif" ,"./icon/icon19.gif","./icon/icon20.gif","./icon/icon21.gif","./icon/icon22.gif","./icon/icon23.gif" ,"./icon/icon24.gif","./icon/icon25.gif"};

createCurrentProgressBar(size;

currentIndex=size*size; progressBarCurrent->setValue(0; for(unsigned int i=0;i
{ mybutton[i] = new MyButton(i,this;

mybutton[i]->setGeometry(20+i%size*60,150+i/size*60,60,60;
43


邵阳学院毕业设计(论文)

int x,y; x=i/size+1;
if((i+1%size
{ y=(i+1%size; } else y=size;
int m=array[x][y]; // std::cout< mybutton[i]->setIcon(QIcon(ss[m]; mybutton[i]->setIconSize(QSize(50,50;

QObject::connect(mybutton[i],SIGNAL(myClicked(int,this,SLOT(xxx(int ; //mybutton[i]->setIcon(QIcon(s; } } void llk::arrayInit(int size { array[size+1][0]=0; array[size+1][size+1]=0; array[0][size+1]=0; array[0][0]=0; for(int i=1;i<=size;i++
{
44


邵阳学院毕业设计(论文)
array[0][i]=0; array[size+1][i]=0; array[i][0]=0; array[i][size+1]=0;
for(int j=1;j<=size;j++
{ array[i][j]=((i-1*size+j-1/4+1;

}
} for(int i=1;i<=size;i++
{ for(int j=1;j<=size;j++
{
int x1,x2,y1,y2,tmp1; // srand(unsigned(time(NULL; x1=rand(%size+1; x2=rand(%size+1; y1=rand(%size+1; y2=rand(%size+1; tmp1=array[x1][y1]; array[x1][y1]=array[x2][y2]; array[x2][y2]=tmp1;

45


邵阳学院毕业设计(论文)

}
} for(int i=0;i<=size+1;i++
{ for(int j=0;j<=size+1;j++
{ std::cout<
} std::cout< }
} void llk::clear(int index { if(isFirstClick
{ firstIndex=index; isFirstClick=false; std::cout< } else {
std::cout< int x1,y1,x2,y2; x1=firstIndex/size+1;
x2=index/size+1;
46

";
邵阳学院毕业设计(论文)

if((firstIndex+1%size
{ y1=(firstIndex+1%size; } else y1=size; if((index+1%size
{ y2=(index+1%size; } else
y2=size; std::cout< std::cout< std::cout<<"**************"<
if(judge(x1,y1,x2,y2,array,size
{ mybutton[firstIndex]->setVisible(false; // free(mybutton[firstIndex]; //mybutton[firstIndex]=NULL; mybutton[index]->setVisible(false; array[x1][y1]=0; array[x2][y2]=0;
currentIndex-=2; progressBarCurrent->setValue(size*size-currentIndex;

47


邵阳学院毕业设计(论文)


} isFirstClick=true; } } void llk::setsize(int size1 { if(size1==8||size1==6||size1==10||size1==4
{ size=size1; } } void llk::mybuttonDelt( { for(int i=0;i
{ free(mybutton[i]; } } void llk::createBtnRerank(
{ btnReRank = new QPushButton(; btnReRank->setParent(this;
btnReRank->setText("reRank";
48


基于Qt的连连看游戏的设计

相关推荐