似乎无法在精灵上的pygame中渲染多行

时间:2017-09-18 09:28:21

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

我有一些问题在pygame中将多行文本渲染到精灵上。文本从txt文件中读取,然后显示在由以下Text类生成的sprite上。但是,由于pygame没有正确渲染多行,我让注释部分按照应该显示的方式显示文本中的每个单词,没有意识到根据我设置的方式,我需要在这个Text类中有一个图像。 (是的,实际上需要。) 我的问题是 有没有办法让我注释掉的部分创建的最终产品进入self.image,好像它是一个像我以前的文本界面一样的表面?

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')

我希望这能解决问题吗?

1 个答案:

答案 0 :(得分: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()