毕业论文-劳拉方块游戏设计与实现_第1页
毕业论文-劳拉方块游戏设计与实现_第2页
毕业论文-劳拉方块游戏设计与实现_第3页
毕业论文-劳拉方块游戏设计与实现_第4页
毕业论文-劳拉方块游戏设计与实现_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

太原理工大学毕业设计(论文)用纸.绪论1.1课题研究的目的及意义劳拉方块曾经是一款非常热门的小游戏,频频出现在电视机游戏和掌上游戏里。它简单易上手,但是变化无穷,充满了挑战。相信很多我的同龄人还记得小时候坐在小霸王游戏机前,紧握着游戏手柄,盯着屏幕上的游戏,玩到忘记了吃饭。大部分人应该都是在那个时候接触并喜欢上这款游戏的。人们不仅从这款游戏中得到了乐趣,而且从其中收获了成就感。在游戏设计领域,劳拉方块不仅仅是一款充满其妙体验的小游戏,更是一个启蒙。无数人编写游戏程序都是从劳拉方块开始的,因为这既是一个检验RAD开发工具的好方法,也是检验一个人对开发语言、环境和基本数据结构知识熟练程度的便捷途径。本次的设计与实现是在Linux[1]平台上完成的。1.2电子游戏的发展状况游戏最早的雏形,可以追溯到人类原始社会流行的活动:扔石头、投掷带尖的棍子。这些最早的游戏显然是以增强生存技能作为初衷。社会进步后,棋牌类游戏、竞技类游戏甚至电子游戏开始出现。电子游戏是其中的主角之一。劳拉方块在红白机时代曾是电子游戏中的天王之一,我国的用户大部分是通过红白机了解、喜欢上它的,无数人和它一起留在了那个年代。对于普通用户来说,它容易上手,操作简单,且游戏过程中变化无穷,在其多个衍生版本中,更是出现了联机版劳拉方块,使其成为一款竞技游戏,给用户提供了一个展现自己高超水平的场所。劳拉方块随着PC机的更迭不断演变,现在已经成为经典。这款游戏的核心是通过不断变化的方块来训练人的反应能力。随着开发工具的更新换代,现在这款游戏已经成为学习软件设计入门的一个经典案例。本文中实现劳拉方块是利用数组作为方块的数据结构[2],对于初学者可仿照此类方法进行设计,从而了解游戏软件的设计与开发过程。1.2.1电子游戏及其分类电子游戏,也就是运行在家用电脑、家用电子游戏机或是掌中宝游戏机及街机上的电子游戏程序。电子游戏作为一款互动娱乐型软件,结合了剧情、程序、动画、美术、音乐等技术,从电子游戏的分类来看,有着多种分类方式。按照游戏类型,传统的游戏分类将其分为第一人称射击游戏、角色扮演游戏、即时战略类游戏、策略类游戏等。而按照游戏运行平台的不同,又可以将电子游戏分为手机游戏、在线游戏、单机版PC游戏、游戏机游戏、互动电视游戏。现在,虽然未制定标准,但行业内将游戏进行标准分类,分为街机游戏、网络游戏、单机版PC游戏、互动电视游戏四大类。论文中采用此标准。在互联网(局域网)技术出现以前,电子游戏都是以单机版游戏的形式出现的。互联网技术出现后,玩家之间实现了同时在线娱乐,电子游戏的一部分步入网络游戏的阵营。所谓“网络游戏”,是指通过人与人之间的互动达到交流、休闲和娱乐的目的。网络游戏的实现,大大增加了游戏的互动性、真实性,丰富了电子游戏的内涵。现在,随着计算机与网络技术的发展,电子游戏获得了长足的进步,已经成为当今社会不可缺少的精神食粮。1.2.2电子游戏发展现状电子游戏最初诞生于美国,一个还在MIT就读的学生于1971年设计了世界上第一个业务用游戏机[3],游戏的名字叫做《电脑空间》。继第一款游戏问世之后,各类游戏开始纷纷被制作出来娱乐玩家。以欧美市场和日本市场最为成功。目前,世界第一大游戏市场仍是美国,其遵循以发行商为主的产业开发链模式,根据美国市场调查公司NPDGroup调查统计,美国2006年游戏总销售金额(包括家用、掌上型主机及软件)为137亿美元,占了全球游戏市场的43%。日本的游戏市场也是渊源已久。从上世纪六十年代初的街机,到六七十年代的家用游戏机,再到八九十年代的掌上游戏机,经过30多年的发展,如今的日本游戏产业已经成为第一娱乐产业,电玩业已经变成国家的经济支柱之一,每年占到GDP的1/5。韩国则是当今网络游戏产业最发达的国家之一。如今国内市场超过60%的游戏产品都来自韩国的游戏软件开发商。韩国的游戏产业一度得到政府的大力支持。由文化观光部出面组建韩国游戏支援中心[4],向韩国游戏产业提供从资金到技术上的多方面支援;成立游戏投资联盟,政府每年向游戏产业投入的资金多达500亿韩元,并为游戏企业提供长期的低息贷款;设立信息化基金和文化产业基金,为游戏产业服务;对指定的风险企业实行各种税制优惠政策,减少甚至免除游戏企业的税务负担;建设游戏产业基地以扶持中小游戏企业的发展;对从事游戏产业的高科技人才免除两年的兵役。此外,韩国还开设了众多的游戏院校,以大力培养游戏人才,从而为游戏生产提供了基础保障。与电子游戏发达的国家相比,在电子游戏方面,我国还与它们存在较大的差距。目前,我国的游戏市场正处在发展阶段,但在市面上流动的游戏软件主要还是来自于美国、日本、韩国等地,但在一些政策和市场的机遇下,国内的厂家正在蓬勃发展,国产原创游戏即将成为游戏的发展主流。中国的游戏产业经过80年代初期台湾厂商的探索至90年代,开始了自己的研发、发行的历程,直至网络游戏的风行,中国的网络游戏开始有了飞速的发展。1983年,智冠科技有限公司在中国台湾成立,为全球第一家签订授权重制中文版产品代理销售合约的公司,2000年智冠在台湾股票上市,2002年其控股的中华网龙在台湾上市。1996年底,UBISOFT上海分公司暨上海育碧电脑软件有限公司成立。同年,全球游戏软件领军企业EA在中国上海成立办事处。1997年,由尚洋公司制作的《血狮》正式上市。1997年,北京新天地互动多媒体技术有限公司成立,该公司引进了《古墓丽影III》(TombRaiderIII)、《盟军敢死队》等著名欧美游戏,并在1999年在中国率先掀起“游戏软件价格革命”,全面推行50元的价格体系,从此正版游戏价格开始贴近大众消费者。1999年,业内估算中国电脑游戏市场(正版)约1.5亿元人民币。2000年,大陆华彩软件代理发行第一款中文MMORPG《万王之王》正式推出,该游戏于1999年在台湾发行,由台湾雷爵资讯(Lager)开发。也在2000年,继《万王之王》、《石器时代》、《网络三国》在台湾上市之后,游戏桔子推出了《天堂》,游戏桔子成立于1995年,1999年以《便利店》在台湾奠定了地位。《天堂》这款由韩国著名游戏公司Ncsoft研发的网络游戏不但在本国大获成功,也在台湾再次夺冠。2001年初,北京华义在中国大陆地区正式推出了《石器时代》,华义国际股份有限公司于1993年在台北成立,2001年在台湾股票上市。《石器时代》成为大陆当时最流行的网络游戏。2001年,天人互动软件技术有限公司在北京成立。当年与SEGA结成PC游戏业务的战略合作关系,发行了《樱花大战Ⅱ》《文明Ⅲ》《无冬之夜》等经典游戏,2002年,引进在欧美网络游戏《魔剑》(ShadowBane),这是首款在中国测试的欧美网络游戏。2001年5月,“联众世界”经过3年多的迅速成长,以同时在线17万人、注册用户约1800万的规模,成为当时世界用户数量第一的在线游戏网站。2005年1月21日,中央电视台报道:我国网络游戏产业当年增加了50%,今后几年都将以50%以上的速度增长;第一届中国网络游戏年会报道:中国国内网络游戏2004年规模达24.7亿元,2009年规模将达到109.6亿元。1.3研究的主要内容俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。这款游戏最初是由苏联的游戏制作人AlexPajitnov制作的,它看似简单但却变化无穷,令人上瘾。相信大多数用户都还记得为它痴迷得茶不思饭不想的那个俄罗斯方块时代。从游戏的基本玩法出发,主要就是俄罗斯方块的形状和旋转,我在设计中在一个图片框中构造了一些的网状小块,由这些小块组合成新的形状,每四个小块连接在一起就可以构造出一种造型,因此我总共设计了7种造型,每种造型又可以通过旋转而变化出2到4种形状,利用随机函数在一个预览窗体中提前展示形状供用户参考,在游戏窗体中用户就可以使用键盘的方向键来控制方块的运动,然后对每一行进行判断,如果有某行的方块是满的,则消除这行的方块,并且使上面的方块自由下落,最后就可以得出用户的分数。1.4研究的目的和意义那么研究基于Qt的劳拉方块游戏有什么意义呢?虽然目前劳拉方块游戏已经有各种语言的不同版本,并且已经将其搬上了网络的平台,单人、双人单机对战和双人网络对战等各种模式均已被大众熟知。由于开发平台不统一,造成软件的管理和使用极不方便,并且容易受到软硬件环境更新的影响,限制了这些新技术在科研生产中发挥更好的作用.如果舍弃原有软件而重新开发,将会耗费大量的人力和资金,而且浪费了许多成熟的软件成果。而Qt在源代码级上实现了跨平台特性,极大的支持了跨平台通用软件的开发。Qt可以用同一个源程序在不同平台上编译链接,生成目标代码,并取得相同的运行效果,称为“一次编写,随处编译”,利用这种方法充分实现了程序的跨平台运行。这种基于源代码的跨平台特性不仅解决了性能的问题,而且可以发挥各个平台的优势,充分利用每个平台自身的特点;并且即可以在新环境下实现原有软件的功能和特点,减少开发费用,还可以改进原有软件的不足,增加新的需求,从而提高软件的质量,延长软件生命期。因此,利用Linux下基于Qt的应用程序开发是一个非常有意义的课题,具有重要的研究和商业价值。另外,通过本游戏的设计,检验了学习效果和动手能力,进一步深入Qt的学习,提高自己的编程水平,从而达到理论与实践相结合的目的。在成为一个真正的游戏开发者的路上,劳拉方块是一个完美开始。为什么?因为它包括任何一个游戏中所有的元素。并且,不需要艺术家般的才能就能做出非常好看的劳拉方块游戏。任何一个能画出方块的人,每个作图形程序的人,就能做出商业品质的劳拉方块游戏。以劳拉方块开始还有另外一个好处,不仅能做出一个完整的既好玩又容易上瘾游戏,而且它看上来和那些商业版本没什么区别。方块就是方块,不管是谁画出它们的,而且tetraminos(劳拉方块中使用的形状)也不过是一些方块的组合。劳拉方块拥有所有游戏共通的独立成份。它有一个游戏循环(这个过程被反复执行直到游戏退出)。这个游戏循环读取玩家的输入,处理这个输入,然后更新游戏的元素(下落的tetraminos),并且检查是输还是赢。以后要做的所有的简单的游戏都要用到这些东西,所以学习这个过程并且实现它是非常重要的。当第一次完成它之后,以后再做游戏时就能看出那个游戏有多难以及要花多长时间。如果没有完整的完成过这些,哪怕一次,就永远不能完整地正确领会其中的每个元素。当做大的项目时,就更不能确定其复杂性及所要的时间。如果甚至不能正确地领会这整个过程(因为你没能完成它),可能是没能建立一个合适的时间表或估计合适的时间,更有可能的是不够努力。还有,玩劳拉方块可以练习人的反映能力,开始时快速的下降会让人手无足措,但适应了之后就会发现自己的反应力变的很快了。另外长时间的手指活动可以让人血液流通加快有利健康。还有劳拉方块高手都知道要想赢,就要有远大的布局,决不能只局限于一点一点的减,这在无形中就提高了人的智慧。

