Menu
CoddyTech

任何帧率下都平滑

本课属于 Coddy Pygame 学习旅程的“音效与游戏体验”单元。第 19 课,共 23 课。

x += (target_x - x) * 0.1每帧移动到目标距离的十分之一。每秒 60 帧时,每秒会移动 60 步;在只能达到 30 帧的慢速电脑上,每秒只有 30 步,因此圆要花两倍时间才能到达。按 F 看看:游戏以 30 帧运行,所有移动都变得更慢。

解决方法是测量时间。clock.tick()会返回自上一帧以来经过的毫秒数。除以 1000 后得到dt,也就是这一帧的时长,单位是秒:每秒 60 帧时约为 0.017,每秒 30 帧时约为 0.033。

dt = 1 / 60          # 循环开始前
...
step = min(1, 6 * dt)
x += (target_x - x) * step
...
dt = clock.tick(fps) / 1000

帧的时间越长,移动的步长就越大,因此无论帧率是多少,圆都能在相同时间内移动相同的距离。数字 6 用来设置速度:每秒 60 帧时,6 * dt约为 0.1,也就是之前的十分之一。min(1, ...)可以防止帧时间过长时一步越过目标。

普通移动也是如此:player_x += 240 * dt表示无论帧率是多少,每秒都会移动 240 像素。大多数小游戏会用tick(60)固定帧率,因此不需要这样做;当帧率可能变化时,再使用dt。

challenge icon

挑战

中等

让缓动在任何帧率下都耗时相同。

  1. 在循环之前设置 dt = 1 / 60。
  2. 在循环末尾设置 dt = clock.tick(fps) / 1000。
  3. 在两行缓动代码中,用 step = min(1, 6 * dt) 替换 0.1:x += (target_x - x) * step。

按“开始”,点击,然后按 F 再点击:滑动所需的时间会相同。然后按“检查”。

亲手试试

import pygame

pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Any Frame Rate")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 28)

x, y = 240, 180
target_x, target_y = 240, 180
fps = 60

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            target_x, target_y = event.pos
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
            fps = 30 if fps == 60 else 60

    x += (target_x - x) * 0.1
    y += (target_y - y) * 0.1

    screen.fill((30, 30, 46))
    pygame.draw.circle(screen, (80, 200, 220), (x, y), 12)
    label = font.render(f"{fps} FPS (F to change)", True, (240, 240, 240))
    screen.blit(label, (10, 10))
    pygame.display.flip()
    clock.tick(fps)

pygame.quit()
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

音效与游戏体验中的所有课

自己练习: Pygame 在线编辑器