pygame-core
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesepygame Core
pygame 核心内容
Build the foundation of a pygame game in Python: the main loop, delta-time
movement, drawing with /, input, and / management.
Targets pygame-ce 2.5+ (the actively maintained community fork; same
).
SurfaceRectSpriteGroupimport pygame使用Python构建pygame游戏的基础:主循环、基于delta-time的移动、/绘制、输入处理,以及/管理。
目标框架为pygame-ce 2.5+(由社区积极维护的分支;使用相同的导入方式)。
SurfaceRectSpriteGroupimport pygameWhen to use
适用场景
- Use when starting a pygame game, fixing the loop, frame-rate-dependent speed, input handling, blitting, or sprite/group collision.
- Use when code does and the project depends on
import pygame(orpygame-ce).pygame
When not to use: Python language questions unrelated to pygame. 3D rendering
(pygame is 2D). For cross-engine save/load use ; for rebindable input
architecture see .
save-systemsinput-systems- 适用于启动pygame游戏、修复循环问题、解决帧率依赖的速度问题、输入处理、绘制(blit)或精灵/组碰撞检测时。
- 适用于代码中包含且项目依赖
import pygame(或pygame-ce)的场景。pygame
不适用场景: 与pygame无关的Python语言问题。3D渲染(pygame是2D框架)。跨引擎存档/加载请使用;可重绑定输入架构请参考。
save-systemsinput-systemsCore workflow
核心工作流程
- Install pygame-ce, not legacy pygame. — it's the maintained fork and imports as
pip install pygame-ce. Don't install both in one environment.pygame - Init and open a window. ,
pygame.init(),screen = pygame.display.set_mode((w, h)).clock = pygame.time.Clock() - Run one loop: events → update → draw → flip. Pump the event queue every
frame (), update state, redraw, then
for event in pygame.event.get().pygame.display.flip() - Make it frame-rate independent. Get (seconds) and scale all motion by
dt = clock.tick(60) / 1000. Keep positions as floats; blit at integer rects.dt - Handle input two ways: event-based (/
KEYDOWN, for discrete actions) and polled (MOUSEBUTTONDOWN, for held movement).pygame.key.get_pressed() - Organise objects with +
Sprite. SubclassGroupwithpygame.sprite.Sprite/image;rectandgroup.update(dt)handle the batch. Run it and watch the window before assuming it works.group.draw(screen)
- 安装pygame-ce,而非旧版pygame。 执行——这是维护中的分支,导入方式为
pip install pygame-ce。不要在同一环境中同时安装两者。pygame - 初始化并打开窗口。 调用,
pygame.init(),screen = pygame.display.set_mode((w, h))。clock = pygame.time.Clock() - 运行单一循环:事件 → 更新 → 绘制 → 刷新。 每帧都要处理事件队列(),更新状态,重新绘制,然后调用
for event in pygame.event.get()。pygame.display.flip() - 实现帧率独立性。 获取(单位:秒),并将所有运动乘以
dt = clock.tick(60) / 1000。保持位置为浮点数;绘制时使用整数矩形。dt - 两种输入处理方式: 基于事件的方式(/
KEYDOWN,用于离散操作)和轮询方式(MOUSEBUTTONDOWN,用于持续按住的移动)。pygame.key.get_pressed() - 使用+
Sprite组织对象。 继承Group并定义pygame.sprite.Sprite/image;rect和group.update(dt)处理批量操作。运行后先查看窗口效果,不要直接假设代码正常工作。group.draw(screen)
Patterns
模式示例
1. Minimal game loop (the skeleton)
1. 最小游戏循环(框架)
python
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
running = True
while running:
dt = clock.tick(60) / 1000 # cap at 60 FPS; dt = seconds since last frame
for event in pygame.event.get(): # MUST drain the queue or the OS thinks it hung
if event.type == pygame.QUIT:
running = False
# update game state here, scaled by dt ...
screen.fill((18, 18, 28)) # clear each frame
# draw everything here ...
pygame.display.flip() # present the frame
pygame.quit()python
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
running = True
while running:
dt = clock.tick(60) / 1000 # 限制帧率为60 FPS;dt为自上一帧以来的秒数
for event in pygame.event.get(): # 必须清空事件队列,否则系统会认为程序无响应
if event.type == pygame.QUIT:
running = False
# 在此处更新游戏状态,按dt缩放...
screen.fill((18, 18, 28)) # 每帧清空屏幕
# 在此处绘制所有内容...
pygame.display.flip() # 展示当前帧
pygame.quit()2. Delta-time movement (frame-rate independent)
2. 基于delta-time的移动(帧率独立)
python
from pygame.math import Vector2
pos = Vector2(100, 100) # keep position as floats
speed = 220 # PIXELS PER SECOND, not per framepython
from pygame.math import Vector2
pos = Vector2(100, 100) # 保持位置为浮点数
speed = 220 # 像素/秒,而非像素/帧inside the loop, after computing dt:
在循环内,计算dt之后:
keys = pygame.key.get_pressed()
direction = Vector2(
keys[pygame.K_RIGHT] - keys[pygame.K_LEFT],
keys[pygame.K_DOWN] - keys[pygame.K_UP],
)
if direction.length_squared() > 0:
direction = direction.normalize() # equal speed on diagonals
pos += direction * speed * dt # RIGHT: dt-scaled
screen.blit(player_img, (round(pos.x), round(pos.y))) # blit at integer pixels
undefinedkeys = pygame.key.get_pressed()
direction = Vector2(
keys[pygame.K_RIGHT] - keys[pygame.K_LEFT],
keys[pygame.K_DOWN] - keys[pygame.K_UP],
)
if direction.length_squared() > 0:
direction = direction.normalize() # 对角线移动速度与轴向一致
pos += direction * speed * dt # 向右移动:按dt缩放
screen.blit(player_img, (round(pos.x), round(pos.y))) # 绘制到整数像素位置
undefined3. Input: events vs polling
3. 输入处理:事件 vs 轮询
python
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN: # discrete press: jump, menu, pause
if event.key == pygame.K_SPACE:
jump()
elif event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
shoot_at(event.pos) # event.pos = (x, y)python
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN: # 离散按键:跳跃、菜单、暂停
if event.key == pygame.K_SPACE:
jump()
elif event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
shoot_at(event.pos) # event.pos = (x, y)Polled state (read once per frame) for continuous/held input:
轮询状态(每帧读取一次)用于持续/按住的输入:
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
move_left(dt)
undefinedkeys = pygame.key.get_pressed()
if keys[pygame.K_a]:
move_left(dt)
undefined4. A Sprite subclass + a Group
4. Sprite子类 + Group组
python
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# convert() once at load makes blits much faster; _alpha keeps transparency.
self.image = pygame.image.load("player.png").convert_alpha()
self.rect = self.image.get_rect(center=(x, y))
self.pos = pygame.math.Vector2(self.rect.center)
self.speed = 240
def update(self, dt): # Group.update(dt) calls this per sprite
keys = pygame.key.get_pressed()
self.pos.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * self.speed * dt
self.rect.center = (round(self.pos.x), round(self.pos.y))
all_sprites = pygame.sprite.Group()
all_sprites.add(Player(400, 300))python
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# 加载时调用convert()可大幅提升绘制速度;_alpha保留透明度。
self.image = pygame.image.load("player.png").convert_alpha()
self.rect = self.image.get_rect(center=(x, y))
self.pos = pygame.math.Vector2(self.rect.center)
self.speed = 240
def update(self, dt): # Group.update(dt)会为每个Sprite调用此方法
keys = pygame.key.get_pressed()
self.pos.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * self.speed * dt
self.rect.center = (round(self.pos.x), round(self.pos.y))
all_sprites = pygame.sprite.Group()
all_sprites.add(Player(400, 300))in the loop:
在循环内:
all_sprites.update(dt) # calls each sprite's update(dt)
all_sprites.draw(screen) # blits each sprite at its rect
undefinedall_sprites.update(dt) # 调用每个Sprite的update(dt)
all_sprites.draw(screen) # 在每个Sprite的rect位置绘制
undefined5. Collision detection
5. 碰撞检测
python
undefinedpython
undefinedSprite vs group: e.g. player picking up coins (True = remove collided coins).
Sprite与组碰撞:例如玩家收集金币(True表示移除碰撞的金币)。
collected = pygame.sprite.spritecollide(player, coins, dokill=True)
score += len(collected)
collected = pygame.sprite.spritecollide(player, coins, dokill=True)
score += len(collected)
Group vs group: bullets vs enemies (kill both on hit).
组与组碰撞:子弹与敌人碰撞(碰撞时双方都销毁)。
hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
Plain rect overlap (no sprites needed):
普通矩形重叠(无需Sprite):
if player.rect.colliderect(door_rect):
open_door()
undefinedif player.rect.colliderect(door_rect):
open_door()
undefinedPitfalls
常见陷阱
- Window freezes / "not responding" → you didn't pump the event queue. Call
(or
pygame.event.get()) every frame.pygame.event.pump() - Speed differs on faster machines → you moved by a fixed amount per frame.
Scale by and use pixels-per-second values.
dt = clock.tick(fps) / 1000 - Sub-pixel movement snaps/jitters → coordinates are integers; store the true position as a
rectof floats and assignVector2each frame.rect.center = round(...) - Blits are slow / framerate drops → call (opaque) or
.convert()(transparent) on loaded images once; un-converted surfaces blit far slower..convert_alpha() - Nothing appears → you forgot (or
pygame.display.flip()), or you drew beforeupdate()so it was cleared away.screen.fill(...) - Wrong draw order → pygame uses painter's order; later blits cover earlier ones. Draw background first, sprites last.
- got the old one → for the maintained fork use
pip install pygame; having both installed causes import conflicts.pip install pygame-ce - Diagonal movement is faster → normalise the direction vector before scaling by speed.
- 窗口冻结/"未响应" → 你没有处理事件队列。每帧都要调用(或
pygame.event.get())。pygame.event.pump() - 在更快的机器上速度不同 → 你每帧移动固定距离。应使用缩放,并使用像素/秒的速度值。
dt = clock.tick(fps) / 1000 - 亚像素移动出现跳跃/抖动 → 坐标是整数;将实际位置存储为
rect浮点数,每帧赋值Vector2。rect.center = round(...) - 绘制(blit)缓慢/帧率下降 → 加载图像时调用一次(不透明)或
.convert()(透明);未转换的Surface绘制速度慢得多。.convert_alpha() - 没有内容显示 → 你忘记调用(或
pygame.display.flip()),或者在update()之前绘制,导致内容被清空。screen.fill(...) - 绘制顺序错误 → pygame遵循画家算法;后续绘制会覆盖之前的内容。先绘制背景,最后绘制精灵。
- 安装了旧版本 → 要安装维护中的分支,请使用
pip install pygame;同时安装两者会导致导入冲突。pip install pygame-ce - 对角线移动速度更快 → 在按速度缩放之前,先对方向向量进行归一化。
References
参考资料
- For variants (
Group,GroupSinglefor z-order), pixel-perfect collision withLayeredUpdates, slicing a spritesheet, simple animation, sound/music, and text rendering, readmask.references/sprites-and-collision.md
- 关于的变体(
Group、用于层级排序的GroupSingle)、基于LayeredUpdates的像素完美碰撞、精灵切片、简单动画、声音/音乐以及文本渲染,请阅读mask。references/sprites-and-collision.md
Related skills
相关技能
- — the same loop concepts in LÖVE/Lua.
love2d-core - — a heavier ECS engine when a project outgrows pygame.
bevy-ecs - /
input-systems— engine-agnostic input and persistence.save-systems - /
platformer— genre templates that pair with pygame.roguelike
- —— 在LÖVE/Lua中使用相同的循环概念。
love2d-core - —— 当项目超出pygame的能力范围时,可使用这款更重量级的ECS引擎。
bevy-ecs - /
input-systems—— 与引擎无关的输入和持久化系统。save-systems - /
platformer—— 与pygame搭配使用的类型模板。roguelike