本系列文章翻译自kidscancode.com网站。这是一个面向少儿提供编程课程服务的网站,在其网站上提供了几个高质量的使用PyGame教授小朋友进行游戏编程的教程,这里将其翻译成中文,并且提供了网页版的PyGame运行环境,读者可以直接在好学好教少儿编程教学平台上直接运行查看效果。
以下为正文。
这是我们的教程系列“使用 Pygame 进行游戏开发”的第 1 部分。 它适用于对游戏开发和提高 Python 编码技能感兴趣的初学者/中级程序员。
什么是 Pygame?
Pygame 是一个“游戏库”——一套帮助程序员制作游戏的工具。包括:
- 图形和动画
- 声音(包括音乐)
- 控制(键盘、鼠标、游戏手柄等)
游戏循环(Game Loop)
每个游戏的核心都是一个循环,我们称之为“游戏循环”。 这个循环不断地运行,一遍又一遍,做所有让游戏运行所需的事情。 游戏每次经过这个循环称为一帧(frame)。
每一帧,可能会发生许多不同的事情,但它们可以分为三个不同的类别:
处理输入(或事件)
这意味着任何游戏之外你想要关注的东西——任何需要游戏来回应的东西,例如:按下键盘、点击鼠标等。更新游戏
这意味着更改此帧(frame)上需要更改的任何内容。 比如一个角色在空中,重力把它拉下来。 再如两个物体相互碰撞而发生爆炸等。渲染(或绘制)
在这一步中,我们在屏幕上绘制所有内容。 背景、角色、菜单或玩家需要看到的任何其他内容都必须绘制在屏幕上正确、更新的位置。
时钟(Clock)
循环的另一个重要方面是控制整个循环的运行速度。 您可能听说过 FPS 一词,它代表每秒帧数(Frames Per Second)。 这意味着每秒应该发生多少次这个循环。 这很重要,因为您不希望游戏运行太快或太慢。 这个参数设置可以让它在不同的计算机上以相同的速度运行 - 如果游戏中的角色需要 10 秒才能在屏幕上运行,那么无论它在哪台计算机上都应该是正确的。
构建 Pygame 模板
现在我们知道了使游戏正常运行需要哪些部分,我们可以开始编写一些代码。 首先,我们将创建一个简单的 PyGame 程序,它除了打开一个窗口并运行一个游戏循环之外什么都不做。 对于您想要制作的任何 PyGame 项目,这将是一个很好的起点。
在我们程序的顶部,我们将导入我们需要的库并为我们的游戏选项设置一些变量:
# Pygame 模板 - 创建新Pygame应用的程序骨架
import pygame
import random
WIDTH = 360 # 游戏窗口的宽度
HEIGHT = 480 # 游戏窗口的高度
FPS = 30 # FPS
接下来我们需要打开游戏窗口:
# 初始化pygame ,创建游戏窗口
pygame.init()
pygame.mixer.init() # for sound
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
pygame.init() 是启动 pygame 并“初始化”它的命令。 screen 将引用我们的游戏屏幕,我们以配置常量中设置的大小创建它。 最后,我们创建一个时钟Clock对象,以便我们能够确保我们的游戏以我们想要的 FPS 运行。
现在是时候制作游戏循环了:
# Game Loop
running = True
while running:
# 处理输入
# 更新状态
# 渲染到屏幕(绘制)
这是我们的游戏循环,它是一个由变量 running 控制的 while 循环。 如果我们希望游戏结束,我们只需将 running 设置为 False,循环就会结束。 现在我们可以用一些基本代码填充每个部分。
渲染/绘制部分
我们将从绘图部分开始。 我们还没有任何字符,但我们可以用纯色填充屏幕。 为此,我们需要谈谈计算机如何处理颜色。
计算机屏幕由像素组成,这些像素有 3 个部分:红色、绿色和蓝色。 每个部分点亮多少决定了该像素是什么颜色,如下所示:
三种基色中的每一种都可以有一个介于 0(关闭)和 255(100% 开启)之间的值,因此三种基色中的每一种都有 256 种不同的值。 以下是可以用于设置颜色的一些示例:
您可以通过将它们相乘得到计算机可以显示的颜色总数:>>> 256 * 256 * 256 = 16,777,216
现在我们了解了颜色,让我们在程序顶部定义一些颜色:
# Colors (R, G, B)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
然后我们可以让我们的绘图部分填满屏幕。
# Draw / render
screen.fill(BLACK)
然而,这还不够,因为计算机显示器的工作方式。更改屏幕上的像素意味着让显卡去告诉显示器更改实际像素。用计算机术语来说,这是一个非常非常缓慢的过程。因此,如果您要在屏幕上绘制很多东西,则可能需要很长时间才能将它们全部绘制出来。我们可以通过使用一种叫做双缓冲的方法巧妙地解决这个问题。这听起来很花哨,但实际上就是这个意思:
想象一下,我们有一个双面白板,可以翻转以显示一侧或另一侧。前面是显示器(玩家看到的屏幕),而后面是隐藏的,只有电脑可以“看到”它。每一帧,我们都在背面进行绘制——每个角色、每个子弹、每一个闪光等等。然后,当我们完成后,我们将板子翻转过来并展示新的帧。这意味着我们只在显示每一帧的时候与显示器进行缓慢的对话,而不是针对更新屏幕上的每一件事。也就是说,将多个更新操作打包成一帧,这样和屏幕的缓慢交互只需要进行一次即可。
所有这些都在 pygame 中自动发生。完成绘图后,您只需告诉它翻转白板即可。事实上,该命令甚至被命名为flip():
# Draw / render
screen.fill(BLACK)
# *after* drawing everything, flip the display
pygame.display.flip()
我们需要确保总是在更新的最后做 flip() 。 如果您在flip后尝试绘制某些东西,它将不会被看到(因为此时只是绘制到了缓存而并没有绘制到屏幕)!
输入/事件部分
目前为止,我们还并不知道我们将编写什么样的游戏,所以我们并不确定我们想要监听什么键盘或鼠标按钮或其他输入。 但是,我们需要设置一个重要事件。 如果您现在尝试运行该程序,您会发现您遇到了问题:无法关闭窗口! 单击角落的“X”不起作用。 那是因为这实际上是一个事件,我们需要告诉我们的程序监听该事件并让它退出游戏。(注意在好学好教少儿编程教学平台上,默认是可以直接关闭窗口的,这点和PyGame原有设置不太一样)
事件可以随时发生。 如果玩家在循环的更新或绘制部分发生时单击“跳转”按钮怎么办? 您不想只是忽略该输入-玩家会感到沮丧。 所以 Pygame 所做的就是保存自上一帧以来发生的所有事件。 这样,如果玩家快速胡点了大量按钮,我们可以让程序知道所有这些按下的按钮。它是一个列表,所以我们运行一个 for 循环来查看所有这些事件:
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
Pygame 有很多可以查找的事件。 pygame.QUIT 是单击“X”时发生的事件,因此我们将 running 设置为 False 并且游戏循环将结束。
控制 FPS
目前,我们没有任何操作需要放在“更新”部分,但我们仍然需要确保我们使用我们的 FPS 设置来控制速度。 我们可以这样做:
while running:
# keep loop running at the right speed
clock.tick(FPS)
tick() 命令告诉 PyGame 计算循环花费了多长时间,然后暂停多长时间以使整个循环(即整个帧)持续适当的时间。 如果我们将 FPS 设置为 30,这意味着我们希望一帧持续 1⁄30 或 0.03 秒。 例如,如果我们的循环代码(更新、绘图等)只需要 0.01 秒,那么 pygame 将等待 0.02 秒。
最后,让我们确保当游戏循环结束时,我们实际上销毁了游戏窗口。 为此,我们将 pygame.quit() 放在代码的最后。
完整代码如下:
# Pygame template - skeleton for a new pygame project
import pygame
import random
WIDTH = 360
HEIGHT = 480
FPS = 30
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
# Update
# Draw / render
screen.fill(BLACK)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
祝贺🎉!现在我们有了一个可用的 Pygame 模板,点击此处直接运行。 我们可以将它保存到一个模板文件中,这样你每次开始一个新的 Pygame 项目时都可以重用它。
在下一个教程中,我们将使用此模板作为学习如何在屏幕上绘制对象并使它们四处移动的起点。