基于QT的飞行射击游戏的实现
2017-12-15成荣荣崔志斌杨克香
成荣荣++崔志斌+杨克香
摘要:飞行射击游戏因操作简单、娱乐性强而广受欢迎。在Linux操作系统下,以Qt为开发平台,采用C++语言设计了一款小型飞行射击类游戏,主要采用类Element和类GamePad来实现游戏的功能。
关键词:Qt;射击游戏;C++
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2017)32-0089-03
Realization of Flight Shooting Game Based on QT
CHENG Rong-rong1, CUI Zhi-bin2, YANG Ke-xiang1
(1.Kunshan dengyun college of science and technology, Kunshan 215300, China; 2.suzhou huatian shihang smart equipment technology CO.LTD, Kunshan 215300, China)
Abstrsct:The flight shooting game is very popular because of its simple,entertaining.In the Linux operating system,Qt as the development platform,using C++ language design a small flight shooting game,Mainly using class Element and class GamePad to achieve the function of the game.
Key words: Qt; shooting game; C++
Qt是一个跨平台应用程序和UI开发框架,具有完整的Qt集成开发环境,其中包括高级C++编译器、项目生成和管理工具,图形化调试器代码管理等等,适用于游戏界面的开发和应用,同时也适用于移动设备软件的设计,例如手机游戏方面[1-2]。在Linux操作系统下,执行完Qt安装包,导入库文件,对环境进行一定的配置之后,就可以在Qt环境中进行C++程序的编辑[3-4]。游戏包括开始(start)、暂停(pause)、结束(end)等,当进入游戏登陆界面时,点击开始(start)开始游戏,点击暂停(pause),可中途停止游戏,当异常或者游戏结束时,可选择结束退出,整个游戏结构如图1所示。
1 类的关系图和作用
游戏主要通过类Element和类GamePad来实现,其中类Element主要存放的是界面右侧的功能键(开始、暂停、结束)、计时器等功能组件。类GamePad的主要功能是生成游戏主界面比如游戏的背景地图等,Map类、Plane类和Bullet类分别在Gamepad类中实现。类的关系如图2所示,各类的作用如表1所示。由于篇幅限制,这里主要介绍类Element和Widget。
2 类Element
2.1 按钮组件
类Element所包含的内容包括:开始,暂停,结束按钮和计时器。定义代码如下:
QPushButton*startBtn;
QPushButton*pauseBtn;
QPushButton*ExitBtn;
QPixmapstartMap,pauseMap,exitMap;
QLabel*ScoreLab;
QLineEdit*ScorePad;
QLabel*TimeLab;
QLineEdit*TimePad;
QLabel*LifeLab;
QLineEdit*LifePad;
首先,startBtn,pauseBtn,ExitBtn聲明分别为开始、暂停、结束按钮,三个按钮的公共类为QpushButton,这是代表按钮的类,实例化的三个按钮,便作为游戏界面上的控制按钮。另外,由类QPixmap声明的StartMap,PauseMap,ExitMap导入的是三个绘图,用于按钮上的三个图标,Qpixmap的主要作用就是绘图,其主要依赖于硬件,与同作用的类QImage相比,类QPixMap是针对屏幕显示而最优化设计,而QImage主要是为图像I/O、图片访问和像素修改而设计的。当图片小的情况下,直接用QPixmap进行加载,画图时无所谓,当图片大的时候如果直接用QPixmap进行加载,会占很大的内存,一般一张几十K的图片,用QPixmap加载进来会放大很多倍,所以一般图片大的情况下,用QImage进行加载,然后转乘QPixmap用户绘制。QPixmap绘制效果是最好的。因此在按钮上绘制图标,便优先选择了QPixMap。
其次,TimeLab和LifeLab声明的是两个标签,分别代表时间和生命数,它们的公共类是QLabel类代表标签,其声明的两个类就是两个计数器前的标志。
最后,通过文本编辑器QLineEdit类声明了两个对象,分别为TimePad、LifePad分别代表时间、生命数的三个显示框,QLineEdit表示行编辑器,经过相应的处理最终显示在界面上的就像是LED的效果。
各项组件实例化之后,需要完成的工作就是进行布局安排,如何布局对于游戏的可视性极为重要,一般的布局管理方面,便利的方法是使用布局管理器,常用的布局管理有以下几种:
1) QVBoxLayout(垂直布局)用于位于竖直方向的组件的布局管理。
2) QHBoxLayout(水平布局)管理水平方向的布局。
3) QGridLayout(网格布局)可以在一个网格范围内进行布局管理。endprint
4) QstacketLayout(堆叠布局)管理位于同一坐标上的多个组件。
布局管理的弊端在于,布局呈现的外观略显生硬僵化,無法达到某些特定的预期,例如本游戏的相关组件布局,需要有大小、位置、美观上的严格要求,所以采用的布局是原始的布局方式,即按照坐标点,人为的进行安置,这样便可以随意愿,布置界面的格局。在各组件定义实例化之后,游戏布局的代码如下:
ScoreLab→setGeometry(0,30,50,40);
ScorePad→setGeometry(50,30,80,40);
LifeLab→setGeometry(0,90,50,40);
LifePad→setGeometry(50,90,80,40);
TimeLab→setGeometry(0,150,50,40);
TimePad→setGeometry(50,150,80,40);
pauseBtn→setGeometry(0,425,50,50);
startBtn→setGeometry(0,425,50,50);
ExitBtn→setGeometry(75,425,50,50);
其中,startBtn和pauseBtn所处的坐标位置一致,利用setShown方法设置按钮的可见性,即当点击按钮时该按钮就会消失,相应的同位置的另一个组件就会显示出来,这样就实现了按钮的切换,实现方法如下:
1) 在文件定义两个槽函数,分别为pauseBtnClicked()和startBtnClicked(),定义代码如下:
void Element::startBtnClicked()
{startBtn→setShown(0);
pauseBtn→setShown(1);}
void Element::pauseBtnClicked()
{pauseBtn→setShown(0);
startBtn→setShown(1);}
2) 使用connect方法,将信号与槽相连接,实现如下:
connect(startBtn,SIGNAL(clicked()),this,SLOT(startBtnClicked()));
connect(pauseBtn,SIGNAL(clicked()),this,SLOT(pauseBtnClicked()));
当setShown()参数为0时表示,组件为不可视,为一时则显现出来,当按钮被点击时,会发出信号,如代码中SIGNAL中的clicked()参数,接受到信号后就会自动调用SLOT中的函数,即先前定义的槽函数。
信号和槽有以下几种关联情况:1)一个信号可以连接多个槽;2)多个信号可以连接一个槽;3)一个信号可以与另外一个信号连接;4)连接可以解除[3]。
所有从Qobject或其子类(例如Qwidget)派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射(emit)出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。
2.2 计时器
点击startBtn的同时,计时器响应。首先,我们在主函数中声明并定义几个整型数hour、min、sec分别代表时、分、秒,并将它们初始化为0,所以在未开始之前,计时器的表盘始终是“00:00:00”显示。
其次,利用QTimer定义一个计时器,命名为timer,方法如下:
timer = new QTimer(this);
timer→setInterval(1000);
setInterval()方法的作用是设定响应的时间,时间单位为毫秒(ms),因此设定时间为1000毫秒,1秒钟响应一次。
实现计时器,还需要几组功能函数,用于显示数字,定义一个槽函数,命名为updateTime用于时分秒的转换,再定义一个函数flushTime()用于更新显示的数字,如代码所示:
void Element::flushTime()
{QString timestr;
timestr.sprintf("%02d:%02d:%02d",hour,min,sec);
TimePad→setText(timestr);}
void Element::updateTime()
{sec++;
if(sec == 60)
{ sec = 0;
min++;
if(min == 60)
{min = 0;
hour++;} }
flushTime();}
connect(timer,SIGNAL(timeout()),this,SLOT(updateTime()));
计时器效果如图3所示:
3 类Widget
Widget是一个组件类,GamePad和Element可以理解为两个组件,实例化之后进行布局安排。
resize(650,500);
gamePad = new GamePad(this);
selectionPad = new Element(this);endprint
gamePad→setGeometry(0,0,500,500);
selectionPad→setGeometry(510,0,200,500);
键盘触发事件,实现角色控制与键盘同步,主要通过系统调用的保护函数keyPressEvent(QKeyEvent *event)实现:
void Widget::keyPressEvent(QKeyEvent *event)
{ if(event→isAutoRepeat())
return;
switch(event→key())
{case Qt::Key_W:
gamePad→RoleMOveCtl(Up);
break;
case Qt::Key_S:
gamePad→RoleMOveCtl(Down);
break;
case Qt::Key_A:
gamePad→RoleMOveCtl(Left);
break;
case Qt::Key_D:
gamePad→RoleMOveCtl(Right);
break;
case Qt::Key_J:
gamePad→RoleMOveCtl(Other);
default:
break;}}
其中对应的Key_A,Key_W,Key_S,Key_S,Key_D是对应的键位(A,W,S,D),用于控制角色的上下左右的移动,Key_J对应键位J用于控制子弹射击。敌方爆炸效果如图4所示,我方爆炸效果如图5所示。
4 结束语
本文实现了基于QT的飞行射击游戏的开发,程序中包含的类有Element,GamePad,Map,Plane,Bullet,ResultDialog,Widget,不同的类实现了游戏中的不同功能,这些类的灵活性强,可扩展性高,明显提高了游戏的可操作性,增加了游戏的真实感体验,也在一定程度上实现了玩家的满意度。
参考文献:
[1] 郑阿奇. Qt4开发实践[M]. 北京: 电子工业出版社, 2011.
[2] 杨盛毅, 文方, 师娇. 实时数据曲线绘制的Qt编程实现[J]. 四川大学学报:自然科学版, 2008, 45(2):61-64.
[3] 譚浩强. C++程序设计[M]. 北京: 清华大学出版社, 2006.
[4] 杨宗德, 邓玉春. Linux高级程序设计[M]. 北京: 人民邮电出版社, 2009.
[5] Jasmin Blanchette, Mark Summerfield. C++GUI编程[M]. 北京: 电子工业出版社, 2008.endprint