2.可行性研究2.1设计目的通过本游戏的设计,结合自己在杰普软件所学到的知识,设计开发劳拉方块游戏,能培养自己的动手和思考能力,初步掌握软件工程的系统理论,加强自身对Qt基础编程知识的理解,提高自己编写程序的水平,从而达到理论与实践相结合的目的。2.2软件的定义该游戏软件开发的主要任务是实现游戏的可视化界面操作。开发过程遵循工程开发规范,采用C++来实现界面和事件的控制,用户可以通过菜单栏的相应选项和上下左右四个方向键对游戏进行可视化的操控。游戏的开始、结束、方块变换、积分以及等级等功能都可以通过这些来进行调节。本游戏开发过程中还有很多生疏和疑问,实现的功能也较为简单,旨在能更好地了解C++的编写技巧和规范,为今后的工作积累经验。2.3可行性分析技术可行性:C++语言中集成了很多标准类库,可以直接调用,Qt中大量的图形界面库和优良的封装和跨平台机制,使得实现界面的可视化以及事件的操控简单了很多。经济可行性:本游戏的开发旨在提升自己的语言逻辑水平,完成毕业设计,考虑到的其他因素并不多,外界阻力很小,对经济要求不高。社会可行性:本游戏设计完成后仅作毕业设计和私人使用,且设计内容健康,不会违反法律,不会对社会造成不良影响。2.4结论意见综上所述,本游戏软件的技术成熟、完备。各方面均无重大问题,因此本游戏软件可开始着手编写。3.需求分析3.1引言对软件需求完全理解对于软件开发工作的成功是至关重要的,需求说明的任务是发现、规范的过程,有益于提高软件开发过程中的能见度,便于对软件开发过程中的控制与管理,便于采用工程方法开发软件,提高软件的质量,便于开发人员、维护人员、管理人员之间的交流、协作,并作为工作成果的原始依据,并且在向潜在用户传递软件功能、性能需求,使其能够判断该软件是否与自己的需求相关。3.2游戏需求28种状态的方块随机产生,自由下落,落下时可由玩家用上、下、左、右控制键控制翻转和移动,以便以玩家所需要的形态和位置落下。如果落下时,方块的方格能填满某一行,则这一行可消去。消去一行后,游戏可给玩家加分,若由存在空格的方块填满整个窗口,则游戏失败。游戏功能需求如下:游戏界面需求:设计良好的游戏界面可以让玩家充分感受到游戏带来的娱乐性,在设计好的一定的区域内运动和变形,不同的色块让其拥有不同的颜色,这样看起来会有一定的美感。游戏形状需求:用数组作为存储方块8种状态的数据结构,即长条形、Z字形、反Z形、田字形、7字形、反7形、T字型,各个方块要能实现它的变形,可设为顺时针或逆时针变形。键盘处理事件需求:方块下落时,可通过键盘方向键(上、下、左、右键)对该方块进行顺时针变形、逆时针变形、向左、向右移动,D键可以使方块加速下落,SPACE键可以使方块瞬间落下。鼠标处理事件需求:通过点击菜单栏中相应的菜单项,可以实现游戏的开始、结束,方块形状的变换,分数、等级的显示,以及游戏帮助等功能。显示需求:当不同的方块填满一行时可以消行,剩余方块向下移动并统计分数。当达到一定分数的时候,会增加相应的等级。3.3开发环境介于开发工具和软件使用的环境,我选择了如下的开发环境:操作系统:MicrosoftWindows7Ultimate(32位)内存:3G硬盘:500GCPU:Intel(R)CORE(TM)I5CPUM480交互工具:键盘/鼠标显示器:通用显示器开发工具:Qt5.33.4接口控制本游戏通过键盘进行操作,在Linux操作系统下,利用键盘的上、下、左、右、D以及SPACE键对方块进行移动变形,要使用键盘的接口事件。3.5方案论证学校现已开设的课程有C语言、C++、java,我自学了Qt,加上自己浏览了一些其它相关的资料,通过网上以及图书馆的资料,知道可以通过C,C++和Qt,VB,Delphi,Java实现劳拉方块游戏的设计。下面简单介绍下VB、Java、Qt各自的优缺点:3.5.1VB的特点全称VisualBasic,它是以Basic语言作为其基本语言的一种可视化编程工具。在中国乃至全世界都能看到它的身影,它曾是在中国最为流行的编程工具,到现在还占据着非常重要的地位,对于它的好坏大家都有一定的了解,VB作为一种较早出现的开发程序以其容易学习,开发效率较高,具有完善的帮助系统等优点曾影响了好几代编程人员,但是由于VB不具备跨平台这个特性,从而也决定了VB在未来的软件开发中将会逐渐地退出其历史舞台;它对组件技术的支持是基于COM和ActiveX,对于组件技术不断完善发展的今天,它也显出了它的落后性;同时VB在进行系统底层开发的时候也是相对复杂的,调用API函数需声明,调用不方便,不能进行DDK编程,不可能深入Ring0编程,不能嵌套汇编;而且面向对象的特性差;网络功能和数据库功能也没有非常突出的表现,综上所述,VB作为一种可视化的开发工具由于其本身的局限性,导致了它在未来软件开发中逐步被其他工具所代替。3.5.2Java的特点(1)安全性Java是一种安全的网络编程语言,不支持指针类型,一切对内存的访问都必须通过对象的实例来实现。这样能够防止他人使用欺骗手段访问对象的私有成员,也能够避免在指针操作中易产生的错误。此外,Java的安全性体现在多个层次上:在编译层,有语法检查;在解释层,有字节码校验器,可进行代码段格式测试和规则检查、访问权限和类型转换合法性检查、操作数堆栈的上溢和下溢检测、代码参数类型合法性检查等;在平台层上,通过配置策略,可设定访问资源域,无须区分本地或远程。(2)可移植性Java具备有很好的移植性,这主要得益于它与平台无关的特性。同时,Java的类库中也实现了与平台无关的接口,这使得这些类库也能移植。同时,Java编译器主要是由Java本身来实现的,Java的运行系统(解释器)由标准C语言实现,因而整个Java系统都具有可移植性。(3)多线程机制Java具有多线程机制,这使得应用程序能够并行地执行。它的同步机制也保证了对共享数据的共享操作,而且线程具有优先级的机制,有助于分别使用不同线程完成特定行为,也提高了交互的实时响应能力。Java的多线程技术使网上实时交互实现很容易,从而为解决网上大数量的客户访问提供了技术基础。(4)跨平台通常,在Windows下编写的程序是不能直接拿到UNIX上运行的,因为程序的执行最终必须转换成为计算机硬件的机器指令来执行,专门为某种计算机硬件和操作系统编写的程序是不能够直接放到其他类型的计算机硬件上执行的,至少要做移植工作。要想让程序能够在不同的计算机上运行,就要求程序设计语言能够跨越各种软件和硬件平台,而Java恰恰满足了这一需求。Java编译器能够产生一种与计算机体系结构无关的字节指令,只要安装了Java虚拟机,Java就可以在相应的处理机上执行。3.5.3Qt的特点Qt拥有一个单一的Library,让你开发各种不同平台的程序,目前支持Windows、Linux、Mac、UNIX、EmbeddedLinux,讲白话点,就是它提供了一个Library让你开发GUI程序,写好之后,只要在各平台重新Compile后,就可以在各平台执行,而且使用完整的ANSIC++语言,且不限Compiler,只要是C++的Compiler都可以,重要的是,该Library相当漂亮,写出来的程序很像C++Builder或.NETFramework的那样精简,不会向MFC那样复杂。目前Qt已经到第四个版本,GUI部分算支持的相当完整,且支持数据库、XML、Multi-Thread、Socket等方面的programming。若以后台角度来说,无论后端是什么数据库,只要透过相同的Interface,不同数据库的Class来实做这个Interface,前端GUI的程序写法完全不用改变,同理,面对不同的OS,理论上只要透过相同的Interface,不同OS的Class各自实做这个Interface,前端GUI的程序也完全不用改变,最后只要靠Compiler将程序compile成各平台的原生程序即可,这样即可保证其执行速度,不用再靠VirtualMachine。但很可惜这个理想,这么多年来都没人可以做出来。Qt无疑是GUI终极解决方案,有强力的ANSIC/C++语言背书,又有单一的GUILibrary,且精简漂亮,又能Compile成各平台的原生执行档,几乎是最完美的解决方案了。3.5.4方案的选择经过以上比较好,考虑到Qt的众多良好特性,尤其是其跨平台性,决定使用Qt开发俄罗斯方块游戏。3.6Qt简介Qt是一个1991年由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(MetaObjectCompiler,moc))以及一些宏,易于扩展,允许组件编程。2008年,奇趣科技被诺基亚公司收购,QT也因此成为诺基亚旗下的编程语言工具。2012年,Qt被Digia收购。但是真正使得Qt在自由软件界的众多Widgets(如Lesstif,Gtk,EZWGL,Xforms,fltk等等)中脱颖而出的还是基于Qt的重量级软件KDE。有趣的是,KDE也是使得Trolltech公司承受巨大压力的一个原因。下面我们将来看看这场著名的自由软件圣战--"KDE/QT.VS.Gnome/Gtk"是怎么发生的。在Unix的图形界面一向是以MIT[5]的XWindow系统为标准,可是在商业应用上有两大流派,一派是以Sun公司领导的Openlook阵营,一派IBM/HP领导的OSF(OpenSoftwareFoundation)的Motif,双方经过多年竞争之后,Motif最终胜出,成为最普遍使用的界面库,后来双方又妥协出一个CDE(CommonDesktopEnviroment)作为一个标准的图形界面。但是Motif/CDER的价格非常昂贵,在这同时微软的Windows图形界面发展速度非常快,而Unix界的后起之秀Linux也急需一个可靠并且免费的图形界面。1996年10月,由开发图形排版工具Lyx的德国人MatthiasEttrich发起了KDE计划。KDE的全称为KDesktopEnvironment,可以看出是针对CDE。KDE本身是采用GPL宣言的,但是KDE却是使用Qt来作为其底层库,因为当时Qt已经将其Unix版本自由发布了,但是Qt并不遵循GPL,因此KDE被很多自由软件的作者攻击,认为利用非自由软件开发违背了GPL的精神,于是GNU的狂热信徒兵分两路,一路是去制作Harmonny,试图重写一套兼容于Qt的替代品,另一路是由一个26岁的墨西哥程序员MiguelDeIcaza领导下重新开发一套叫GNOME(GNUNetworkObjectEnviroment)来替代KDE。由于Linux界的老大RedHat不喜欢KDE/Qt的版权,因此RedHat甚至专门派出了几个全职程序员来加入GNOME进行开发工作,于是一场同MotifVSOpenlook相似的圣战就这么打起来了。Trolltech为了KDE曾数次修改Qt的版权,从成立KDEFreeQt基金会到采用QPL,可谓是费尽心机,但是GNOME采用的GTK一开始就是完全的GPL,因此在这个方面GNOME有一定的优势,加上Qt/KDE采用C++开发,入门的门槛比较高,而GTK/Gnome采用C,因此GNOME吸引了更多的自由软件开发者,但是KDE毕竟先走了一步,推出的KDE1.1.2十分稳定,而当时急忙中推出的GNOME1.0的系统稳定性奇差,有人甚至笑称GNOME1.0还没有KDE1.0Alpha稳定。但是GNOME后来发展比较快,大有迎头赶上的势头。当时双方的开发者在网络上炒得天翻地覆,连Linux之父Linus只是说了一句喜欢用KDE都倍受指责。战争到了第三个年头,也就是2000年,可谓是风云突变,一个接一个重大的事件先后发生:首先是一批从Apple公司出来的工程师成立了一个叫Eazel的公司替GNOME设计界面,然后是一批GNOME程序员成立了一个HelixCode公司替GNOME提供商业支持,而大家期待以久的KDE2.0也终于发布了,这恐怕是目前最为庞大的自由软件了之一,除了KDE本身,还包括Koffice套件,和集成开发环境Kdevelop等等大批软件,其主力软件Kounqueror也是第一个可以同微软的InternetExploer相抗衡的浏览器。而Sun公司,RedHat公司,Eazel公司,HelixCode等一批公司成立了一个GNOME基金会,Sun还宣布将把重量级办公软件Staroffice同GNOME集成,Trolltech公司自然不能坐以待毙,于今年10月4日将Qt的freeedition变为GPL宣言,彻底解决了KDE的版权问题,又推出了嵌入式Qt,给了GNOME阵营一个有力的回击。到现在为止,这场战争还在继续,相信我们不能很快看到结果。一般说来,目前GNOME吸引的公司比较多,但是KDE/Qt的开发的效率和质量比GNOME高,而且在Office/嵌入式环境中先走一步,在一定时间内还将处于优势地位。那么对于用户来说,如何在Qt/GTK中作出选择呢?一般来说,如果用户使用C++,对库的稳定性,健壮性要求比较高,并且希望跨平台开发的话,那么使用Qt是较好的选择,但是值得注意的是,虽然Qt的FreeEdition采用了GPL宣言,但是如果你开发Windows上的Qt软件或者是Unix上的商业软件,还是需要向Trolltech公司支付版权费用的。QtCreator是一个用于Qt开发跨平台集成开发环境(IDE),QtCreator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境(IDE),并确保首次接触Qt框架的开发人员能迅速上手和操作。并且它包含了一套用于创建和测试基于Qt应用程序的高效工具,包括:一个高级的C++代码编辑器、上下文感知帮助系统、可视化调试器、源代码管理、项目和构建管理工具。QtCreator2.3.1和Qt4.7共同构成的QtSDK,包含了开发跨平台应用程序所需的全部功能。Qt支持windows平台、linux/unix平台、macintosh平台、Embedded平台等,所以Qt所开发的应用具有良好地可移植性。Qt官网()上有完整的SDK下载,下载开发平台的SDK,下载完成后点击即可安装。安装完成后,运行Qt。3.7Qt的类库Qt类库大致可以分为三个部分:控件,框架和工具。(1)控件控件部分包括环境控件,主窗口控件,标准对话框,基本的GUI控件,扩展GUI控件,GUI组织控件,以及帮助系统控件。环境控件为应用程序提供全局服务的类,包括系统设定、国际化等。例如QTranslator,Qapplication。主窗口类为应用程序提供界面框架,可以在上面添加菜单、工具条等,为应用程序提供集装箱的功能,如QMainWindow。标准对话框类是为打开/关闭文件,选择颜色等预先设计的标准对话框,如QColorDialog,QFileDialog。基本控件包括所有的GUI控件,如按钮、组合框等,如QPushButton。扩展的控件包括树状视图、进度条等,如QListView。GUI组织类负责对各种控件进行组织以构成复杂的对话框,如QGroupBox。帮助系统控件是为应用程序提供在线帮助的类,QStatusBar,QToolTip。(2)框架框架部分包括的是一些抽象的类,通常不可见,如对象模型、抽象控件、绘图、拖放、控件外观。对象模型是框架的基础,如QObject。可见的控件一般从抽象控件派生,如QButton。绘图类控制绘图,如QBrush。拖放类控制拖放操作,如QDragObject。控件外观类控制控件的外观如颜色、字体等。例如QColor。(3)工具工具部分包括时间日期和链表树等数据结构,它们和GUI无关。普通工具包括链表、堆栈、队列、树等常见数据结构,如QArray。图形处理工具控制图像的编码/解码算法。如QImageIO。I/O控制工具处理I/O的一些类,如QFile。时间和日期工具类处理时间和日期,如Qdate,QTime。另外还有其他杂类如Qsignal,QIconSet等。3.8Qt相比其他图形界面库的优点(1)优良的跨平台特性。Qt支持下列操作系统:MicrosoftWindows95/98、MicrosoftWindowsNT、Linux、Solaris、SunOS、HP-UX、DigitalUNIX(OSF/1、Tru64)、Irix、FreeBSD、BSD/OS、SCO、AIX、OS390和QNX等。(2)面向对象。Qt的良好封装机制使得Qt的模块化程度非常高,可重用性较好,对于用户开发来说是非常方便的。Qt提供了一种称为signals/slots的安全类型来替代callback,这使得各个元件之间的协同工作变得十分简单。(3)丰富的API。Qt包括多达250个以上的C++类,还提供基于模板的collections、serialization、file、I/Odevice、directorymanagement和date/time类。甚至还包括正则表达式的处理功能。(4)支持2D/3D图形渲染,支持OpenGL。(5)大量的开发文档。(6)XML支持。3.9Qt对象间通讯机制对象间通讯是面向对象程序设计的一个极其重要的内容,类似于MicrosoftMFC的消息映射和事件循环,Qt的对象间通讯采用的是信号—槽(signal—slot)机制,信号就好像是事件,而槽则是响应事件的方法。如果需要实现对象间的通讯,只需要把一个对象的信号和另外一个对象的槽使用连接(connect)起来[6]。信号—槽机制说明:Qt下对象间的通讯用信号—槽机制来实现。信号—槽机制是Qt的一个中心特征并且也是它与其它图形工具包的最不相同的部分。图3-1直观地表示了这种机制是如何工作的。图3-1信号与槽的连接原理图在图形用户界面编程中,经常希望一个窗口部件的一个变化被通知给另一个窗口部件。更一般地,希望任何一类对象可以和其它对象进行通讯。例如,如果正在解析一个XML文件,当遇到一个新的标签时,也许要通知列表视图正在用来表达XML文件的结构。较老的工具包是使用一种被称作回调的通讯方式来实现同一目的。回调是指一个函数的指针,所以如果希望一个处理函数通知一些事件,可以把另一个函数(回调)的指针传递给处理函数,处理函数在适当的时候调用回调函数。回调有两个主要缺点:首先他们不是类型安全的,从来都不能确定处理函数使用了正确的参数来调用回调;其次回调和处理函数是非常强有力地联系在一起的,因为处理函数必须知道要调用哪个回调。在Qt中有一种可以替代回调的技术:使用信号和槽。当一个特定事件发生的时候,一个信号被发射。Qt的窗口部件有很多预定义的信号,但是总是可以通过继承来加入自己定义的信号。槽就是一个可以被调用处理特定信号的函数。Qt的窗口部件有很多预定义的槽,通常也可以加入自己的槽,这样就可以处理感兴趣的信号了。信号—槽机制是类型安全的:一个信号的签名必须与它的接收槽的签名相匹配。实际上一个槽的签名可以比它接收的信号的签名少,因为它可以忽略额外的签名。因为签名是一致的,编译器就可以帮助检测类型是否匹配。信号和槽是宽松地联系在一起的:一个发射信号的类不用知道哪个槽要接收这个信号。Qt的信号和槽的机制可以保证如果把一个信号和一个槽连接起来,槽会在正确的时间使用信号的参数而被调用。信号和槽可以使用任何数量、任何类型的参数。它们是完全类型安全的,不会再有回调核心转储。从QObject类或者它的一个子类(比如QWidget类)继承的所有类都可以包含信号槽。当对象的状态发生改变的时候,信号被发送给其它对象,从而实现了该对象与其它对象的通信。对象在发射信号时,无须知道有没有槽接收它所发射的信号,而槽是正常的成员函数,一个槽不知道它是否被任何信号连接,这就是信息封装,这种封装确保了对象可以用作一个软件组件。此外,使用对象时也无须知道这种通讯机制的实现细节。在信号—槽机制实现的过程中,可以把许多信号和单一槽相连,也可以把一个信号和许多槽相连。把一个信号和另一个信号直接相连也是可以的。(这时,只要第一个信号被发射时,第二个信号立刻就被发射)。总体来看,信号和槽构成了一个强有力的组件编程机制。

