Menu
CoddyTech

Pygame 速查表

最后更新

初始化与游戏循环

每个 pygame 程序都会先打开一个窗口,然后不断重复同一个循环,直到玩家退出。

操作代码
安装 pygame-cepython3 -m pip install pygame-ce
导入并启动 pygameimport pygame pygame.init()
打开窗口screen = pygame.display.set_mode((640, 480))
设置窗口标题pygame.display.set_caption("My Game")
创建时钟clock = pygame.time.Clock()
游戏循环running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False screen.fill("black") pygame.display.flip() clock.tick(60)
循环结束后关闭pygame.quit()

窗口显示

屏幕本身就是一个 Surface,调用 flip 之前什么都不会显示出来。

操作代码
显示画好的一帧pygame.display.flip()
只刷新部分区域pygame.display.update([rect1, rect2])
清空屏幕screen.fill((30, 30, 46))
窗口尺寸screen.get_size(), screen.get_width()
把屏幕当作 Rectscreen.get_rect()
可调整大小的窗口pygame.display.set_mode((640, 480), pygame.RESIZABLE)
按桌面分辨率全屏pygame.display.set_mode((0, 0), pygame.FULLSCREEN)

颜色与绘图

pygame.draw 的函数接收一个 Surface、一种颜色和一个位置。width=0 表示填充。

操作代码
RGB 颜色(255, 140, 0)
用名称或十六进制表示颜色"tomato", "#ff8c00", pygame.Color("gold")
矩形pygame.draw.rect(screen, "red", (x, y, w, h))
描边和圆角pygame.draw.rect(screen, "red", rect, width=2, border_radius=8)
圆(以圆心定位)pygame.draw.circle(screen, "blue", (cx, cy), radius)
直线pygame.draw.line(screen, "white", (x1, y1), (x2, y2), 3)
多边形pygame.draw.polygon(screen, "green", [(0, 0), (40, 0), (20, 30)])
矩形框内的椭圆pygame.draw.ellipse(screen, "purple", (x, y, w, h))

Rect

Rect 用整数保存一个位置和一个尺寸。

操作代码
创建 Rectplayer = pygame.Rect(x, y, width, height)
按任意一点定位player.center = (320, 240), player.bottom = 400
边和角left, right, top, bottom, topleft, midbottom
原地移动player.move_ip(dx, dy)
返回移动后的副本moved = player.move(dx, dy)
限制在屏幕内player.clamp_ip(screen.get_rect())
以中心为基准放大bigger = player.inflate(20, 20)
浮点坐标(pygame-ce)pygame.FRect(10.5, 20.25, 40, 40)

图片、Surface 与 blit

在循环开始前把图片加载一次,然后每一帧 blit 到屏幕上。

操作代码
加载带透明通道的图片img = pygame.image.load("player.png").convert_alpha()
加载不透明的图片bg = pygame.image.load("sky.png").convert()
绘制图片screen.blit(img, (x, y))
居中绘制screen.blit(img, img.get_rect(center=(320, 240)))
新建空白 Surfacepanel = pygame.Surface((200, 100))
透明 Surfacelayer = pygame.Surface((200, 100), pygame.SRCALPHA)
整个 Surface 半透明img.set_alpha(128)
从精灵图中切出一帧frame = sheet.subsurface((0, 0, 32, 32))
保存截图pygame.image.save(screen, "shot.png")

变换

每个函数都会返回一个新的 Surface。要对原图做变换,而不是对上一次的结果。

操作代码
调整大小pygame.transform.scale(img, (64, 64))
按倍数缩放pygame.transform.scale_by(img, 2)
平滑缩放pygame.transform.smoothscale(img, (64, 64))
旋转(逆时针,单位为度)pygame.transform.rotate(img, 45)
绕中心旋转rotated = pygame.transform.rotate(original, angle) rect = rotated.get_rect(center=rect.center)
水平翻转pygame.transform.flip(img, True, False)

事件与键盘

单次按键用事件处理,持续按住的键用 get_pressed() 检测。

操作代码
读取这一帧的事件for event in pygame.event.get():
窗口被关闭event.type == pygame.QUIT
按下了某个键event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE
松开了某个键event.type == pygame.KEYUP
输入的字符event.unicode
当前按住的键keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= 5
用两个键算出方向dx = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
这一帧刚按下的键(pygame-ce)pygame.key.get_just_pressed()[pygame.K_SPACE]
按键常量K_a...K_z, K_0...K_9, K_UP, K_RETURN, K_ESCAPE, K_LSHIFT
按键的名称pygame.key.name(event.key)
自定义事件HIT = pygame.event.custom_type() pygame.event.post(pygame.event.Event(HIT))

鼠标

按键编号:1 为左键,2 为中键,3 为右键。

操作代码
按下了某个鼠标键event.type == pygame.MOUSEBUTTONDOWN and event.button == 1
按下的位置event.pos
当前指针位置x, y = pygame.mouse.get_pos()
当前按住的鼠标键left, middle, right = pygame.mouse.get_pressed()
鼠标移动event.type == pygame.MOUSEMOTION, event.rel
滚轮滚动event.type == pygame.MOUSEWHEEL, event.y
点击在按钮范围内button_rect.collidepoint(event.pos)
隐藏鼠标指针pygame.mouse.set_visible(False)

