Python Forum

Full Version: Pygame writing using fonts and labels
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

I have created a game which has an error in the display of the label when I want to close the pygame window, my pygame window is not the problem as it closes fine but I have come across an issue in the output of the label. I have abstracted the code down to deal with the problem at hand. Can someone please point out my mistake.

import pygame
import time

#pygame initialisation
pygame.init()

def cover(BACKGROUND, screen):
    # This is a library function built in which displays the selected shape - this case a rectangle
    pygame.draw.rect(screen, BACKGROUND, (0, 0, 640, 80))
    
def font():
    #set font for later on use for declaring a window
    Select_Font = pygame.font.SysFont('arial', 70)
    return Select_Font

#Set Colours
Colour_Countdown = (0, 255, 0)
BACKGROUND = (0, 0, 0)

#pygame window setting
screen_size = (640, 640)
screen = pygame.display.set_mode(screen_size)

#setting font for test
LabelFont = font()


#code with possible error
cover(BACKGROUND, screen)
label = LabelFont.render("Closing in ...", 1, Colour_Countdown) #print ("Closing in ...")                                                                                                                                                                                   screen.blit(label, (20,-5))
screen.blit(label, (20,-5))
pygame.time.wait(1000)
cover(BACKGROUND, screen)
label = LabelFont.render("3", 1, Colour_Countdown) #print ("3")
screen.blit(label, (20,-5))
pygame.time.wait(1000)
cover(BACKGROUND, screen)
label = LabelFont.render("2", 1, Colour_Countdown) #print ("2")
screen.blit(label, (20,-5))
pygame.time.wait(1000)
cover(BACKGROUND, screen)
label = LabelFont.render("1", 1, Colour_Countdown) #print ("1")    
screen.blit(label, (20,-5))
pygame.time.wait(1000)
pygame.quit()
Thanks for the long running support
I just get a blank screen with your program. I also do not get an error at all.

Ideally you should have a main game loop and use a ticks from the game to determine seconds. This i believe is what you are trying to accomplish?

import pygame as pg
import random
 
pg.init()
 
screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
done = False
 
class Number:
    def __init__(self, number):
        self.timer = 0.0
        self.delay = 1000
        self.number = number
        self.new_num()
 
    def new_num(self):
        self.image, self.rect = self.make_text('Closing in {}'.format(self.number), (255,0,0), screen_rect.center, 75, 'Ariel')
        self.number -= 1
 
    def make_text(self,message,color,center,size, fonttype):
        font = pg.font.SysFont(fonttype, size)
        text = font.render(message,True,color)
        rect = text.get_rect(center=center)
        return text,rect
 
    def update(self): 
        if pg.time.get_ticks()-self.timer > self.delay:
            self.timer = pg.time.get_ticks()
            self.new_num()
        if self.number < 0:
            return True

    def draw(self, surf):
        surf.blit(self.image, self.rect)
 
num = Number(3)
 
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
    screen.fill((0,0,0))
    close = num.update()
    if close:
        done = True
    num.draw(screen)
    pg.display.update()
    clock.tick(60)
In this way you can also change the number in the parenthesis to increase it.
Here my example.
import os
import pygame
from types import SimpleNamespace
from pygame.sprite import Sprite, Group

# Wrap pygame builtin colors into namespace.
color = SimpleNamespace(**pygame.color.THECOLORS)

# Interface
class Scene:
    def __init__(self, manager):
        self.manager = manager

    def on_draw(self, surface): pass
    def on_event(self, event): pass
    def on_update(self, delta): pass

    def on_quit(self):
        self.manager.quit()

# Handles what scene is active
class Manager:
    def __init__(self, caption, width, height, center=True, flags=0):
        if center:
            os.environ['SDL_VIDEO_CENTERED'] = '1'

        # Basic pygame setup
        pygame.display.set_caption(caption)
        self.surface = pygame.display.set_mode((width, height), flags)
        self.rect = self.surface.get_rect()
        self.clock = pygame.time.Clock()
        self.running = False
        self.delta = 0
        self.fps = 60

        self.scene = Scene(self)

    def mainloop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.scene.on_quit()
                else:
                    self.scene.on_event(event)

            self.scene.on_update(self.delta)
            self.scene.on_draw(self.surface)
            pygame.display.flip()
            self.delta = self.clock.tick(self.fps)

    def quit(self):
        self.running = False

class Label(Sprite):
    def __init__(self, text, font, color, position, anchor="topleft"):
        Sprite.__init__(self)
        self._text = text
        self._font = font
        self._color = color
        self._anchor = anchor
        self._position = pygame.Vector2(position)
        self.render()

    def render(self):
        self.image = self._font.render(self._text, 1, self._color)
        self.rect = self.image.get_rect(**{self._anchor: self._position})

    def set_text(self, text):
        self._text = text
        self.render()

class Timer:
    def __init__(self, interval, callback, user_data=None):
        self.tick = pygame.time.get_ticks() + interval
        self.interval = interval
        self.callback = callback
        self.user_data = user_data

    def expire(self, ticks):
        if ticks > self.tick:
            return True

        return False

    def update(self, ticks):
        if ticks > self.tick:
            self.callback(self)
            self.tick += self.interval

class CountDown:
    def __init__(self, count, update_callback, callback, interval=1000):
        self.timer = Timer(interval, self.timer_update)
        self.count = count
        self.callback = callback
        self.update_callback = update_callback

    def timer_update(self, timer):
        self.count -= 1
        if self.count < 1:
            self.callback()
        else:
            self.update_callback(self)

    def update(self, ticks):
        self.timer.update(ticks)

class MainScene(Scene):
    def __init__(self, manager):
        Scene.__init__(self, manager)
        position = manager.rect.centerx, 20
        self.font = pygame.font.Font(None, 32)
        self.label = Label("Welcome", self.font, color.dodgerblue, position, "midtop")
        self.quit_label = None
        self.quit_countdown = None
        self.sprites = Group(self.label)

    def on_draw(self, surface):
        surface.fill(color.black)
        self.sprites.draw(surface)

    def on_quit(self):
        if self.quit_countdown is None:
            self.quit_countdown = CountDown(5, self.update_countdown_label, self.manager.quit)
            self.update_countdown_label(self.quit_countdown)

    def on_update(self, delta):
        ticks = pygame.time.get_ticks()
        if self.quit_countdown:
            self.quit_countdown.update(ticks)

    def update_countdown_label(self, countdown):
        text = "Closing in ... {}"
        if self.quit_label:
            self.quit_label.set_text(text.format(countdown.count))
        else:
            self.quit_label = Label(text.format(countdown.count), self.font,
                              color.firebrick, self.manager.rect.center, "center")
            self.quit_label.add(self.sprites)

if __name__ == "__main__":
    pygame.init()
    manager = Manager("Countdown Example", 800, 600)
    manager.scene = MainScene(manager)
    manager.mainloop()