限制循环帧率

4 投票
2 回答
10220 浏览
提问于 2025-04-20 15:31

就像在pygame中一样,我想限制一个循环的帧率。Pygame提供了pygame.time.Clock.tick()这个方法来实现:

如果你传入一个可选的帧率参数,这个函数会延迟执行,以保持游戏的运行速度低于指定的每秒帧数。这可以帮助限制游戏的运行速度。通过每帧调用Clock.tick(40),程序的帧率永远不会超过每秒40帧。

但是在Python中怎么原生实现呢?

举个例子:

import time

max_frames = 125 # 25*5
current_frame = 1
while current_frame <= max_frames:
    print('frame', time.clock(), current_frame)
    current_frame += 1

产生:

('frame', 0.01, 1)
('frame', 0.01, 2)
('frame', 0.01, 3)
[...]
('frame', 0.01, 124)
('frame', 0.01, 125)

我想要每秒25帧,所以

('frame', 0.01, 1)
('frame', 0.05, 2)
('frame', 0.08, 3)
[...]
('frame', 4.98, 124)
('frame', 5.00, 125)

2 个回答

3

假设你所说的“在Python中原生实现”是指使用Python的标准库,那么time模块确实提供了一些基本的工具,但这可能并不是你想要的。简单来说,限制帧率就是要等到合适的时间过去:

from time import time, sleep

fps=5
frameperiod=1.0/fps
now=time()
nextframe=now+frameperiod
for frame in range(120):
  print frame, now
  while now<nextframe:
    sleep(nextframe-now)
    now=time()
  nextframe+=frameperiod

之所以说clock在这里不管用,是因为它测量的是处理器时间,而不是实际经过的时间。

不过,这种方法有几个缺点:

  1. 它没有和合适的更新事件(比如显示器的帧)同步
  2. 内部循环可以弥补时间不足的情况,但无法处理时间过长的情况
  3. 这里没有办法对外部事件做出反应

这些都是使用更高级或更紧密结合的框架的好理由。例如,把等待时间放入select或类似的工具中(这些是像asyncore或Twisted这样的主要循环的一部分),可以快速响应事件;Kivy可以帮助你实现基于时间的动画,而不需要处理帧;Pygame可以根据适当的标志与显示器同步,并提供均匀间隔的事件(虽然间隔定时器也能做到这一点,但它们在Windows上不工作,并且需要信号处理)。

7

你可以直接用 time.sleep(1./25) 来等待 1/25 秒。

while current_frame <= max_frames:
    # ... do stuff 
    time.sleep(1./25)

请注意,这样做会在循环体执行的时间之外,额外再等待这个时间。或者,你可以记住上一次执行的时间,然后等到 这个时间 + 1/25 秒再继续。

while current_frame <= max_frames:
    start = time.time()
    # ... do stuff that might take significant time
    time.sleep(max(1./25 - (time.time() - start), 0))

撰写回答