4.游戏的详细设计4.1劳拉方块游戏功能图在项目设计中,项目的详细设计环节必不可少。一些可能存在的问题在详细设计的过程中将会得到纠正。4.1.1游戏运行流程图游戏开始后,方块下落,期间我们可以通过方向键来调整方块的下落姿态,当落下的方块占满窗口后,游戏将会结束。图4-1详细地描述了此过程。劳拉方块游戏开始劳拉方块游戏开始通过方向键来调整方块下落姿态通过方向键来调整方块下落姿态调整过后的劳拉方块落下调整过后的劳拉方块落下方块占满窗口是否游戏结束YESYESNO退出游戏退出游戏图4-1游戏运行流程图

4.1.2方块下落得分图NONOYESLEVEL增加LINESREMOVED增加YESYES是否消除行数n是否更改方块姿态SCORE增加是否暂停方块落下方块下落NONOYESLEVEL增加LINESREMOVED增加YESYES是否消除行数n是否更改方块姿态SCORE增加是否暂停方块落下方块下落 图4-2方块下落得分流程4.1.3游戏系统流程结构设计劳拉方块游戏中,我们将事先设计好的产生方块的模块称作图形工场,而和玩家交互的部分简单地归纳为处理按键事件和处理逻辑部分,而游戏面板部分负责显示。这三部分通过不用的方式进行交互。图4-3和图4-4详细地描述了此过程。图4-3游戏系统流程结构设计图图4-4系统数据流图4.2图形实体类TetrixPiece实现4.2.1图形的产生定义一个枚举类型,表示方块的七种形状,通过图形实体类TetrixPieced文件中的setRandomShape()方法随机产生一个初值,用于产生图形的某种状态,如图3和图4中图例所示:随机产生一个数随机产生一个数随机数Z字形S字形直线型T字形正方形L字形反L型4-5图形的随机产生每个形状由4个小方块组成,这里每行的四个坐标即4个小方块的坐标,其中横向为X,纵向为Y,上图分别为Z字形、S字形、直线型、T字形、正方形、L字形和反L字形,各个图形的坐标依次如下:图4-6色块的存储数组4.2.2图形的旋转图形的旋转是通过绘制4个方向的方块,在不同旋转角度显示不同方向的方块来实现的。定义一个函数rotatedLeft()const,当每次响应键盘向上的方向键时,方块旋转90度,同时画布刷新一次,这样,方块的变形就实现了。4.3游戏内容的实现4.3.1关于存储劳拉方块的关键部分,一定程度上是基于对存储结构的理解。游戏中,每一块落下的方块都由四个小色块组成,这四个小色块存储在一个数组的四个元素中[6]。我们在TetrixPiece类下setShape(TetrixShapeshape)函数中创建这个数组,即staticconstintcoordsTable[8][4][2],该三维数组中,第一维表示类型,第二维表示x坐标,最后一维表示y坐标,这样我们就能用坐标的方式描述出劳拉方块中的七种不同形状的方块。然后通过下文中的函数调用这个数组中的方块。4.3.2关于七种色块的调用要在前一块色块已经完成落下的情况下,怎样随机生成不同的色块,这也是游戏设计中的一个重要部分。这时,我们需要在框架类board中添加一个计时器事件[7],这是下一步的关键。计算机此时通过setRandomShape()来产生不同类型的七种方块,而在timerEvent()中规定了一些功能,比如WaitingAfterLine()来有效的控制方块的产生时机。并且用Timer控件,每隔一段时间方块的y坐标+1,并检测下是否有可以消除的方块然后根据计算机时钟控制色块在一定的时间不停的产生。4.3.3关于色块的变形色块变形,这是劳拉方块游戏的一个玩点。这个在游戏设计之初很难被实现。因为思路和语法问题,修正中也遇到不少问题,出现如下图的情况:图4-7变形模块修正过程中曾经出现的问题首先,这个功能是通过对色块数组坐标的修正来实现的,当我们按下←键时,通过event->key()接受到信号并对色块的X坐标进行-1操作,Y值不变。→键同样的原理,Y不变,X+1操作。向上和向下键通过rotatedLeft()和rotatedRight()分别实现色块的向左和向右旋转。D键通过oneLineDown()实现了方块的加速下落,空格键则通过dropDown()实现方块的瞬间落下,同时,也加入了误操规避,通过QFrame::keyPressEvent(event)[8]进行归纳,不进行任何操作。当然,在方块变形的过程中,为了防止在游戏框边界[9]变形引起错误,加入了变形范围。4.3.4关于方块下落功能:判断图形能否向下移动,显示下移后的界面,或者游戏结束。实现:先向下移动一步,此时并不在界面上显示下移后的界面,判断是否到底,若到底则消行记录分数、出现下一个图形;判断是否是否一开始就与其它图形重合,若是则游戏结束;经过以上判断,此时方可显示一下一步后的界面,并进入下一次计时。4.3.5关于满行及消行判断功能:判断是否有已满行,然后把该行消去。实现:游戏在方块下移到底后,利用循环判断有几行已满,并对已满行进行清零和进行加分操作,同时更新窗口,从而实现消行的效果。4.3.6关于绘制游戏区域及方块通过调用QPainter的drawLine的方法绘制游戏网格,调用QPainter和drawRect绘制方块背景和边框。4.3.7关于键盘事件响应劳拉方块是通过上下左右移动来控制游戏的运行,那么是具体如何实现的呢?这就需要用到键盘的按下事件,通过响应键盘的按下事件来实现。本游戏设计的是用上下左右方向键键来控制游戏的操作,其中左右方向键控制方块向左向右移,向上和向下键控制方块的形状,SPACE键则方块直接下坠,D键方块加速下落。键盘响应事件功能图如图6所示:判断按键判断按键判断可否变形,图形变化调用函数判断可否移动。可以则移动判断可否移动。可以则移动判断可否移动。可以则默认下移一步,否则下到底如不是这4个按键,则接收其他按键。图4-8键盘事件功能图具体代码实现:通过重新实现虚函数QWidget::keyPressEvent来响应相应的键盘按键事件。4.4游戏主窗体的实现游戏主窗体是整个游戏的显示部分,主要用于放置绘制好的游戏区域,显示游戏玩家的得分情况、关卡和其它基本信息。游戏区域的宽分成10等分,高分成22等分,也就是说每行有10小矩形,总共有22行(BoardWidth=10,BoardHeight=22)。左边是LCD的显示部分,LCD的显示最大为五位数。分为得分(scoreLcd)、等级(levelLcd)、消行(linesLcd)。另外,主窗体还设计了游戏的暂停按钮,方便游戏者的操作。游戏的设计在Qt中整个工程下完成。

