Home > database >  Problems with detecting delay and removing it from .after() in python
Problems with detecting delay and removing it from .after() in python

Time:02-21

I am developing a Tkinter python game - long story short it needs to be able to run at different FPS values. However, I am having trouble maintaining a consistent second length.

I have tried to make it detect lag and take it away from the .after() function:

def UpdatesEveryFrame():
    s = time.perf_counter()

    # Code here

    s = int((time.perf_counter()  - s)*1000)
    LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame)

However, this is unsuccessful. It seems to create an accurate value in milliseconds (usually around 15) but this does not make an accurate second delay. I have tried replacing perf_counter() with time() but this has the same effect.

Because of what the game is based upon, it is essential that there is an accurate second delay. Can you help? Thanks.

CodePudding user response:

If the goal here is precision, then perhaps you should try the time.perf_counter_ns method of the time module, it specifically is made to be more precise than time.perf_counter, and gives time in nanoseconds, further if the time has to be converted back into seconds, it can be done using unit conversion.

Further, the documentation of time.perf_counter method mentions this as well -:

Use perf_counter_ns() to avoid the precision loss caused by the float type.

def UpdatesEveryFrame():
    s = time.perf_counter_ns()/(10 ** 9) # used perf_counter_ns, divided by (10 ** 9) to convert to seconds.

    # Code here

    s = int((time.perf_counter_ns()/(10 ** 9) - s)*1000) # used perf_counter_ns, divided by (10 ** 9) to convert to seconds.
    LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame)

EDIT: There also exists time.monotonic method, designed specifically to measure the time elapsed between two consecutive calls, it returns time in fractional seconds similar to time.perf_counter, so no changes have to be made in the current code except the name of the function itself.

def UpdatesEveryFrame():
    s = time.monotonic() # Changed method name.

    # Code here

    s = int((time.monotonic()  - s)*1000)
    LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame) # Changed method name.
  • Related