Typewriter Effect Pygame

Typewriter Effect Pygame

Sorry if I don't answer your question directly, because your code is too confusing for me now, so I took the liberty to rewrite your code to get done what you want.

The idea is to have two sprites:

  • the cursor, which is a) displayed on the screen and b) keeps track of what text to write and where

  • the board, which is basically just a surface that the text is rendered on

Note how all the writing logic is on the Cursor class, and we have a nice, simple and dumb main loop.

import pygame
import os

#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((WIDTH, HEIGHT))

class Board(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((WIDTH, HEIGHT))
self.image.fill((13,13,13))
self.image.set_colorkey((13,13,13))
self.rect = self.image.get_rect()
self.font = pygame.font.SysFont("monospace", 18)

def add(self, letter, pos):
s = self.font.render(letter, 1, (255, 255, 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((0,255,0))
self.text_height = 17
self.text_width = 10
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 ...

"""

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)

Sample Image

Have a question for pygame typewriting effect and the background image

Your game just exits after the first screen render. You need to add a loop to your main function to continue the game:

#Main loop
def runGame():
running = True
while (running): # main loop
global gamePad, clock, background
drawObject(background, 0, 0)

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

all_sprites.update()
all_sprites.draw(gamePad)
pygame.display.flip()
pygame.display.update() # don't need this
clock.tick(60)

initGame()
runGame()

How do I make text appear letter by letter in a box in Pygame?

See Typewriter Effect Pygame. The basic idea is that you use a timer event (pygame.time.set_timer()) and append the text letter by letter:

typewriter_event = pygame.USEREVENT+1
pygame.time.set_timer(typewriter_event, 100)

text = 'Hello World'
typewriter_text = ""

while run:
# [...]

for event in pygame.event.get():
if event.type == typewriter_event:
if len(typewriter_text) < len(text):
typewriter_text += text[len(typewriter_text)]

Unfortunately pygame cannot render text with line breaks. You have to render the test line by line. See Rendering text with multiple lines in pygame

Typing effect in Python

you should use sys.stdout.flush() after each iteration

The problem is that stdout is flushed with the newline or manually with sys.stdout.flush()

So the result is

import sys
from time import sleep

words = "This is just a test :P"
for char in words:
sleep(0.5)
sys.stdout.write(char)
sys.stdout.flush()

The reason why your output is buffered is that system call needs to be performed in order to do an output, system calls are expensive and time consuming (because of the context switch, etc). Therefore user space libraries try to buffer it and you need to flush it manually if needed.

Just for the sake of completeness ... Error output is usually non-buffered (it would be difficult for debugging). So following would also work. It is just important to realise that it is printed to the error output.

import sys
from time import sleep

words = "This is just a test :P"
for char in words:
sleep(0.5)
sys.stderr.write(char)

Python simple typewriter effect

This is because you're declaring global line at wrong place;

Try declaring it in loop() as it's your main function (or initially called function) here:

import time

def typing():
for letter in line:
time.sleep(0.03)
print(letter, end='')

def loop():
global line
line ='I am gay'
typing()
print('')
line ='Are you also gay?'
typing()
print('')
loop()
loop()

DEMO https://repl.it/G7Zw

Python/Pygame adding a title screen with a button

The implementation of a button is answered several times. For example Pygame mouse clicking detection, How do I detect if the mouse is hovering over a button? PyGame button class is not displaying the text or changing colour on hover or How can I add an image or icon to a button rectangle in Pygame? and myn more.


Create 2 scenes with 2 application loops. The first loop shows the title screen and waits for button 2 to be pressed. The 2nd loop is the game loop:

button_rect = pygame.Rect(x, y, width, height) # start button rectangle

abort = False
start = False
while not abort and not start:
for event in pygame.event.get():
if event.type == pygame.QUIT:
abort = True

if event.type == MOUSEBUTTONDOWN:
if button_rect.collidepoint(event.pos):
start = True

# draw title screen
# [...]

done = abort
while not done:

while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True

# game
# [...]

Alternatively, you can combine both scenes in one loop.Add a variable game_state, implement event handling and draw the scenes depending on the value of game_state. Change the game_state when the start button is pressed:

game_state = 'title'

done = False
while not done:

# event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True

if game_state == 'title':
if event.type == MOUSEBUTTONDOWN:
if button_rect.collidepoint(event.pos):
game_state = 'game'

elif game_state == 'game':
# handle game events:
# [...]

# drawing
if game_state == 'title':
# draw title screen
# [...]

elif game_state == 'game':
# game
# [...]


Related Topics



Leave a reply



Submit