2.6 Surface对象
窗口屏幕是Surface对象,图片也是Surface对象,那么到底什么是Surface呢,它又有哪些功能呢?本节将详细介绍Surface及其常见用法。
涉及Surface的相关模块为pygame.Surface,它提供了对Surface所有功能的支持。该模块提供的功能函数较多,本节只介绍常用的一些函数。
不过,与其说Surface是一个模块,不如说它是一个类,pygame.Surface下的功能函数其实都是Surface类的成员函数,Surface对象其实就是指pygame.Surface类的对象,前面提到的Rect对象与之同理。
1. Surface的定义
图2-6 Surface示意图
Surface是一块如图2-6所示的矩形显示区域,用来表示任意图像,它具有固定的宽度、高度、像素格式。也可以把Surface理解为一张画布,在其上面可以做许多事情,如绘制图像、绘制线条和文字、填充颜色等;还可以把当前Surface作为图像复制到另外一个Surface上。
在Pygame中,所有与显示相关的区域都被表示为Surface,如屏幕和图片,它们都是Surface对象,可以通过pygame.Surface模块提供的函数对它们进行一系列操作。其中,通过pygame.display.set_mode()创建的display surface是一个比较特殊的Surface。在代码中,大多数时候需要不断向该Surface绘制内容,最后在屏幕上显示出来。在调用pygame.display.flip()或pygame.display.update()更新屏幕时,显示的只是该Surface上的内容。
2. 创建Surface
创建Surface对象的方式有以下几种。
(1)通过pygame.display.set_mode()返回的display surface创建Surface,它是一个特殊的Surface对象。
(2)通过pygame.image.load()返回的image surface创建Surface,它也是一个Surface对象。
以上两种方式相信读者都不陌生,因为本书已经多次提及。除此之外,还有一种更为直接的创建Surface对象的方式。
(3)通过Surface类的构造函数创建Surface对象。该方式会默认创建一个空的Surface,其内部所有像素都被初始化为黑色,其构造函数包含多个参数,其中,只有分辨率是必须指定的,如下所示。
(4)使用函数pygame.font.Font.render()创建Surface对象,该方式将在需要显示文字时用到,该函数可以创建一个包含指定文字的Surface对象,其细节将在后续章节详细介绍。
以上便是创建Surface对象的四种常用方式。
3. 绘制Surface
前面说过,Surface其实就是一张画布,我们可以在该画布上绘制任意想要的内容,如填充颜色、绘制图像、文字、线条和图形等,那么该如何向Surface绘制内容呢?
pygame.Surface模块提供了两个与绘制相关的函数:fill()和blit(),这两个函数都在Hello World示例程序中出现过,下面详细介绍这两个函数。
fill()函数用来向Surface填充指定颜色,其第一个参数color为待填充颜色的RGB值或RGBA值;第二个参数rect代表颜色填充的目标区域,如果没有指定,则会填充整个Surface;第三个参数special_flags涉及更多高级特性,这里不做介绍。
blit()函数用来把一个Surface绘制到另一个Surface,即像素之间的复制,图像和文字的绘制都使用这种方式。该函数的调用者是目标Surface,其第一个参数source为源Surface;第二个参数dest为待绘制区域的左上角坐标,其取值可以是一个点的坐标,也可以是Rect对象,当其取值是Rect对象时,起关键作用的将是该矩形的左上角坐标,矩形的其他参数会被忽略;第三个参数area代表源Surface中需要绘制的区域,即可以只把源Surface中的一部分区域绘制到目标Surface,如果没有指定该参数,则会默认把整个源Surface绘制到目标Surface。其中,只有前面两个参数是在使用时必须指定的。
在大多数情况下,blit()函数的调用者为display surface,即display surface作为目标Surface被绘制。
现在,我们了解了如何向Surface填充颜色、绘制图像与文字(关于绘制文字,此处留有悬念,后续会详细介绍),那么该如何向Surface绘制线条与图形呢?很遗憾,绘制线条和图形的相关函数并不是在pygame.Surface模块中定义的,而是pygame.draw模块提供的,这个知识点需要留到后面讲解。
4. 转换Surface像素格式
当使用blit()函数把源Surface绘制到目标Surface时,如果两者的像素格式不一致,则blit()函数内部会自动进行像素格式转换。在一般情况下,blit()函数每帧都会被调用,如果每调用一次就进行一次格式转换,则会花费大量时间。因此,在创建源Surface后、执行blit()函数前,需要把源Surface转换成与屏幕display surface一致的像素格式,这样做可以大幅加快blit的过程,从而提升程序性能。
像素格式转换用到了以下两个函数。
该函数把当前Surface转换成与屏幕Surface(display surface)一致的像素格式,返回值为转换后的Surface。
该函数与convert()函数的功能类似,但它会保留像素的alpha值。如果使用的是带有透明效果的图片,则必须使用该函数进行转换,转换后仍然会保留图片原来的透明效果;如果此时使用convert()函数,则会丢失图片原来的透明信息。
上述两个函数的典型用法是:
加载图像Surface后,立刻对它们进行像素格式转换。这样一来,image0和image1就都变为像素格式转换后的图像Surface了。
总之,如果图片不带有透明效果,则使用convert()函数进行像素格式转换;如果图片带有透明效果,则使用convert_alpha()函数进行像素格式转换。
5. 获取Surface属性
我们知道,Surface其实就是一块用来显示的矩形区域,它应该具备矩形应有的一些属性,如宽度、高度、坐标等信息。pygame.Surface模块也提供了一些函数,用来获取这些有用的信息,常用的函数有以下几种。
获取Surface的宽度,单位为像素(pixel)。
获取Surface的高度,单位为像素(pixel)。
获取Surface的尺寸,返回值为(width,height)二元组,单位为像素(pixel)。
获取Surface所在的矩形区域,返回值为一个Rect对象,默认返回的是一个左上角坐标位于(0,0)、宽度和高度与Surface相同的矩形Rect对象。该函数可以接收一些关键字参数,用来指定返回的Rect对象的属性,如:
上述代码返回的是一个中心点坐标位于(100,100)、宽度和高度与Surface相同的矩形,返回值rect是一个Rect对象,与下面这段代码的效果相同。
关于Rect类的用法,本书将在后续章节详细讲解。
除了以上函数以外,pygame.Surface模块还提供了许多其他函数,不过它们大多是与像素操作相关的,这里不做深入探讨。