Welcome, guest | Sign In | My Account | Store | Cart

This code adjust itself for set FPS value. It is much more precise that time.sleep fps implementation.

Python, 22 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time

_tick2_frame=0
_tick2_fps=20000000 # real raw FPS
_tick2_t0=time.time()

def tick(fps=60):
 global _tick2_frame,_tick2_fps,_tick2_t0
 n=_tick2_fps/fps
 _tick2_frame+=n
 while n>0: n-=1
 if time.time()-_tick2_t0>1:
  _tick2_t0=time.time()
  _tick2_fps=_tick2_frame
  _tick2_frame=0


#test:

while True:
 tick(1) #1 frame per second
 print _tick2_fps #see adjustment in action

I am woking on game in Tkinter and I've needed precise FPS implementation. This works fine :)

5 comments

Stephen Chappell 8 years, 10 months ago  # | flag

Let me share a few other implementations and ideas with you. The first is your code readied for Python 3, and the rest are self-correcting timing algorithms. They also provide errors when they cannot run the remaining code at the frames-per-second requested. My implementation of tick uses a callback to run the rest of the program, and the Timer class is can be used similarly to how you wrote your code.

import time

_tick2_frame = 0
_tick2_fps = 20000000   # real raw FPS
_tick2_t0 = time.time()

def tick(fps=60):
    global _tick2_frame, _tick2_fps, _tick2_t0
    n = _tick2_fps / fps
    _tick2_frame += n
    while n > 0:
        n -= 1
    if time.time() - _tick2_t0 > 1:
        _tick2_t0 = time.time()
        _tick2_fps = _tick2_frame
        _tick2_frame = 0

# while True:
#     tick(1)             # 1 frame per second
#     print(_tick2_fps)   # see adjustment in action
#     print(time.time())

################################################################################

def tick(fps, callback):
    frame = 0
    start = time.perf_counter()
    while True:
        callback()
        frame += 1
        target = frame / fps
        passed = time.perf_counter() - start
        differ = target - passed
        if differ < 0:
            raise ValueError('callback was too slow')
        time.sleep(differ)

# tick(60, lambda: print(time.time()))

################################################################################

class Timer:

    def __init__(self, fps):
        self.__fps = fps
        self.__frame = 0
        self.__start = None

    def tick(self):
        if self.__start is None:
            self.__start = time.perf_counter()
        self.__frame += 1
        target = self.__frame / self.__fps
        passed = time.perf_counter() - self.__start
        differ = target - passed
        if differ < 0:
            # raise ValueError('cannot maintain desired FPS rate')
            return True
        time.sleep(differ)
        return False

timer = Timer(30)
while True:
    if timer.tick():
        raise ValueError('cannot maintain desired FPS rate')
    print(time.time())
Jiri Justra (author) 8 years, 10 months ago  # | flag

Hi, Stephen. Thanks for your comment. I am sorry, but your code seems python3-only and uses not precise time.sleep. Can you provide more in-depth explanation, pls?

Tony Flury 8 years, 8 months ago  # | flag

Jiri - the problem for most people is that your code seems to use a busy loop, which is not ideal for many applications as wastes CPU cycles - which is not great for a multi-tasking system.

Jiri Justra (author) 8 years, 8 months ago  # | flag

True, Tony. But this code is made for a game, where it is not much of concern. I needed precision for high fps animations. This did the job.

Grant Jenks 6 years, 9 months ago  # | flag

Did you consider using a generator to maintain the last tick timestamp? I think you could generate how long to sleep and then use different sleep functions. time.sleep is in the standard library but others may use gevent.sleep.

I created a number of games in Free Python Games at http://www.grantjenks.com/docs/freegames/ but I didn't worry too much about high-precision FPS. I just put a plain sleep(50) or whatever call in the code. There's definitely room for improvement but the simplicity is hard to beat.

Created by Jiri Justra on Tue, 12 May 2015 (MIT)
Python recipes (4591)
Jiri Justra's recipes (3)

Required Modules

Other Information and Tasks