How to make a circular countdown timer in Pygame?

Question:

How can i make this kind of countdown in Pygame? (i’m looking for how could i make the circle’s perimeter decrease, that’s the issue, because displaying the time isn’t hard )
Keep in mind that how long the perimeter of the circle is and the displayed time should be in proportion with each other.

Asked By: Salem

||

Answers:

Just use pygame.draw.arc and specify the stop_angle argument depending on the counter:

percentage = counter/100
end_angle = 2 * math.pi * percentage
pygame.draw.arc(window, (255, 0, 0), arc_rect, 0, end_angle, 10)

Minimal example:

import pygame
import math

pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
counter = 100
text = font.render(str(counter), True, (0, 128, 0))

timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, 1000)

def drawArc(surf, color, center, radius, width, end_angle):
    arc_rect = pygame.Rect(0, 0, radius*2, radius*2)
    arc_rect.center = center
    pygame.draw.arc(surf, color, arc_rect, 0, end_angle, width)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == timer_event:
            counter -= 1
            text = font.render(str(counter), True, (0, 128, 0))
            if counter == 0:
                pygame.time.set_timer(timer_event, 0)                

    window.fill((255, 255, 255))
    text_rect = text.get_rect(center = window.get_rect().center)
    window.blit(text, text_rect)
    drawArc(window, (255, 0, 0), (100, 100), 90, 10, 2*math.pi*counter/100)
    pygame.display.flip()

pygame.quit()
exit()

Sadly the quality of pygame.draw.arc with a width > 1 is poor. However this can be improved, using cv2 and cv2.ellipse:

import pygame
import cv2
import numpy

pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
counter = 100
text = font.render(str(counter), True, (0, 128, 0))

timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, 1000)

def drawArcCv2(surf, color, center, radius, width, end_angle):
    circle_image = numpy.zeros((radius*2+4, radius*2+4, 4), dtype = numpy.uint8)
    circle_image = cv2.ellipse(circle_image, (radius+2, radius+2),
        (radius-width//2, radius-width//2), 0, 0, end_angle, (*color, 255), width, lineType=cv2.LINE_AA) 
    circle_surface = pygame.image.frombuffer(circle_image.flatten(), (radius*2+4, radius*2+4), 'RGBA')
    surf.blit(circle_surface, circle_surface.get_rect(center = center), special_flags=pygame.BLEND_PREMULTIPLIED)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == timer_event:
            counter -= 1
            text = font.render(str(counter), True, (0, 128, 0))
            if counter == 0:
                pygame.time.set_timer(timer_event, 0)                

    window.fill((255, 255, 255))
    text_rect = text.get_rect(center = window.get_rect().center)
    window.blit(text, text_rect)
    drawArcCv2(window, (255, 0, 0), (100, 100), 90, 10, 360*counter/100)
    pygame.display.flip()

pygame.quit()
exit()
Answered By: Rabbid76
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.