Reputation: 87
I'm trying to create a Tabata or HIIT timer with pygame. Essentially I want to count up and down in seconds and display the time either elapsed or remaining. I modified code I found here http://www.pygame.org/project-Countdown-1237-.html
I was having problems having accurate time display with the standard code linked above. It was not accurate at all. Maybe 2 seconds elapsed for every second updated on the screen. So the countdown would be twice as long. So I modified the code to get a more accurate time count.
First I'm not sure this is the best way to go about this. Eventually I will want to have rounds where the up and down counters repeat. My biggest problem is that after about 2 minutes the time is off. So true elapsed time might be 2:00 minutes but the interval timers are a second or two behind. It continues to get worse as the timer continues to run where the displayed time continues to be n seconds behind true elapsed time. Any help would be greatly appreciated. I've seen people use pygame.time but not sure that gets me any closer to what I need to accomplish
Thanks
#!/usr/bin/env python
import time
import pygame
from pygame.locals import *
import sys, os
if sys.platform == 'win32' or sys.platform == 'win64':
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
Screen = max(pygame.display.list_modes())
icon = pygame.Surface((1,1)); icon.set_alpha(0); pygame.display.set_icon(icon)
pygame.display.set_caption("[Program] - [Author] - [Version] - [Date]")
Surface = pygame.display.set_mode(Screen,FULLSCREEN)
black = 0,0,0
red = 255,0,0
white = 255,255,255
green = 0,75,0
orange = 175,75,0
Font = pygame.font.Font("font.ttf",1000)
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
test = Font.render("0",True,(255,255,255))
width = test.get_width()
height = test.get_height()
totalwidth = 4.5 * width
timerCountDown = 1
timerCountUp = 1
preTimerCountdown = 1
def quit():
pygame.mouse.set_visible(True)
pygame.event.set_grab(False)
pygame.quit(); sys.exit()
def GetInput():
key = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE: quit()
def CountUp(startTime,timeDuration,backgroundColor):
Surface.fill(backgroundColor)
start_pos = (Screen[0]/2)-(totalwidth/2)
currentTime = time.time()
elapsedTime = currentTime - startTime
displayTime = time.strftime('%M:%S', time.gmtime(elapsedTime)) #'%H:%M:%S'
pos = [start_pos,(Screen[1]/2)-(height/2)]
timeDuration = time.strftime('%M:%S', time.gmtime(timeDuration))
Surface.blit(Font.render(displayTime,True,(white)),pos)
pygame.display.flip()
if displayTime == timeDuration:
time.sleep(0)
#quit()
global timerCountUp
timerCountUp = 0
startTime = currentTime
def CountDown(startTime,timeDuration,backgroundColor):
Surface.fill(backgroundColor)
startTime = startTime +1
start_pos = (Screen[0]/2)-(totalwidth/2)
currentTime = time.time()
elapsedTime = currentTime - startTime
displayTime = timeDuration - elapsedTime
displayTime = time.strftime('%M:%S', time.gmtime(displayTime)) #'%H:%M:%S'
pos = [start_pos,(Screen[1]/2)-(height/2)]
timeDuration = time.strftime('%M:%S', time.gmtime(timeDuration + 1))
Surface.blit(Font.render(displayTime,True,(white)),pos)
pygame.display.flip()
if displayTime == "00:00":
global timerCountDown
timerCountDown = 0
startTime = currentTime
def main():
startTime = time.time()
Clock = pygame.time.Clock()
global timerCountUp
timerCountUp = 1
global timerCountDown
timerCountDown = 1
global preTimerCountdown
preTimerCountdown = 1
while True:
GetInput()
Clock.tick(60)
while timerCountUp != 0:
CountUp(startTime,7,green)
GetInput()
global timerCountDown
timerCountDown = 1
startTime = time.time()
while timerCountDown != 0:
CountDown(startTime,3,orange)
GetInput()
global timerCountUp
timerCountUp = 1
startTime = time.time()
if __name__ == '__main__': main()
Upvotes: 0
Views: 3054
Reputation: 11190
Your delay comes from 2 places.
The call to Clock.tick(60)
sleeps for a fraction of a second to ensure, that it is called 60 times per second. In your case, you should remove it since you are not calling this function every frame.
The bigger delay comes from the fact, that each function call takes some time, and you are not taking this into account.
You are also sleeping at the end of a timer for 1 second. This is not accurate.
I suggest for you to keep track of how many ms more a timer took, and subtract that from your next timer.
Upvotes: 3