3

I would create a sort of "scrolling dialogue" like in the old point and click. I'll try to explain better:

I have the following text: "Hello World". I would print in the screen letter by letter: "H" (1 sec after) "e" (1 sec after) "l" etc etc..

i tried to do in this way:

font = pygame.font.Font("orangekid.ttf", 25)
text = font.render("A long time ago", True, (0, 128, 0))


        pygame.display.update()
        for i in range(len("A long time ago")):
            display_game.fill(BLACK)
            display_game.blit(text[i],(400+i, 300))

            clock.tick(60)

but it gives me an error about the text[i].

How can i solve the problem?

pppery
  • 3,550
  • 19
  • 28
  • 41
Vito
  • 684
  • 2
  • 8
  • 25

2 Answers2

5

Here, you render the entire text to a Surface:

text = font.render("A long time ago", True, (0, 128, 0))

Here, you iterate over a string:

for i in range(len("A long time ago")):
    display_game.fill(BLACK)
    display_game.blit(text[i],(400+i, 300))

text is a Surface, not a string anymore, so you can't index it like a string and hope to get a part of the text. The Surface named text does not know if it contains text or not.

Also, you have to use some kind of timer to change the text every second.

Here's a simple example of how you could do what you want:

import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()

font = pygame.font.Font(None, 25)

# raise the USEREVENT every 1000ms
pygame.time.set_timer(pygame.USEREVENT, 200)

# generate a generator that scrolls through the letters
# given a string foo, it will return
# f
# fo
# foo
def text_generator(text):
    tmp = ''
    for letter in text:
        tmp += letter
        # don't pause for spaces
        if letter != ' ':
            yield tmp

# a simple class that uses the generator
# and can tell if it is done
class DynamicText(object):
    def __init__(self, font, text, pos, autoreset=False):
        self.done = False
        self.font = font
        self.text = text
        self._gen = text_generator(self.text)
        self.pos = pos
        self.autoreset = autoreset
        self.update()
    
    def reset(self):
        self._gen = text_generator(self.text)
        self.done = False
        self.update()
        
    def update(self):
        if not self.done:
            try: self.rendered = self.font.render(next(self._gen), True, (0, 128, 0))
            except StopIteration: 
                self.done = True
                if self.autoreset: self.reset()

    def draw(self, screen):
        screen.blit(self.rendered, self.pos)
            
message = DynamicText(font, "A long time ago...", (200, 200), autoreset=True)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: break
        if event.type == pygame.USEREVENT: message.update()
    else:
        screen.fill(pygame.color.Color('black'))
        message.draw(screen)
        pygame.display.flip()
        clock.tick(60)
        continue
    break
pygame.quit()

enter image description here

B. Willems
  • 50
  • 1
  • 5
sloth
  • 95,484
  • 19
  • 164
  • 210
1

In the example you gave, 'text' is a surface (font.render renders a surface based on the string you give it). What you want to do is iterate over a string, and then render it to a surface.

Another thing I would change is the "(400+i, 300)", because letters are more than one pixel in width, so moving the coordinates by only one pixel would have them overlap. I would suggest using the font.size function to determine the new coordinates.

Example:

clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 48)
string = "A long time ago"
windowSurface.fill(BLACK)
for i in range(len(string)):
    text = font.render(string[i], True, (0, 128, 0))
    windowSurface.blit(text,(400 + (font.size(string[:i])[0]), 300))
    pygame.display.update()
    clock.tick(2)
CodePanter
  • 36
  • 4