精灵与精灵组

精灵保存一个 image 和一个 rect,精灵组可以一次更新和绘制许多精灵。

操作代码
精灵类class Coin(pygame.sprite.Sprite): def __init__(self, pos): super().__init__() self.image = coin_img self.rect = self.image.get_rect(center=pos)
创建精灵组coins = pygame.sprite.Group()
加入精灵组coins.add(Coin((100, 50)))
更新所有精灵coins.update()
绘制所有精灵coins.draw(screen)
把精灵从所有组中移除coin.kill()
只放一个精灵的组player = pygame.sprite.GroupSingle(Player())

碰撞检测

Rect 重叠时才算碰撞,边缘刚好相接不算。

操作代码
两个矩形a.colliderect(b)
点在矩形内rect.collidepoint(x, y)
多个矩形中第一个碰到的rect.collidelist(walls) # index or -1
精灵与精灵组hits = pygame.sprite.spritecollide(player, coins, True)
是否碰到任意一个pygame.sprite.spritecollideany(player, enemies)
精灵组与精灵组pygame.sprite.groupcollide(bullets, enemies, True, True)
像素级精确碰撞pygame.sprite.spritecollide(a, group, False, pygame.sprite.collide_mask)
圆形碰撞pygame.Vector2(a).distance_to(b) < r1 + r2

文字与字体

先把文字渲染成 Surface,再 blit 到屏幕上。

操作代码
默认字体font = pygame.font.Font(None, 36)
系统字体font = pygame.font.SysFont("arial", 24)
字体文件font = pygame.font.Font("pixel.ttf", 32)
渲染文字text = font.render("Score: 10", True, "white")
居中绘制screen.blit(text, text.get_rect(center=(320, 40)))
长文本自动换行(pygame-ce)font.render(story, True, "white", None, 400)
不渲染直接获取尺寸font.size("Hello")
已安装的字体pygame.font.get_fonts()

音效与音乐

音效只需加载一次;音乐则从文件中流式播放一首曲子。

操作代码
加载音效jump = pygame.mixer.Sound("jump.ogg")
播放音效jump.play()
音效音量jump.set_volume(0.5)
加载音乐pygame.mixer.music.load("theme.ogg")
循环播放音乐pygame.mixer.music.play(-1)
暂停和继续pygame.mixer.music.pause(), pygame.mixer.music.unpause()
停止音乐pygame.mixer.music.stop()

时间与计时器

时间以毫秒为单位。

操作代码
限制帧率clock.tick(60)
以秒为单位的帧间隔(delta time)dt = clock.tick(60) / 1000
当前帧率clock.get_fps()
初始化以来经过的毫秒数pygame.time.get_ticks()
重复触发的计时器事件SPAWN = pygame.event.custom_type() pygame.time.set_timer(SPAWN, 1000)
只触发一次的计时器pygame.time.set_timer(SPAWN, 2000, loops=1)
停止计时器pygame.time.set_timer(SPAWN, 0)

Vector2

用浮点数表示位置和速度。

操作代码
创建向量pos = pygame.Vector2(100, 200)
按速度移动pos += velocity * dt
长度velocity.length()
斜向移动保持相同速度if direction.length() > 0: direction = direction.normalize()
两点之间的距离pos.distance_to(target)
旋转velocity.rotate(90)
朝某个点前进一步(pygame-ce)pos.move_towards_ip(target, 5)

用 Python 做 2D 游戏时最常用的 pygame 代码,按任务分组:游戏循环、窗口显示、颜色与绘图、Rect、图片与 blit、缩放与旋转、键盘和鼠标输入、精灵与精灵组、碰撞检测、文字、音效、计时器和 Vector2。每一行都是一段可以直接粘贴的短代码,旁边写着它的作用。

这里的内容全部基于 pygame-ce 2.5 编写。pygame-ce 是 pygame 的社区版,导入时仍然写 import pygame。标注了 pygame-ce 的行用到了它新增的功能,其余各行在原版 pygame 中同样可用。任何代码片段都可以在 pygame 在线编辑器里试一试,它直接在浏览器中运行 pygame,无需安装。还不熟悉 Python 本身?先看 Python 速查表。

Pygame 速查表常见问题

这份 pygame 速查表免费吗?

免费,而且无需注册。把它加入书签,或者在浏览器里打印成 PDF,需要查精灵组、音效或碰撞检测的写法时随时回来看。

这份速查表同时适用于 pygame 和 pygame-ce 吗?
是的。两者都用 import pygame 导入,API 几乎完全相同。标注了 pygame-ce 的行(FRect、scale_by、get_just_pressed、文字自动换行和 move_towards_ip)需要 pygame-ce,其余内容两者都能运行。
为什么我的 pygame 窗口没有响应?
因为游戏循环没有读取事件。即使你不处理这些事件,也要每一帧调用一次 pygame.event.get(),并在每帧结尾调用 pygame.display.flip() 和 clock.tick(60)。
处理输入时该用事件还是 key.get_pressed()?
每按一次只触发一次的动作,比如跳跃或打开菜单,用 KEYDOWN 事件。按住按键期间持续进行的动作,比如行走,用 pygame.key.get_pressed()。
Coddy 编程语言插图

在 Coddy 学习 Pygame

开始