Why is this text printing function function in pygame creating lag?

Shown below is a function I made in pygame for text to be printed letter by letter. It will print up to 3 lines before running off the edge of the screen. For some reason, if I print the equivalent of three lines of text and attempt to print a single character afterwards, the program freezes and stops running temporarily. Is there a reason why this is happening? Also, if there is something that my function may not accommodate in terms of printing text, what can I do to improve this function?

Here is the code:

def print_text_topleft(string):
    global text
    letter = 0  # Index of string 
    text_section = 1  # used for while true loop
    counter = 6  # frames to print a single letter
    output_text = ""  # First string of text
    output_text2 = "" # second string of text
    output_text3 = "" # third string of text
    while text_section == 1:
        temp_surface = pygame.Surface((WIDTH,HEIGHT))  # Creates a simple surface to draw the text onto
        text = list(string)  # turns the string into a list
        if counter > 0:  # Counter for when to print each letter
            counter -= 1
        else:
            counter = 6  # Resets counter 
            if letter <= 41:
                output_text += text[letter]  # prints to first line
            elif letter > 41:
                if letter > 82:
                    output_text3 += text[letter]  # prints to second
                else:
                    output_text2 += text[letter]  # prints to third

            if letter == len(text) - 1:  # End of string
                time.sleep(2)
                text_section = 0
            else:
                letter += 1

        temp_surface.fill((0,0,0))
        message, rect = gameFont.render(output_text, (255,255,255))  # Gamefont is a font with a size of 24
        message2, rect2 = gameFont.render(output_text2, (255,255,255))
        message3, rect3 = gameFont.render(output_text3, (255,255,255))
        rect.topleft = (20,10)
        rect2.topleft = (20,50)
        rect3.topleft = (20,90) 
        temp_surface.blit(message,rect)  # All strings are drawn to the screen
        temp_surface.blit(message2,rect2)
        temp_surface.blit(message3,rect3)
        screen.blit(temp_surface, (0,0))  # The surface is drawn to the screen
        pygame.display.flip()  # and the screen is updated

and here are the two string I run through it:

print_text_topleft("Emo: Hello friend. My name is an anagram. I would be happy if the next lines would print. That would be cool! ")
print_text_topleft("Hi")

Upvotes: 1

Views: 194

Answers (2)

ParvBanks
ParvBanks

Reputation: 1436

I'm never used pygame but just read your question out of curiosity. I guess you need to optimize the multiple loops you've added to the code.

Also, temp_surface = pygame.Surface((WIDTH,HEIGHT)) specifies the target window size. Not sure where you're specifying the width and height and if it is limiting the output?

Upvotes: 0

Adam Smith
Adam Smith

Reputation: 54213

You're doing a lot of raw text processing which is somehow using all the most expensive Python functions for doing so. Consider:

text = list(string)          # O(n) + list init

if counter > 0: counter -=1  # due to the rest of the structure, you're now
                             # creating the above list 6 times! Why??

output_text += text[letter]  # string concatenation is slow, and you're doing this
                             # n times (where n is len(string)). Also you're
                             # calling n list indexing operations, which while
                             # those are very fast, is still unnecessary.

time.sleep(2)                # this will obviously freeze your app for 2s

Why not construct your string ahead of time?

span = 40  # characters per line
lines = [string[start:start+span] for start in range(0, len(string)+1, span)]
if len(lines) > 3:
    # what do you do if the caller has more than three lines of text?

Then render your text as usual.

Upvotes: 1

Related Questions