pythontextpygamecenterrect

Pygame - center text in moving rect


i'm making a drop the number game in pygame and have squares which will fall from the top of the screen to the bottom whilst having a numeric value and that number being displayed on each square. I am struggling to get the text centered on the square and it is made more difficult when each number can have 1 - 4 digits in them

class sqr:
    def __init__(self):
        self.colours = [(255,0,0), (0,255,0), (0,0,255)]
        self.Xpositions = [0,125,245,365,485]
        self.OnScreen = False
        self.X = random.choice(self.Xpositions) 
        self.Y = 0
        self.colour = random.choice(self.colours)
        self.number = random.choice([20,40,80])
        self.numberFont =  pygame.font.Font("TitilliumWeb-Black.ttf", 48)

    def drawSquare(self, colour,  X, Y):
        pygame.draw.rect(screen, colour, (X, Y, 120, 120))

    def numberTextFunc(self, X, Y):
        numberText = self.numberFont.render(f"{self.number}", True, (87, 63, 63))
        screen.blit(numberText, (X , Y))

square = sqr()

gameRunning = True
while gameRunning:

    background = screen.fill((0,100,140))
    
    #draw lines for grid
    for i in range(5):
        pygame.draw.rect(screen, (0,0,0), (line[i], 0 , 5, 800))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameRunning = False

    #square
    square.drawSquare(square.colour, square.X, square.Y)
    square.numberTextFunc(square.X, square.Y)
    square.OnScreen = True

    square.Y += 1

    if square.Y >= 680:
        square.Y = 680

    pygame.display.update()

Solution

  • Use pygame.Surface.get_rect to get the text rectangle. pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0). Set the center of the text rectangle by the center of the square. Use the text reectnagle to blit the text. The second argument of blit is either a tuple (x, y) or a rectangle. With a rectangle, only the upper left corner of the rectangle is taken into account. Therefore you can pass the text rectangle directly to blit:

    class sqr:
        # [...]
    
        def numberTextFunc(self, X, Y):
            numberText = self.numberFont.render(f"{self.number}", True, (87, 63, 63))
            rect = pygame.Rect(X, Y, 120, 120)
            textRect = numberText.get_rect(center = rect.center)
            screen.blit(numberText, textRect)
    

    You can simplify your code. X and Y are attributes of the object. Hence there is no need to pass the coordinates to the methods:

    class sqr:
        def __init__(self):
            self.colours = [(255,0,0), (0,255,0), (0,0,255)]
            self.Xpositions = [0,125,245,365,485]
            self.OnScreen = False
            self.X = random.choice(self.Xpositions) 
            self.Y = 0
            self.colour = random.choice(self.colours)
            self.number = random.choice([20,40,80])
            self.numberFont =  pygame.font.Font("TitilliumWeb-Black.ttf", 48)
    
        def drawSquare(self, colour):
            pygame.draw.rect(screen, colour, (self.X, self.Y, 120, 120))
    
        def numberTextFunc(self):
            numberText = self.numberFont.render(f"{self.number}", True, (87, 63, 63))
            rect = pygame.Rect(self.X, self.Y, 120, 120)
            textRect = numberText.get_rect(center = rect.center)
            screen.blit(numberText, textRect)
    
    gameRunning = True
    while gameRunning:
    
        background = screen.fill((0,100,140))
    
        #draw lines for grid
        for i in range(5):
            pygame.draw.rect(screen, (0,0,0), (line[i], 0 , 5, 800))
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameRunning = False
    
        #square
        square.drawSquare(square.colour)
        square.numberTextFunc()
        square.OnScreen = True
    
        square.Y += 1
        if square.Y >= 680:
            square.Y = 680
    
        pygame.display.update()