5.游戏主要功能选项的实现与检验5.1主要功能的验证(1)计分功能(SCORE)该部分是用来统计游戏玩家的得分:自由下落增加1分score+=dropHeight+1;每消去n行,多增加10nscore+=10*numFullLines;(2)暂停功能(PAUSE)通过PAUSE键来控制游戏的暂停。quitButton->setFocusPolicy(Qt::NoFocus);pauseButton=newQPushButton(tr("&Pause"));//暂停按钮(3)消行数功能(LINESREMOVED)当方块落下的时候,刚好将一行或n行填满,则消去n行if(numFullLines>0){numLinesRemoved+=numFullLines;/*LCD数字显示[11]消除行数等于满行数*/(4)游戏等级功能(LEVEL)该类功能是用于统计游戏者所能达到的等级数/*声明信号*/signals:voidscoreChanged(intscore);//得分该表触发该信号voidlevelChanged(intlevel);//级别改变触发该信号if(numPiecesDropped%5==0){++level;//每当分数达到了5的某个倍数时,level增加1(5)游戏退出功能(QUIT)当按下QUIT键时,游戏可视化窗口[12]关闭,退出劳拉方块游戏startButton->setFocusPolicy(Qt::NoFocus);quitButton=newQPushButton(tr("&Quit"));//退出按钮5.2游戏快捷键简简介(1)方向键(4个方向键)switch(event->key()){//左键按下,X左移,Y不变caseQt::Key_Left:tryMove(curPiece,curX-1,curY); break;caseQt::Key_Right://右键按下,X右移,Y不变tryMove(curPiece,curX+1,curY); break;caseQt::Key_Down://向下键按下,X,Y交换tryMove(curPiece.rotatedRight(),curX,curY); break;caseQt::Key_Up://向上键按下,X,Y交换tryMove(curPiece.rotatedLeft(),curX,curY); break;(2)加速下落键(D) caseQt::Key_D://按下D,加速下落 oneLineDown(); break;(3)立即落下键(空格键) caseQt::Key_Space://按下空格键,方块直接落下 dropDown(); break;5.3调试程序打开QT,如图5-1:图5-1QT主界面点击“openproject”选项,在“打开文件”窗口中选择想要打开的文件,如图5-2:图5-2打开已存在的项目打开文件后,点击“Debug”按钮,对项目进行编译,如图5-3:图5-3游戏编译成功5.4加载成功,观察效果游戏编译成功,点击绿色箭头按钮,程序将被编译运行,运行结果如图5-4和5-5所示:图5-4游戏开始界面图5-5游戏运行界面点击面板上的“Pause”后,游戏将进入暂停状态,如图5-6所示:图5-6游戏暂停界面游戏运行一段时间后,游戏的等级和分数均获得了提升,能够正常运行,如图5-7:图5-7游戏运行一段时间后的截图5.5代码详解5.5.1main.cpp该部分为程序的主入口,即main函数,从代码中可以看出,程序的运行流程为先定义图形用户界面类,调用库函数和创建头文件,自定TetrixWindow类的对象并以时间为随机参数变量改变方块下落形状,让窗口在后台循环运行,达到显示窗口的目的#include<QtGui>//定义图形用户界面类#include<stdlib.h>//调用库函数#include"tetrixwindow.h"//调用创建的头文件intmain(intargc,char*argv[])//c++程序入口,(argc是命令行参数的数目,*argv[]是指向参数的各个指针所构成的数组){QApplicationapp(argc,argv);//,Qt程序入口TetrixWindowwindow;//自定TetrixWindow类的对象,其实就是QWidget类的子类window.show();//显示qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//以时间为随机参数变量改变方块下落形状returnapp.exec();//让窗口在后台循环运行,达到显示窗口的目的} 5.5.2tetrixboard.cpp该部分为代码的“黑盒”部分,所有关乎程序的逻辑处理部分全部集合在其中,如游戏的行消除、计分、等级等功能,都是在这个文件中进行定义的。值得一说的是,该部分还用到了QT中的一些自带的框架风格及其相应的设置功能,这些功能使得游戏实现的过程变得容易。#include<QtGui>//定义图形用户界面类#include"tetrixboard.h"TetrixBoard::TetrixBoard(QWidget*parent):QFrame(parent){/*设置框架风格为Panel|Sunken,API有图可参照*/setFrameStyle(QFrame::Panel|QFrame::Sunken);setFocusPolicy(Qt::StrongFocus);/*设置框架焦点策略*/isStarted=false;/*初始化开始和暂停均为false*/isPaused=false;clearBoard();/*清空界面*/nextPiece.setRandomShape();/*指名下一个图形随机生成*/}/*设置nextPieceLabel的值为输入值*/voidTetrixBoard::setNextPieceLabel(QLabel*label){nextPieceLabel=label;}QSizeTetrixBoard::sizeHint()const/*显示尺寸*/{returnQSize(BoardWidth*15+frameWidth()*2,BoardHeight*15+frameWidth()*2);}QSizeTetrixBoard::minimumSizeHint()const{returnQSize(BoardWidth*5+frameWidth()*2,BoardHeight*5+frameWidth()*2);}voidTetrixBoard::start(){if(isPaused)return;isStarted=true;isWaitingAfterLine=false;numLinesRemoved=0;numPiecesDropped=0;score=0;level=1;clearBoard();//清屏/*emit关键字表示发送信号*/emitlinesRemovedChanged(numLinesRemoved);emitscoreChanged(score);emitlevelChanged(level);newPiece();/*开始计时器,该框架类会接受到一个计时器事件*/timer.start(timeoutTime(),this);}/*暂停*/voidTetrixBoard::pause(){/*没有开始,即返回*/if(!isStarted)return;isPaused=!isPaused;/*暂停则停止计时*/if(isPaused){timer.stop();}else{/*没有停止,且是正在进行,则计时*/timer.start(timeoutTime(),this);}/*更新控件显示*/update();}voidTetrixBoard::paintEvent(QPaintEvent*event){QFrame::paintEvent(event);/*在这个框架上画图*/QPainterpainter(this);QRectrect=contentsRect();/*在rect中间显示文本信息*/if(isPaused){painter.drawText(rect,Qt::AlignCenter,tr("Pause"));return;}intboardTop=rect.bottom()-BoardHeight*squareHeight();for(inti=0;i<BoardHeight;++i){for(intj=0;j<BoardWidth;++j){TetrixShapeshape=shapeAt(j,BoardHeight-i-1);if(shape!=NoShape)drawSquare(painter,rect.left()+j*squareWidth(),boardTop+i*squareHeight(),shape);}}if(curPiece.shape()!=NoShape){for(inti=0;i<4;++i){intx=curX+curPiece.x(i);inty=curY-curPiece.y(i);drawSquare(painter,rect.left()+x*squareWidth(),boardTop+(BoardHeight-y-1)*squareHeight(),curPiece.shape());}}}voidTetrixBoard::keyPressEvent(QKeyEvent*event){if(!isStarted||isPaused||curPiece.shape()==NoShape){QFrame::keyPressEvent(event);return;}switch(event->key()){//左键按下,X左移,Y不变caseQt::Key_Left:tryMove(curPiece,curX-1,curY); break;caseQt::Key_Right://右键按下,X右移,Y不变tryMove(curPiece,curX+1,curY); break;caseQt::Key_Down://向下键按下,X,Y交换tryMove(curPiece.rotatedRight(),curX,curY); break;caseQt::Key_Up://向上键按下,X,Y交换tryMove(curPiece.rotatedLeft(),curX,curY); break;caseQt::Key_Space://按下空格键,方块直接落下 dropDown(); break;caseQt::Key_D://按下D,加速下落 oneLineDown(); break;default://按错其他键,不执行错误操作QFrame::keyPressEvent(event);}}以上的部分,完整地定义了游戏中的键盘事件处理机制以及游戏随机生成方块的产生原理,通过以上代码的处理及相应,才能对键盘发出的信号做出相应的反应。接下来的部分是色块的生成部分,以时间作为随机变量,随机产生方块,每当分数达到了5的某个倍数时,level增加1。voidTetrixBoard::timerEvent(QTimerEvent*event)//以时间作为随机变量{if(event->timerId()==timer.timerId()){if(isWaitingAfterLine){isWaitingAfterLine=false; newPiece(); timer.start(timeoutTime(),this);}else{neLineDown();}}else{QFrame::timerEvent(event);}}voidTetrixBoard::clearBoard()//{for(inti=0;i<BoardHeight*BoardWidth;++i)board[i]=NoShape;}voidTetrixBoard::dropDown()//方块下落{intdropHeight=0;intnewY=curY;while(newY>0){if(!tryMove(curPiece,curX,newY-1))break;--newY;++dropHeight;}pieceDropped(dropHeight);}voidTetrixBoard::oneLineDown()//{if(!tryMove(curPiece,curX,curY-1))pieceDropped(0);}voidTetrixBoard::pieceDropped(intdropHeight)//游戏级数、分数{for(inti=0;i<4;++i){intx=curX+curPiece.x(i);inty=curY-curPiece.y(i);shapeAt(x,y)=curPiece.shape();}++numPiecesDropped;if(numPiecesDropped%5==0){++level;//每当分数达到了5的某个倍数时,level增加1timer.start(timeoutTime(),this);emitlevelChanged(level);}score+=dropHeight+1;emitscoreChanged(score);removeFullLines();if(!isWaitingAfterLine)newPiece();}下面的部分是关于游戏界面中LEVEL的设定。得分的机制也做了设定。LCD数字显示消除行数等于满行数,消除一行增加10分。voidTetrixBoard::removeFullLines(){intnumFullLines=0;for(inti=BoardHeight-1;i>=0;--i){boollineIsFull=true;/*假设刚开始就满行*//*每行都没有障碍物*/for(intj=0;j<BoardWidth;++j){if(shapeAt(j,i)==NoShape){/*则设置满行标志false*/lineIsFull=false;break;}}if(lineIsFull){/*LCD数字自加*/++numFullLines;/*j:横坐标k:纵坐标*/for(intk=i;k<BoardHeight-1;++k){for(intj=0;j<BoardWidth;++j)/*用上一行的图形填充满行的位置*/shapeAt(j,k)=shapeAt(j,k+1); }/*将顶行设置为空白行*/for(intj=0;j<BoardWidth;++j)shapeAt(j,BoardHeight-1)=NoShape;}}if(numFullLines>0){/*LCD数字显示消除行数等于满行数*/numLinesRemoved+=numFullLines;/*消除一行增加十分*/score+=10*numFullLines;/*发分数和消行信号*/emitlinesRemovedChanged(numLinesRemoved);emitscoreChanged(score);/*每500ms框架会接收到一个定时器事件*/timer.start(500,this);isWaitingAfterLine=true;/*设置当当前的方块为空白*/curPiece.setShape(NoShape);/*更新控件显示*/update();}}/*生成新方块*/voidTetrixBoard::newPiece(){/*将当前显示的方块设置为即将显示的方块*/curPiece=nextPiece;/*设置下一个方块随机产生*/nextPiece.setRandomShape();/*显示方块*/showNextPiece();/*设置当前的横坐标为框架的中心*/curX=BoardWidth/2+1;/*设置curY为框架顶点+方块最小高度*/curY=BoardHeight-1+curPiece.minY();if(!tryMove(curPiece,curX,curY)){curPiece.setShape(NoShape);timer.stop();isStarted=false;}}下面的部分是上色部分,色块的颜色就是由这些决定的。在一个数组中定义了若干颜色,通过设置画笔,然后使用定制颜色来画图。voidTetrixBoard::showNextPiece(){if(!nextPieceLabel)return;intdx=nextPiece.maxX()-nextPiece.minX()+1;intdy=nextPiece.maxY()-nextPiece.minY()+1;/*squareWidth:一个正方块的宽squareHeight:正方块的高*构建一个图像映射*QPixmap为QPaiterDevice的子类*/QPixmappixmap(dx*squareWidth(),dy*squareHeight());/*构建绘画这个pixmap的painter*/QPainterpainter(&pixmap);/*画一个小方块*/painter.fillRect(pixmap.rect(),nextPieceLabel->palette().background());/*画方块*/for(inti=0;i<4;++i){intx=nextPiece.x(i)-nextPiece.minX();inty=nextPiece.y(i)-nextPiece.minY();drawSquare(painter,x*squareWidth(),y*squareHeight(),nextPiece.shape());}/*设置标签的图片映像*/nextPieceLabel->setPixmap(pixmap);}boolTetrixBoard::tryMove(constTetrixPiece&newPiece,intnewX,intnewY){for(inti=0;i<4;++i){intx=newX+newPiece.x(i);inty=newY-newPiece.y(i);/*设置边界*/if(x<0||x>=BoardWidth||y<0||y>=BoardHeight)returnfalse;/*没有方块则返回false*/if(shapeAt(x,y)!=NoShape)returnfalse;//循环}curPiece=newPiece;curX=newX;//赋值新坐标curY=newY;/*更新控件*/update();returntrue;//循环}voidTetrixBoard::drawSquare(QPainter&painter,intx,inty,TetrixShapeshape)//方块颜色的控制{/*定义颜色,并初始化*/staticconstQRgbcolorTable[8]={0x000000,0xCC6666,0x66CC66,0x6666CC,0xCCCC66,0xCC66CC,0x66CCCC,0xDAAA00};QColorcolor=colorTable[int(shape)];/*使用制定颜色画图*/painter.fillRect(x+1,y+1,squareWidth()-2,squareHeight()-2,color);/*设置画笔*/painter.setPen(color.light());/*画直线*/painter.drawLine(x,y+squareHeight()-1,x,y);painter.drawLine(x,y,x+squareWidth()-1,y);painter.setPen(color.dark());painter.drawLine(x+1,y+squareHeight()-1,x+squareWidth()-1,y+squareHeight()-1);painter.drawLine(x+squareWidth()-1,y+squareHeight()-1,x+squareWidth()-1,y+1);}5.3.3tetrixpiece.cpp在picec.cpp文件中,对色块的存储和色块的旋转进行了定义。色块存储在一个三维数组中,第一维表示类型,第二维表示X坐标,第三维表示Y坐标。色块的旋转也在此文件中进行了详细的定义。#include<QtCore>#include<stdlib.h>#include"tetrixpiece.h"/*在这7中形式的图像中随机的生成一种*/voidTetrixPiece::setRandomShape(){setShape(TetrixShape(qrand()%7+1));}/*设置样式为参数所示样式*/voidTetrixPiece::setShape(TetrixShapeshape){/*该三维数组中,第一维表示类型,第二维表示x坐标,最后一维表示y坐标*/staticconstintcoordsTable[8][4][2]={{{0,0},{0,0},{0,0},{0,0}},{{0,-1},{0,0},{-1,0},{-1,1}},{{0,-1},{0,0},{1,0},{1,1}},{{0,-1},{0,0},{0,1},{0,2}},{{-1,0},{0,0},{1,0},{0,1}},{{0,0},{1,0},{0,1},{1,1}},{{-1,-1},{0,-1},{0,0},{0,1}},{{1,-1},{0,-1},{0,0},{0,1}}};for(inti=0;i<4;i++){for(intj=0;j<2;++j)/*coords数组比保存图形信息,和平面点坐标对应*/coords[i][j]=coordsTable[shape][i][j];}pieceShape=shape;}intTetrixPiece::minX()const{intmin=coords[0][0];for(inti=1;i<4;++i)/*qt定义的方法,返回两个数中最小的*/min=qMin(min,coords[i][0]);returnmin;}intTetrixPiece::maxX()const{intmax=coords[0][0];for(inti=1;i<4;++i)/*qMax返回两个值中最大的一个*/max=qMax(max,coords[i][0]);returnmax;}intTetrixPiece::minY()const{intmin=coords[0][1];for(inti=1;i<4;++i)min=qMin(min,coords[i][1]);returnmin;}intTetrixPiece::maxY()const{intmax=coords[0][1];for(inti=1;i<4;++i)max=qMax(max,coords[i][1]);returnmax;}/*向左旋转*/TetrixPieceTetrixPiece::rotatedLeft()const{/*当是正方形时,旋转了等于本身*/if(piece

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论