Program Arcade Games
With Python And Pygame

Chapter 11: 位图和声音

要超越简单的绘制图形,我们的程序需要有能力使用位图图像。位图图像可以是照片或者有绘图程序绘制并存储起来的图形。

但是光有图像还不够。游戏还要哟声音! 这一章展示了如何把图像和声音添加到你的游戏。

11.1 在文件夹中存储程序

视频:在文件夹中管理项目

我们现在写的程序都只涉及打一个文件而已。现在我们要包含图像和声音,所以在我们的程序里会有很多文件。 很容易把这些文件和其他程序混在一起。 最简洁的分离办法是把每一类程序放在各自的文件夹内。 在开始任何项目之前,点击“创建新文件夹”按钮,比使用新的文件夹作为存储点,如图例所示11.1

fig.create_a_folder
Figure 11.1: 创建一个新文件夹

11.2 设置背景图像

视频:在文件夹中管理项目

需要给你的游戏添加一个背景? 找一张图片如图所示11.2。 如果你在浏览器里寻找,通常你可以右击一张图片,然后保存在计算机上。 把图片保存在我们刚给游戏创建的文件夹里。

确保你没有使用有版权的图片!使用反图像搜索很容易发现你是否盗用了。你已经学程过半了,不要冒这个风险。

fig.background_image
Figure 11.2: Background Image

任何用在游戏里的位图图像应该剪裁到符合屏幕的尺寸。不要取一张从高分辨率里拍摄的5000x5000的图片并输出到一个800x600的窗口里。 使用一个图形程序(甚至简单的画图程序),可以重新调整图形的尺寸。

载入图像是个简单的过程,只需要用到一行代码。 在那一行代码背后有许多事情正在发生,所以解释这一行需要三个部分。 我们第一个版本的load命令会载入一个saturn_family1.jpg的文件。这个文件和Python程序在同一个文件夹内,否则计算机无法找到它:

pygame.image.load("saturn_family1.jpg")

这行代码可以载入图片,但是我们没有办法指向这个图片并显示出来!我们需要一个变量来获取load()命令返回的内容。 在下一个版本中,我们创建了一个新的便利那个名叫background_image。下面就是版本2:

background_image = pygame.image.load("saturn_family1.jpg")

最后,图片需要转化成Pygame可以轻松操作的格式。为了这个目的,我们砸末尾添加一个.convert()命令来调用转化函数。 函数.convert()是属于Image类的一个方法。我们会在第12章中讨论类,对象和方法的相关内容。

所有图片的导入应该都和下面这行代码类似。 只需更具需要改变变量名和文件名。

background_image = pygame.image.load("saturn_family1.jpg").convert()

载入图片嘘小在主循环之前完成。 尽管在主循环内载入是可能的,但这样会使得程序每秒从硬盘读取很多次。是完全没有必要的。只需要在程序启动时读取一次。

要显示图片使用blit命令。这个“blits”命令会把图片比特化到屏幕上。我们已经在之前第五章显示文本的时候使用过这个命令。

blit命令是screen变量的一个方法,所以我们需要使用screen.blit。 下一步,我们需要传递图像来比特化,已经决定在哪儿显示。 这个命令需要在循环之内完成,这样每一帧都能绘制图像。参考下列代码:

screen.blit(background_image, [0, 0])

这行代码会将background_image中的图像比特化到屏幕上,从(0, 0)开始。

11.3 移动图片

视频: 移动图片

现在我们需要载入一个图片并在屏幕中移动它。我们会一艘简单橙色太空飞船开始。 你可以在这里http://kenney.nl/获取它以及其他素材。参考图例11.3。 飞船的图片也可以从书的网站上下载,或者你可以寻找任一.gif或者.png格式的图片(白色或者黑色背景)。不要使用.jpg格式。

fig.player_image
Figure 11.3: 玩家图片

载入图片的命令和载入背景图片是一样的。 在这个例子中,我假设文件名保存为player.png.

player_image = pygame.image.load("player.png").convert()

在程序主循环内,鼠标坐标已经获取,并传递至另一个blit函数来绘制图像:

# 获取现在的鼠标位置。这会返回一个两个数字组成的列表。
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]

# 复制图片至屏幕:
screen.blit(player_image, [x, y])

这会产生一个问题。图片是一张带黑色背景的飞船。 所以当图像如图例绘制出来的时候11.4.

fig.nontrans_background

我们只想要飞船,不需要矩形的北极啊! 但是所有我们能够载入的都是矩形,我们如何移除矩形只保留我们想要的部分呢? 一种可行的办法是告诉程序让一种颜色变“透明”,不显示出来。 这在载入之后可以立即完成。下面的代码会把黑色 (假设BLACK是已经被定义的变量)变透明:

