这是一组给大家介绍Python游戏引擎开发的系列教程,使用Python开发的优点就不多说,下面进入引擎开发的第一个阶段,关于创建窗口和重绘界面。。在开发本地应用之前,我们得先有个窗口,用于显示界面。其次我们还得实现重绘机制,使游戏不停地刷新,达到动态化的目的。
Qt的渲染机制
在上一章《序》中我们讲到本次开发用到了PyQt,也就是Qt的Python版。在开始实现引擎功能之前我们要先了解一下Qt,这里先了解渲染机制。
在Qt中,绘画用到的类叫做QPainter,顾名思义,就是个画家类吧。在这个类中,提供了非常多的方法用于操控这个“画家”,比如说叫他去画个圆,叫他去测量文字的尺寸,画家先生当然是不会推辞的。 在使用QPainter时,需要给其一个绘画设备,也就类似于画家的画板。这个绘画设备就是一个QWidget,部件类。这个类又提供了很多方法,比如说设置部件尺寸等。在Qt中,如果只有一个QWidget,那么这个QWidget就会成为窗口对象。
Qt中的事件以及信号和槽
Qt中的事件和JavaScriptdom事件有点不同,不是通过注册一个事件类型和所对应的监听器来进行事件回调的,而是Qt直接在类中写好了监听器,通过重写这个监听器方法来执行自己的代码,也就是是说Js的事件是加了才会调用的,而Qt是自动加上了事件,通过修改监听器来执行自定义的代码。不过Qt对Js添加事件这一功能换了种说法——信号和槽。这个就好比《基督山伯爵》中菲尔兰出卖阿里国王那段一样——送来的是匕首则引爆炸弹炸掉所有的财产和家人,送来的是戒指则平安无事。这里的“送来匕首”就是信号,“引爆炸弹”就是槽;“送来戒指”是信号,“平安无事”为槽。你还可以把信号理解为事件名,槽理解为回调函数。
上文所提到的绘画需要在QWidget的paintEvent中进行。
也就是说,如果你要使用Qt里一系列的功能,请在实例化QApplication后,调用exec_方法前使用这些功能,也就是程序的入口是在代码中# ...的位置。另外,QApplication要接受一个参数,也就是代码中的sys.argv,因此你需要在使用前引入sys模组。 这里就顺便提一下Qt的一些模组。Qt作为一款强大的引擎,难免有很多模组,不过我们大致要用的就只有QtGui,QtCore,QtWebKit这些模组。开发游戏的话,QtGui,QtCore这两个模组就已经够用了。
库件基础类
基础部分大致讲完了,开始封装吧,首先封装的就是Stage类。这个类大致就是管理一些全局的事物吧,比如说获取窗口的大小,设置窗口刷新频率,向最低层加入显示对象等等。不过在实现Stage前,我们得先创建一个库件中最底层的Object类:
这个类作为库件中所有类的基类,方便以后给所有类扩展功能。然后是Stage类的构造器部分:
可以看到,这个类中包含了许多全局属性。比如说width和height就是用来获取游戏界面宽高的,backgroundColor用来设置底色。 接下来是_setCanvas方法,用来完成创建绘画设备和QPainter以及重绘计时器:
Qt的QTimer是一个计时器类,通过调用setInterval方法来设置计时时间,并循环计时。start方法开启计时器。然后还用到了connect方法来连接信号和槽,信号是“计时完毕”,槽是“刷新窗口”。这样一来,我们就可以通过这个信号槽装置来实现定时刷新界面的功能了。
在上面的代码中,我们还保存了绘画类QPainter,方面在以后的代码中调用这个画笔。
上面的代码中还出现了CanvasWidget类,它派生自QWidget类,在这个类中,我们还会加入其他的功能,例如重写绘画事件监听器,键盘事件监听器等。构造器代码如下:
当然,Qt为我们提供了不只是QWidget这一种基础部件,还有输入框,按钮,窗口等高级部件,不过我们暂时用不上这些部件,更何况Qt在没有其他窗口部件的情况下,会默认把第一个QWidget设置为窗口对象,所以这里的CanvasWidget继承自QWidget,实例化后,就是窗口对象。 上面用到的setWindowTitle和setFixedSize方法分别是用来设置窗口标题,窗口固定大小的。然后使用show方法把这个部件显示出来。
因为整个游戏中只能有一个Stage对象,为了方便全局公开使用,我们直接在库件里实例化这个类,作为唯一的舞台对象:
在上面的_setCanvas方法中,我们用到了信号槽来完成界面的刷新,那么到底是怎么刷新的呢?当我们的计时器计时到指定的时间后会调用部件的update槽,在这个槽里会调用到paintEvent中,正如我们在“Qt中的事件以及信号和槽”中提到的,这个事件是在QWidget中已经写好了的,我们只需要在CanvasWidget中重写这个函数即可:
调用到Stage对象的_onShow方法中:
在这个函数中,我们首先用QPainter的begin方法绑定绘画设备。然后进行擦除界面,再通过_showDisplayList方法进行重绘,最后结束绘画。值得注意的是_showDisplayList方法,它通过遍历显示列表,将遍历得到对象进行重画:
我们通过调用显示对象的_show方法就可以完成绘制对象了。在后续的开发中,我们只需要为某个对象添加_show方法,然后加入显示列表,就可以重绘该对象了。如果在_show中加入绘画图片的功能,那么就得到了图片类,添加绘画文字的功能,就成了文本类。
在_onShow方法中我们还用到了getColor这个全局函数,用于把颜色名字字符串或者16进制值转化为QColor,毕竟Qt这个文盲,认颜色就只认QColor:
由于Stage类是用来作为最底层显示列表的,所以加入addChild,removeChild方法用来完成添加和删除显示对象:
最后添加init全局函数用于初始化界面:
其中的QApplication在上文已经有了详细的描述。 调用init函数并传入对应的参数就可以看到空空的窗口了。