Не могу отрисовать несколько строк в Pygame на спрайте

У меня есть некоторые проблемы при рендеринге нескольких строк текста на спрайт в Pygame. Текст читается из текстового файла, а затем отображается на спрайте, который создается следующим классом Text. Однако, поскольку 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 ответ

Решение

Чтобы растереть несколько линий на поверхности, вам нужно сначала определить размер текста.

В приведенном ниже примере я передаю список строк Text учебный класс.

Тогда я нахожу ширину самой длинной линии max(font.size(line)[0] for line in self.text) и высота линии font.get_linesize() и создать поверхность с этим размером (пройти pg.SRCALPHA сделать его прозрачным).

Теперь вы можете использовать for цикл для рендеринга и блики строк в self.text список на поверхность. Перечислите список строк, чтобы получить позицию 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()
Другие вопросы по тегам