【问题标题】:Cant seem to render multiple lines in pygame on a sprite似乎无法在精灵的 pygame 中渲染多行
【发布时间】:2018-02-26 19:00:15
【问题描述】:

我在将多行文本渲染到 pygame 中的精灵上时遇到了一些问题。文本从 txt 文件中读取,然后显示在由以下 Text 类制作的精灵上。然而,由于 pygame 不能正确渲染多行,我做了注释部分以显示文本中的每个单词应该显示的方式,没有意识到根据我设置所有内容的方式,我需要这个 Text 类中的图像。 (是的,确实需要。) 所以我的问题是 有没有办法将我注释掉的部分创建的最终产品放入 self.image 中,就好像它是像我之前的 textsurface 一样的表面?

class Text(pg.sprite.Sprite):
    def __init__(self, game, x, y, text):
        self.groups = game.all_sprites, game.text
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        myfont = pg.font.SysFont('lucidaconsole', 20, bold = True)

        '''words = [word.split(' ') for word in text.splitlines()]
        space = myfont.size(' ')[0]
        max_width = 575
        max_height = 920
        pos = (0, 0)
        text_x, text_y = pos
        for line in words:
            for word in line:
                text_surface = myfont.render(word, False, (0, 255, 0))
                text_width, text_height = text_surface.get_size()
                if (text_x + text_width >= max_width):
                    text_x = pos[0]
                    text_y += text_height
                game.screen.blit(text_surface, (text_x, text_y))
                text_x += text_width + space
            text_x = pos[0]
            text_y += text_height'''

        textsurface = myfont.render(text, False, (0, 255, 0))
        self.image = textsurface
        game.screen.blit(textsurface, (0, 0))
        self.rect = game.text_img.get_rect()
        self.x = x
        self.y = y
        self._layer = 2
        self.rect.x = (x * TILESIZE) - 49
        self.rect.y = (y * TILESIZE) - 45

可能有点模糊,为什么要这样,因为游戏的很大一部分是这样绘制的:

def draw(self):
    for sprite in sorted(self.all_sprites, key=lambda s: s._layer):
        self.screen.blit(sprite.image, self.camera.apply(sprite))
    pg.display.flip()

为了能够绘制它,它必须是制作它的 all_sprites 组的一部分,所以它确实需要图像,也许有一种方法可以在绘制的同时以某种方式隔离 Text 类?

为了传递文本,我使用

if event.type == pg.USEREVENT + 1:
            for row, tiles in enumerate(self.map.data):
                for col, tile in enumerate(tiles):
                    if tile == 'T':
                        with open('text_code.txt') as f:
                            for line in f:
                                Text(self, col, row, line)

所以文本来自一个 .txt 文件,其中可以找到这样的文本:

Player has moved left!
Player has moved down!
Player has moved down!
Player has moved right!
Player has moved right!

这是由任何玩家运动写在这里的:

def move(self, dx=0, dy=0):
    if (dx == -1):
        with open('text_code.txt', 'a') as f:
            f.write('Player has moved left!\n')
    if (dx == 1):
        with open('text_code.txt', 'a') as f:
            f.write('Player has moved right!\n')
    if (dy == -1):
        with open('text_code.txt', 'a') as f:
            f.write('Player has moved up!\n')
    if (dy == 1):
        with open('text_code.txt', 'a') as f:
            f.write('Player has moved down!\n')

我希望这能解决问题?

【问题讨论】:

    标签: python python-3.x pygame text-rendering pygame-surface


    【解决方案1】:

    要在一个表面上添加多条线,您需要首先确定文本的大小。

    在下面的示例中,我将字符串列表传递给Text 类。

    然后我找到最长线的宽度max(font.size(line)[0] for line in self.text) 和线高font.get_linesize() 并创建一个具有此大小的表面(通过pg.SRCALPHA 使其透明)。

    现在您可以使用for 循环将self.text 列表中的线条渲染和blit 到表面上。枚举行列表以获取 y 位置并将其乘以行高。

    import pygame as pg
    
    
    pg.init()
    
    MYFONT = pg.font.SysFont('lucidaconsole', 20, bold=True)
    
    s = """Lorem ipsum dolor sit amet, consectetur adipiscing
    elit, sed do eiusmod tempor incididunt ut labore et
    dolore magna aliqua. Ut enim ad minim veniam, quis
    nostrud exercitation ullamco laboris nisi ut aliquip
    ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore
    eu fugiat nulla pariatur. Excepteur sint occaecat
    cupidatat non proident, sunt in culpa qui officia
    deserunt mollit anim id est laborum."""
    
    
    class Text(pg.sprite.Sprite):
    
        def __init__(self, pos, text, font):
            super().__init__()
            self.text = text
            width = max(font.size(line)[0] for line in self.text)
            height = font.get_linesize()
            self.image = pg.Surface((width+3, height*len(self.text)), pg.SRCALPHA)
            # self.image.fill(pg.Color('gray30'))  # Fill to see the image size.
            # Render and blit line after line.
            for y, line in enumerate(self.text):
                text_surf = font.render(line, True, (50, 150, 250))
                self.image.blit(text_surf, (0, y*height))
            self.rect = self.image.get_rect(topleft=pos)
    
    
    class Game:
    
        def __init__(self):
            self.done = False
            self.clock = pg.time.Clock()
            self.screen = pg.display.set_mode((1024, 768))
            text = Text((20, 10), s.splitlines(), MYFONT)
            self.all_sprites = pg.sprite.Group(text)
    
        def run(self):
            while not self.done:
                self.clock.tick(30)
                self.handle_events()
                self.draw()
    
        def handle_events(self):
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    self.done = True
    
        def draw(self):
            self.screen.fill((50, 50, 50))
            self.all_sprites.draw(self.screen)
            pg.display.flip()
    
    
    if __name__ == '__main__':
        Game().run()
        pg.quit()
    

    【讨论】:

    • 嘿,我试过你上面说的,但我得到 ValueError: max() arg is an empty sequence,有什么线索吗? [关于width = max(font.size~)部分]
    • 您不能将空序列(列表、元组等)传递给max。它必须包含一些项目。 text 是我的示例中的字符串列表。
    • 我试过这样做" width = max(myfont.size(line)[0] for line in self.text) 估计不是这样,我会搜索它应该是怎样的
    • 你传递的text参数是什么?
    • 编辑了原帖
    猜你喜欢
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多