I'm having some issues rendering multiple lines of text onto a sprite in pygame. The text is read from a txt file, and then shown on the sprite which is made by the following Text class. However, since pygame doesnt render multiple lines correctly, I made the commented part to display every word in the text the way it should be shown, not realizing that according to the way I set everything up, I need an image in this Text class. (Yes, actually need.) SO MY QUESTION IS Is there a way to get the final product my commented out part creates, into the self.image as if it were a surface like my previous 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
Maybe a little vague as of why it has to be done like this, because a large part of the game is drawn like this:
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()
And to be able to draw it, it has to be part of the all_sprites group making it so it really does need the image, perhaps there's a way to seclude the Text class somehow while still drawing it?
To pass the text, I use
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)
So the text comes from a .txt file, where text like this is found:
Player has moved left!
Player has moved down!
Player has moved down!
Player has moved right!
Player has moved right!
Which was written here by any player movement:
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')
I hope this clears things up?
To blit several lines onto a surface you need to figure out the size of the text first.
In the example below, I pass a list of strings to the
Text
class.Then I find the width of the longest line
max(font.size(line)[0] for line in self.text)
and the line heightfont.get_linesize()
and create a surface with this size (passpg.SRCALPHA
to make it transparent).Now you can use a
for
loop to render and blit the lines in theself.text
list onto the surface. Enumerate the list of lines to get the y position and mutliply it by the line height.