player_image.set_colorkey(BLACK)

这对大部分以.gif和.png结尾的图片文件有效。对绝大多数.jpg文件无效。jpeg格式对保存摄影图片很棒,但是它为了压缩图片用算法更改了图像。 .gif and .png格式的图片虽然也压缩了,但是它们使用的算法并没有改变图像。.bmp格式是完全不压缩的,也造成文件巨大。 因为.jpg格式图片改变了凸显,这就意味着不是所有的背景是同一种颜色。 在图例11.5中飞船已经以白色背景存储为jpeg文件了。这种白色并不是正好(255, 255, 255), 但是非常接近。

fig.jpeg_artifacts
Figure 11.5: JPEG压缩产物

如果你在挑选一张想变透明的图片,选择.gif或者.png格式。它们是艺术类图片最好的格式。照片是.jpg。 请记住不是把文件扩展名改成.png就真的可以改变一章.jpg图片的。即使你把它叫成其他名字它还是一张.jpg图片。 它需要通过图像程序才能转化成另一种格式。但是一旦是jpg格式,那么图像已经被改变了再转化成.png以及无济于事。

下面是三个找到免费的图皮的网站:
Kenney.nl
OpenGameArt.org
HasGraphics.com

11.4 声音

视频: 声音

砸这个部分我们会在鼠标点击的时候播放一个镭射光的声音。这个声音文件源自于Kenney.nl。你可以在这里下载并保存:
ProgramArcadeGames.com/python_examples/en/laser5.ogg

像图像一样,声音必须在使用前载入好。这一步也是要在循环主程序之前一次完成。 下面的命令载入了一个声音文件并创建了一个名为click_sound的变量来指向它:

click_sound = pygame.mixer.Sound("laser5.ogg")

我们可以使用下面的命令来播放声音:

click_sound.play()

但是我们把这条命令放在哪儿? 如果我们放在主循环里那么它会每秒播放二十次以上。非常烦人。我们需要一个“触发器”。当一些事件发生时,我们来播放声音。 例如下面这段代码,当用户点击鼠标按年的时候我们来播放这段声音:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        done = True
    elif event.type == pygame.MOUSEBUTTONDOWN:
        click_sound.play()

未压缩的声音文件通常以.wav结尾。这些文件比其他文件大很多因为没有使用算法来使文件变小。 还有一种更受欢迎的.mp3格式,尽管这种格式砸某些特定应用中很不合适。另一种免费使用的格式是.ogg

Pygame不使用任何在网上可以找到的网上bd>.wav文件。 如果你有文件不工作,你可一使用程序Audacity把它转化成一个.ogg.格式的声音文件。这种格式很小且在pygame中很可靠。

如果你想让你的程序运行时播放背景声音,可以参考这些例子:
ProgramArcadeGames.com/en/python_examples/f.php?file=background_music.py

请注意你不能够传播有版权的音乐。即使你做了一个关于你程序的视频使用了有版权的音乐作背景。YouTube和其他视频网站会以侵权举报你。

能给你的程序找到免费声音的地方是:
OpenGameArt.org
www.freesound.org

11.5 代码清单

"""
 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

 Explanation video: http://youtu.be/4YqIKncMJNs
 Explanation video: http://youtu.be/ONAK8VZIcI4
 Explanation video: http://youtu.be/_6c4o41BIms
"""

import pygame

# Define some colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# Call this function so the Pygame library can initialize itself
pygame.init()

# Create an 800x600 sized screen
screen = pygame.display.set_mode([800, 600])

# This sets the name of the window
pygame.display.set_caption('CMSC 150 is cool')

clock = pygame.time.Clock()

# Before the loop, load the sounds:
click_sound = pygame.mixer.Sound("laser5.ogg")

# Set positions of graphics
background_position = [0, 0]

# Load and set up graphics.
background_image = pygame.image.load("saturn_family1.jpg").convert()
player_image = pygame.image.load("playerShip1_orange.png").convert()
player_image.set_colorkey(BLACK)

done = False

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.MOUSEBUTTONDOWN:
            click_sound.play()

    # Copy image to screen:
    screen.blit(background_image, background_position)

    # Get the current mouse position. This returns the position
    # as a list of two numbers.
    player_position = pygame.mouse.get_pos()
    x = player_position[0]
    y = player_position[1]

    # Copy image to screen:
    screen.blit(player_image, [x, y])

    pygame.display.flip()

    clock.tick(60)

pygame.quit()

11.6 复习

11.6.1 选择题小测验

Click here for a multiple-choice quiz.

11.6.2 练习表

Click here for the chapter worksheet.

11.6.3 实验

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.