【问题标题】:pygame - How to display text with font & color?pygame - 如何显示带有字体和颜色的文本?
【发布时间】:2022-07-28 23:12:55
【问题描述】:

有没有办法可以使用 python 在 pygame 窗口上显示文本?

我需要显示一堆更新的实时信息,而不是为我需要的每个角色制作图像。

我可以将文本 blit 到屏幕吗?

【问题讨论】:

标签: python pygame


【解决方案1】:

是的。可以在 pygame 中绘制文本:

# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 15)

# render text
label = myfont.render("Some text!", 1, (255,255,0))
screen.blit(label, (100, 100))

【讨论】:

  • 好的,如果计算机上没有安装字体,我可以安装一种字体吗?
  • 我不确定,但看起来你可以。根据font.SysFont 的文档,它从系统字体 (pygame.org/docs/ref/font.html#pygame.font.SysFont) 加载字体。
  • @maxhud:是的。使用pygame.font.Font("path/to/font.ttf",size)
【解决方案2】:

您可以通过使用pygame.font.Font设置字体路径来使用您自己的自定义字体

pygame.font.Font(filename, size): return Font

例子:

pygame.font.init()
font_path = "./fonts/newfont.ttf"
font_size = 32
fontObj = pygame.font.Font(font_path, font_size)

然后使用 fontObj.render 渲染字体并 blit 到表面,如上面的 veiset 的回答。 :)

