简体   繁体   中英

Limit loop frame rate

As like of pygame i want to limit the frame rate of a loop. Pygame provide the pygame.time.Clock.tick() way to do it:

If you pass the optional framerate argument the function will delay to keep the game running slower than the given ticks per second. This can be used to help limit the runtime speed of a game. By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second.

But how to do it natively in python ?

To illustrate:

import time

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

produce:

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

I would like 25 frames per seconds, so

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

You could just use time.sleep(1./25) to wait 1/25 of a second.

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

Note that will will always wait that time additionally to whatever time the loop body takes anyway. Alternatively, memorize the last execution time and wait until this time + 1/25 of a second.

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

Assuming that by "natively in python" you meant using the Python standard library, the time module does provide sufficient building blocks, but it rather likely not what you want. At its core, frame rate limiting is simply waiting for the right amount of time to pass:

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

The reason clock doesn't work here is that it measures processor time rather than wall time.

However, this approach has a couple of flaws:

  1. It does not synchronize to a suitable update event (such as monitor frames)
  2. The inner loop can compensate for undershooting, but not overshooting
  3. There is no facility to react to outside events here

All of which are good reasons to use more closely tied or higher level frameworks. For instance, folding the waiting time into select or similar (part of the main loop of things like asyncore or Twisted) allows fast response to events, Kivy can help you do time based animation without ever dealing with frames, and Pygame can sync with the monitor given appropriate flags as well as provide evenly spaced events (while interval timers also do this, they don't work on Windows and require signal handling).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM