2.3 Hello World
如果想迅速了解任意一个库,则最好的方法就是先从代码入手。下面给出一个Pygame的Hello World示例程序,以帮助读者直观、快速地了解Pygame。
首先来看其执行结果:该程序会创建一个标题为Hello World的窗口,窗口中间显示有Pygame的Logo,如图2-3所示。
图2-3 Hello World示例程序
代码如下。
基本上所有Pygame程序大体都是这个样式,下面逐行解释上述代码。
第1~3行:首先引入相关的库,即sys和pygame,引入sys的目的是使用其中的exit()函数。
下面分析main()函数中的代码。
第7行:该函数用来初始化Pygame中的所有相关模块,在执行其他操作前,必须调用该函数。
第9行:该函数是Pygame创建游戏窗口的核心函数,虽然其名字并不直观,但其功能确实如此。该函数创建了一个尺寸为800×400像素的游戏窗口,其参数为窗口尺寸,返回值为Surface对象,代表整个游戏窗口所在的显示区域。
第10行:设置窗口标题为Hello World。
第12行:加载pygame.png,即Logo所在的图片,其返回值Logo也是一个Surface对象。在Pygame中,所有与显示相关的区域(包括加载后的图片)都被表示为Surface对象,Surface对象是一块显示区域,也可以把它理解为一张画布。
第13行:调用Surface对象的get_rect()函数获取Logo所在的矩形区域,其返回值logo_rect的类型为Rect对象,其默认值为(0,0,width,height),即左上角坐标为(0,0)、宽和高与Logo图片相同的一个矩形区域。
注意:在Pygame程序中,坐标原点(0,0)位于窗口的左上角。
第14行:由于之前获得的logo_rect,即Logo图片所在的矩形位于(0,0,image_width,image_height),其左上角坐标为(0,0),因此现在需要把该矩形移动到窗口中间。前面解释了logo_rect其实是一个Rect对象,因此它具有许多属性。这里,我们直接把logo_rect的center属性赋值为(400,200)即可,现在Logo图片所在的矩形logo_rect就已经被移动到窗口中间了。关于Rect对象的更多用法,本书会在后续章节详细讲解。
第16~20行:在所有必需要素都初始化完毕后,下面开始实现游戏循环。熟悉GUI编程的读者想必对此并不陌生,因为几乎所有游戏程序都有类似的死循环,主要用来检测和处理用户输入、更新游戏状态、绘制屏幕等。上述代码通过while True进入死循环,然后不断读取消息队列中的所有消息,并判断消息类型是否为pygame.QUIT,如果是,则调用pygame.quit()和sys.exit()结束程序。当窗口关闭时,会收到此QUIT消息,此段代码将被执行。由于本程序比较简单,因此只简单地设置一个QUIT消息,读者也可以在此处理其他类型的消息。
游戏循环中的后面三行代码均是与屏幕绘制相关的。
第22行:该函数用来把屏幕窗口填充为白色,fill()函数的参数为待填充颜色的RGB值。
第23行:该函数用来把Logo surface绘制到screen surface上,绘制Logo的位置为logo_rect,即从logo_rect左上角的位置开始绘制Logo,其第一个参数代表source surface,第二个参数代表绘制source surface的位置。
之所以把这个函数放在循环中调用,是因为在一般情况下source surface rect的位置是不断变化的,即屏幕上的物体是不断移动的,因此每次循环都需要重新绘制,以把其绘制在屏幕上的合适位置。不过本程序比较简单,Logo图片时刻保持静止,因此并没有体现出这一点。基于此,也可以理解把上面的fill()函数放入循环的原因是每次在因物体移动而重绘时,都需要把之前屏幕上的内容擦除,否则就会出现物体的“重影”现象。因此,每次在绘制物体前,都需要把屏幕填充为白色、其他颜色或背景图,这样可以有效避免“重影”现象的产生。
除此之外,另一个需要注意的地方就是屏幕的绘制顺序,一定要按照先后顺序进行绘制,否则后绘制的内容会覆盖先绘制的内容。在上述代码中,如果先执行blit(),后执行fill(),则整个屏幕都会变成白色,Logo图片会被白色背景覆盖住。
第24行:该函数用来更新屏幕上的内容,使所有绘制到screen surface上的内容都显示在屏幕上。
注意:如果希望屏幕正确显示,则该函数是必需的,必须在每次循环的所有绘制操作完成后调用该函数,否则屏幕将一片漆黑,什么都不显示。而把该函数放在循环中调用执行的原因是屏幕上的内容是不断变化的,因此需要不断更新屏幕。