【讨论】:

    【解决方案3】:

    我的游戏中有一些代码可以显示实时比分。它具有快速访问功能。

    def texts(score):
       font=pygame.font.Font(None,30)
       scoretext=font.render("Score:"+str(score), 1,(255,255,255))
       screen.blit(scoretext, (500, 457))
    

    我在我的 while 循环中使用它来调用它:

    texts(score)
    

    【讨论】:

    • 这样每次都会创建一个Font对象,浪费处理周期。
    • 我建议对您使用的字体大小进行缓存。只需定义一个字典并这样做:如果 self.fonts.get(size) 为 None: self.fonts[size] = pygame.font.SysFont(None, size)
    【解决方案4】:

    有两种可能性。在任何一种情况下,PyGame 都必须由 pygame.init 初始化。

    import pygame
    pygame.init()
    

    使用 pygame.font 模块并创建一个 pygame.font.SysFontpygame.font.Font 对象。 render()pygame.Surface正文和blit表面到屏幕:

    my_font = pygame.font.SysFont(None, 50)
    text_surface = myfont.render("Hello world!", True, (255, 0, 0))
    screen.blit(text_surface, (10, 10))
    

    或者使用 pygame.freetype 模块。创建一个 pygame.freetype.SysFont()pygame.freetype.Font 对象。 render()pygame.Surface带文字或直接render_to()将文字显示到屏幕上:

    my_ft_font = pygame.freetype.SysFont('Times New Roman', 50)
    my_ft_font.render_to(screen, (10, 10), "Hello world!", (255, 0, 0))
    

    另见Text and font


    最小 pygame.font 示例: repl.it/@Rabbid76/PyGame-Text

    import pygame
    
    pygame.init()
    window = pygame.display.set_mode((500, 150))
    clock = pygame.time.Clock()
    
    font = pygame.font.SysFont(None, 100)
    text = font.render('Hello World', True, (255, 0, 0))
    
    background = pygame.Surface(window.get_size())
    ts, w, h, c1, c2 = 50, *window.get_size(), (128, 128, 128), (64, 64, 64)
    tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
    for rect, color in tiles:
        pygame.draw.rect(background, color, rect)
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        window.blit(background, (0, 0))
        window.blit(text, text.get_rect(center = window.get_rect().center))
        pygame.display.flip()
    
    pygame.quit()
    exit()
    

    最小 pygame.freetype 示例: repl.it/@Rabbid76/PyGame-FreeTypeText

    import pygame
    import pygame.freetype
    
    pygame.init()
    window = pygame.display.set_mode((500, 150))
    clock = pygame.time.Clock()
    
    ft_font = pygame.freetype.SysFont('Times New Roman', 80)
    
    background = pygame.Surface(window.get_size())
    ts, w, h, c1, c2 = 50, *window.get_size(), (128, 128, 128), (64, 64, 64)
    tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
    for rect, color in tiles:
        pygame.draw.rect(background, color, rect)
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        window.blit(background, (0, 0))
        text_rect = ft_font.get_rect('Hello World')
        text_rect.center = window.get_rect().center
        ft_font.render_to(window, text_rect.topleft, 'Hello World', (255, 0, 0))
        pygame.display.flip()
    
    pygame.quit()
    exit()
    

    【讨论】:

      【解决方案5】:

      我写了一个包装器,它将缓存文本表面,只有在变脏时才重新渲染。 googlecode/ninmonkey/nin.text/demo/

      【讨论】:

      • 这是如何回答问题的?
      【解决方案6】:

      我写了一个 TextBox 类。它可以相对容易地使用许多自定义字体并指定颜色。 我想在屏幕上的几个地方显示文字,其中一些会更新例如生命、分数(所有玩家的)高分、经过的时间等等。

      首先,我在项目中创建了一个 fonts 文件夹并加载了我想使用的字体。例如,我的 fots 文件夹中有“arcade.ttf”。在制作 TextBox 的实例时,我可以使用字体位置(可选)arg 指定该字体。

      例如

      self.game_over_text = TextBox("GAME OVER", 100, 80, 420, RED, 'fonts/arcade.ttf')
      

      我发现制作文本并在每次“笨拙”时更新它,所以我的解决方案是 update_text 方法。

      例如,更新玩家得分:

      self.score1_text.update_text(f'{self.p1.score}')
      

      它可以重构为接受 str 列表,但它适合我编写“S”版本的需要

      # -*- coding: utf-8 -*-
      '''
       @author:   srattigan
       @date:     22-Mar-2022
       @project:  TextBox class example
       @description:  A generic text box class 
                  to simplify text objects in PyGame
                  Fonts can be downloaded from
                  https://www.dafont.com/ 
                  and other such sites.
      '''
      
      # imports
      import pygame
      
      # initialise and globals
      WHITE = (255, 255, 255)
      pygame.font.init() # you have to call this at the start
      
       
      class TextBox:
          '''
          A text box class to simplify creating text in pygame
          '''
          def __init__(self, text, size, x=50, y=50, color=WHITE, fontlocation=None):
              '''
              Constuctor
              text: str, the text to be displayed
              size: int, the font size
              x: int, x-position on the screen
              y: int, y-position on the screen
              color: tuple of int representing color, default is (255,255,255)
              fontlocation: str, location of font file.  If None, default system font is used.
              '''
              pygame.font.init()
              self.text = text
              self.size = size
              self.color = color
              self.x = x
              self.y = y
              if fontlocation == None:
                  self.font = pygame.font.SysFont('Arial', self.size)
              else:
                  self.font = pygame.font.Font(fontlocation, self.size)
      
          def draw(self, screen):
              '''
              Draws the text box to the screen passed.
              screen: a pygame Surface object
              '''
              text_surface = self.font.render(f'{self.text}', False, self.color)
              screen.blit(text_surface, [self.x, self.y])
      
          def update_text(self, new_text):
              '''
              Modifier- Updates the text variable in the textbox instance
              new_text: str, the updated str for the instance.
              '''
              if not isinstance(new_text, str):
                  raise TypeError("Invalid type for text object")
              self.text = new_text
      
          def set_position(self, x, y):
              '''
              Modifier- change or set the position of the txt box
              x: int, x-position on the screen
              y: int, y-position on the screen
              '''
              self.x = x
              self.y = y
      
          def __repr__(self):
              rep = f'TextBox instance, 
      	text: {self.text} 
      	FontFamly:{self.font} 
      	Color: {self.color} 
      	Size: {self.size} 
      	Pos: {self.x, self.y}'
              return rep
      
      if __name__ == "__main__":
          test = TextBox("Hello World", 30, 30, 30)
          print(test)
      

      在我的游戏类中使用它

      from textbox import TextBox
      

      在游戏的初始化部分,是这样的:

      self.time_text = TextBox("Time Left: 100", 20, 20, 40)
      self.cred_text = TextBox("created by Sean R.", 15, 600, 870)
      self.score1_text = TextBox("0", 100, 40, 650)
      self.score2_text = TextBox("0", 100, 660, 650)
      self.lives1_text = TextBox("[P1] Lives: 3", 20, 40, 750)
      self.lives2_text = TextBox("[P2] Lives: 3", 20, 660, 750)
      self.game_over_text = TextBox("GAME OVER", 100, 80, 420, RED)
      
      self.textbox_list = []
      self.textbox_list.append(self.time_text)
      self.textbox_list.append(self.cred_text)
      self.textbox_list.append(self.score1_text)
      self.textbox_list.append(self.score2_text)
      self.textbox_list.append(self.lives1_text)
      self.textbox_list.append(self.lives2_text)
      

      这样当我想在屏幕上绘制所有内容时:

      for txt in self.textbox_list:
          txt.draw(screen)
      

      在游戏的更新部分,我只使用 update_text 方法直接更新已更新文本的框 - 如果没有要更新的内容,文本将保持不变。

      【讨论】:

        【解决方案7】:

        我写了一个TextElement 类来处理文本放置。它仍有改进的余地。要改进的一件事是使用 SysFont 添加后备字体,以防字体资源不可用。

        import os
        from typing import Tuple, Union
        from pygame.font import Font
        from utils.color import Color
        
        
        class TextElement:
            TEXT_SIZE = 50
        
            def __init__(self, surface, size=TEXT_SIZE, color=Color('white'), font_name='Kanit-Medium') -> None:
                self.surface = surface
                self._font_name = font_name
                self._size = size
                self.color = color
                self.font = self.__initialize_font()
        
            @property
            def font_name(self):
                return self._font_name
        
            @font_name.setter
            def font_name(self, font_name):
                self._font_name = font_name
                self.font = self.__initialize_font()
        
            @font_name.deleter
            def font_name(self):
                del self._font_name
        
            @property
            def size(self):
                return self._size
        
            @size.setter
            def size(self, size):
                self._size = size
                self.font = self.__initialize_font()
        
            @size.deleter
            def size(self):
                del self._size
        
            def write(self, text: str, coordinates: Union[str, Tuple[int, int]] = 'center'):
                rendered_text = self.font.render(text, True, self.color)
                if isinstance(coordinates, str):
                    coordinates = self.__calculate_alignment(rendered_text, coordinates)
                self.surface.blit(rendered_text, coordinates)
                return self
        
        
            def __calculate_alignment(self, rendered_text, alignment):
                # https://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
                # Aligns rendered_text to the surface at the given alignment position
                # e.g: rendered_text.get_rect(center=self.surface.get_rect().center)
                alignment_coordinates = getattr(self.surface.get_rect(), alignment)
                return getattr(rendered_text, 'get_rect')(**{alignment: alignment_coordinates}).topleft
        
            def __initialize_font(self):
                return Font(os.path.join(
                    'assets', 'fonts', f'{self._font_name}.ttf'), self._size)
        
        

        以下是如何使用它:

          TextElement(self.screen, 80).write('Hello World!', 'midtop')
          TextElement(self.screen).write('Hello World 2!', (250, 100))
        
          # OR
        
          text = TextElement(self.screen, 80)
          text.size = 100
          text.write('Bigger text!', (25, 50))
          text.write('Bigger text!', 'midbottom')
        

        我希望这可以帮助别人!干杯!

        【讨论】:

          猜你喜欢
          • 2012-04-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多