Complete drawing a circle in a specific amount of time

Viewed 315

I am trying to create a countdown with a circle. The circle will show how much time has passed compared to the amount of time given. So if the countdown is 10 seconds and 5 have passed, half circle will have been drawn. I've come up with this code:

from math import pi
import pygame


pygame.init()

(x, y) = (800, 600)
screen = pygame.display.set_mode((x, y))
clock = pygame.time.Clock()

radius = 50
# Just to place the circle in the center later on
top_left_corner = ((x / 2) - (radius / 2), (y / 2) - (radius / 2))
outer_rect = pygame.Rect(top_left_corner, (radius, radius))

countdown = 1000  # seconds

angle_per_frame = 2 * pi / (countdown * 60)
angle_drawn = 0
new_angle = angle_per_frame
while True:
    if angle_drawn < 2 * pi:
        new_angle += angle_drawn + angle_per_frame
        pygame.draw.arc(screen, (255, 255, 255), outer_rect, angle_drawn, new_angle, 10)
        angle_drawn += angle_per_frame
    clock.tick(60)
    pygame.display.update(outer_rect)

So fps = 60 and in each frame I am drawing 2 * pi / countdown * fps, dividing a full circle into frames. And then in each frame, drawing a part of the circle. It seems to draw the circle fine, but it can't be used for a timer for two reasons:

  1. The circle seems to be completed in less time than given.

  2. While drawing the circle, it seems like the last part of the circle is drawn faster.

Can anyone point out what I am doing wrong?

1 Answers

The problem is that you increment new_angle by angle_drawn + angle_per_frame and because you add angle_per_frame to angle_drawn it will be bigger each frame.

I'd rather use the delta time that clock.tick returns, otherwise there could be inaccuracies if the frame rate isn't constant. Then multiply the angle_per_second value by dt to get the correct value for this frame.

Also, because pygame.draw.arc doesn't work if the difference between the angles is too small, I had to subtract 0.2 from the start angle and had to add a short delay before the drawing starts.

from math import pi
import pygame
from pygame import freetype


pygame.init()

x, y = 800, 600
screen = pygame.display.set_mode((x, y))
clock = pygame.time.Clock()
FONT = freetype.Font(None, 32)
WHITE = pygame.Color('white')

radius = 50
# Just to place the circle in the center later on
top_left_corner = (x/2 - radius/2, y/2 - radius/2)
outer_rect = pygame.Rect(top_left_corner, (radius, radius))

countdown = 10  # seconds
angle_per_second = 2*pi / countdown
angle = 0
dt = 0  # dt is the time since the last clock.tick call in seconds.
time = 0

done = False
while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    time += dt
    angle += angle_per_second * dt
    # Delay the drawing a little bit, because draw.arc doesn't work
    # with very small angle differences.
    if angle > 0.2:
        pygame.draw.arc(screen, WHITE, outer_rect, angle-0.2, angle, 10)

    rect = pygame.draw.rect(screen, (50, 50, 50), (400, 340, 100, 50))
    FONT.render_to(screen, (410, 350), str(round(time, 2)), WHITE)
    dt = clock.tick(60) / 1000  # / 1000 to convert it to seconds.
    pygame.display.update([outer_rect, rect])
Related