Search code examples
pythonpython-3.xpygame

How would I continue and write more than 1 message with this typewriter effect in pygame?


I have this problem with using pygame with this certain effect I'm using to have scrolling text. When I tried calling a function I defined, the function is being ignored until it's the very last time that function is called. This results in an output of 1 message being typed and not all of them. How could i fix this. The code:

import pygame
import os
import time

#Sets the width and height of the screen
WIDTH = 320
HEIGHT = 240

#Importing the external screen
os.putenv('SDL_FBDEV', '/dev/fb1')
os.putenv('SDL_MOUSEDRV', 'TSLIB')
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')

#Initializes the screen - Careful: all pygame commands must come after the init
pygame.init()
clock = pygame.time.Clock()

#Sets mouse cursor visibility
pygame.mouse.set_visible(False)
#Sets the screen note: must be after pygame.init()
screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)

class Board(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((900,900))
        self.image.fill((13,13,13))
        self.image.set_colorkey((13,13,13))
        self.rect = self.image.get_rect()
        self.font = pygame.font.Font('PressStart2P-Regular.ttf', 18)

    def add(self, letter, pos):
        s = self.font.render(letter, 1, (230, 230, 0))
        self.image.blit(s, pos)

class Cursor(pygame.sprite.Sprite):
    def __init__(self, board):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 20))
        self.image.fill((255,255,255))
        self.text_height = 34
        self.text_width = 20
        self.rect = self.image.get_rect(topleft=(self.text_width, self.text_height))
        self.board = board
        self.text = ''
        self.cooldown = 0
        self.cooldowns = {'.': 12,
                        '[': 18,
                        ']': 18,
                        ' ': 5,
                        '\n': 30}

    def write(self, text):
        self.text = list(text)

    def update(self):
        if not self.cooldown and self.text:
            letter = self.text.pop(0)
            if letter == '\n':
                self.rect.move_ip((0, self.text_height))
                self.rect.x = self.text_width
            else:
                self.board.add(letter, self.rect.topleft)
                self.rect.move_ip((self.text_width, 0))
            self.cooldown = self.cooldowns.get(letter, 8)

        if self.cooldown:
            self.cooldown -= 1

all_sprites = pygame.sprite.Group()
board = Board()
cursor = Cursor(board)
all_sprites.add(cursor, board)
text = """[i] Initializing ...
[i] Entering ghost mode ...

done ...

"""
text = """[Me] What you talking about?

done ...

"""
cursor.write(text)
#Main loop
running = True
while running:

    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            running = False

    all_sprites.update()
    screen.fill((0, 0, 0))
    all_sprites.draw(screen)
    pygame.display.flip()
    clock.tick(60)

Only "[Me] What you talking about?

done ..." is displayed and not the first message.

I had tried time sleep and simple while loops to solve this but the program just ignores the first function, waits the sleep, then goes on to the second action.


Solution

  • I think your problem is here:

    text = """[i] Initializing ...
    [i] Entering ghost mode ...
    
    done ...
    
    """
    text = """[Me] What you talking about?
    
    done ...
    
    """
    

    You are defining the variable text as something and then immediately redefining it, so the first value of text is never written.

    I modified your code to have a list dialogueLoop that contains all the dialogues beside the first one and, when the first dialogue is done being typed, switches the text of cursor to the next dialogue. Worked for me.

    The following is a working version of your code. You could replace the lines after self.cooldown -= 1 with the following, and it should work.

    board = Board()
    cursor = Cursor(board)
    all_sprites.add(cursor, board)
    text = """[i] Initializing ...
    [i] Entering ghost mode ...
    
    done ...
    
    """
    cursor.write(text)
    cursor.update()
    #Main loop
    running = True
    
    dialogueLoop = ["""[Me] What you talking about?
    
        done ...
    
        """
    ] # all the dialogues beside the first one
    
    while running:
    
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                running = False
        
        while len(cursor.text) > 0: # updating loop
    
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    running = False
    
            screen.fill((0, 0, 0))
            all_sprites.update()
            all_sprites.draw(screen)
            pygame.display.flip()
            clock.tick(60)
        if len(dialogueLoop) > 0: # switching dialogues
            text = dialogueLoop[0]
            dialogueLoop.pop(0)
        else:
            # dialogue is all finished
            pass