1

In my main loop I have:

clock.tick_busy_loop(60)
pygame.display.set_caption("fps: " + str(clock.get_fps()))

However, the readout says the game is reading at 62.5fps. I then tried to input clock.tick_busy_loop(57.5), which gave me a readout of 58.82...fps. When I set clock.tick_busy_loop(59) I get 62.5fps again. It looks like there is a threshold between 58.8fps and 62.5fps that I can't overcome here. How do I get my game to actually run at 60fps? I'm mainly looking for this kind of control because I executing events that are contingent on musical timing.

Null Salad
  • 765
  • 2
  • 16
  • 31
  • 1
    use time instead of fps to control events. Even if you get 60fps on your computer I may get only 30fps on mine - and your program will be useless for me. – furas Oct 17 '16 at 01:33
  • isn't Clock a subclass of pygame.time? Or are you suggesting not using Clock and calculating the system's time? – Null Salad Oct 17 '16 at 01:42
  • use [pygame.time.get_ticks()](http://www.pygame.org/docs/ref/time.html#pygame.time.get_ticks) and `if pygame.time.get_ticks() >= previous_execution + delay: execute_event()` to control events. It will work on fast computer with 60fps and on slow computer with 30fps. – furas Oct 17 '16 at 02:04
  • I would suggest you use the system time with import time and time.time() and delay as needed as appropriate with time.sleep(). The pygame library is built using SDL, whose timer resolution is poor and is basically on the millisecond range. The reason why you fluctuate between 62.5 and 58.82 is because you are either waiting 16 or 17 ms respectively between frames (hint: divide 1000 by each of those ms times). – CodeSurgeon Oct 17 '16 at 02:06

1 Answers1

2

So I whipped up a simple demo based on my comment above that uses the system time module instead of the pygame.time module. You can ignore the OpenGL stuff as I just wanted to render something simple on screen. The most important part is the timing code at the end of each frame, which I have commented about in the code.

import pygame
import sys
import time
from OpenGL.GL import *
from OpenGL.GLU import *

title = "FPS Timer Demo"
target_fps = 60
(width, height) = (300, 200)
flags = pygame.DOUBLEBUF|pygame.OPENGL
screen = pygame.display.set_mode((width, height), flags)

rotation = 0
square_size = 50
prev_time = time.time()

while True:
    #Handle the events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    #Do computations and render stuff on screen
    rotation += 1
    glClear(GL_COLOR_BUFFER_BIT)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, width, 0, height, -1, 1)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslate(width/2.0, height/2.0, 0)
    glRotate(rotation, 0, 0, 1)
    glTranslate(-square_size/2.0, -square_size/2.0, 0)
    glBegin(GL_QUADS)
    glVertex(0, 0, 0)
    glVertex(50, 0, 0)
    glVertex(50, 50, 0)
    glVertex(0, 50, 0)
    glEnd()
    pygame.display.flip()

    #Timing code at the END!
    curr_time = time.time()#so now we have time after processing
    diff = curr_time - prev_time#frame took this much time to process and render
    delay = max(1.0/target_fps - diff, 0)#if we finished early, wait the remaining time to desired fps, else wait 0 ms!
    time.sleep(delay)
    fps = 1.0/(delay + diff)#fps is based on total time ("processing" diff time + "wasted" delay time)
    prev_time = curr_time
    pygame.display.set_caption("{0}: {1:.2f}".format(title, fps))
CodeSurgeon
  • 2,435
  • 2
  • 15
  • 36
  • This works great though for reasons that escape me I have to half the framerate for it to be synchronous with my audio. Seems to work though! – Null Salad Oct 27 '16 at 20:35
  • @NullSalad Glad it works for you! That does seem to be an odd issue. Post a question about it with your sample and I will take a look at it. – CodeSurgeon Oct 28 '16 at 01:23