打字机效果 Pygame [英] Typewriter Effect Pygame

查看:93
本文介绍了打字机效果 Pygame的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题真的很难问,但我知道 Stack Overflow 的你们是最聪明的人.

This question is really difficult to ask, but I know you guys here at Stack Overflow are the brightest minds.

我完全不知道为什么会出现这个问题(我对 Python 和 Pygame 相当熟悉,所以我会因为我对提高技能的热爱而收到关于如何改进代码的任何建议).

I'm totally blinded by why this issue happens (I'm fairly at Python and Pygame, so any suggestions on how to improve the code will be received with the love of improving my skills).

我正在创建的内容:这真的是一个噱头项目,我有一个 2.5 英寸的小屏幕 (PiTFT) 连接到 Raspberry Pi,代码正在创建一个打字机效果,在文本写入时在文本前面移动光标.

What I'm creating: It's really a gimmick project, I have a little 2.5" screen (PiTFT) attached to a Raspberry Pi and the code is creating a typewriter effect with a moving cursor in front of the text as it's being written.

挑战 1 每次在 pygame 中移动 sprite 时,必须重新绘制所有内容,否则会看到一条轨迹,并且由于光标在文本前面移动,因此结果如下所示:

Challenge 1 was that every time you move a sprite in pygame, you must redraw everything, otherwise you will see a trail, and since the cursor is moving in front of the text, the result would look like this:

我设法通过变黑/清除屏幕来解决这个问题.但是后来我丢失了所有以前写过的信件.所以我创建了一个列表(整个词),我用以前写的所有字符填充它.每次循环遍历循环时,我都会使用此列表来重绘所有以前的书面文本.所以现在:

I managed to solve this issue by blackening / clearing the screen. But then I lost all the previously written letters. So I created a list (entireword), which I'm populing with all the previously written characters. I use this list every time I cycle through the loop to redraw all the previous written text. So now:

如您所见,文字看起来很有趣.它应该是:

As you can see, the text looks funny. It's supposed to read:

[i] 正在初始化...

[i] Initializing ...

[i] 进入幽灵模式... []

[i] Entering ghost mode ... []

我已经花了几个小时来达到这一点 - 代码几乎完美运行!魔法发生在函数print_screen() 中,但是我的代码中是什么导致文本最后包含来自另一行的字母?:>

I've been spending hours and hours getting to this point - and the code ALMOST works perfectly! The magic happens in the function print_screen(), but WHAT in my code is causing the text to include a letter from the other line in the end? :>

非常感谢您的帮助 <3

Help is GREATLY appreciated <3

完整代码如下:

import pygame
import time
import os
import sys
from time import sleep
from pygame.locals import *

positionx = 10
positiony = 10
entireword = []
entireword_pos = 10
counter = 0
entire_newline = False


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

#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()

#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))

# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 18)

#Class

class cursors(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 20))
        self.image.fill((0,255,0))
        self.rect = self.image.get_rect()
        self.rect.center = (positionx + 10, positiony + 10)

    def update(self):
        self.rect.x = positionx + 10
        self.rect.y = positiony

#Functions

#Prints to the screen
def print_screen(words, speed):
    rel_speed = speed
    for char in words:
        #speed of writing
        if char == ".":
            sleep(0.3)
        else:
            sleep(rel_speed)

        #re-renders previous written letters
        global entireword

        # Old Typewriter functionality - Changes position of cursor and text a newline

        #Makes sure the previous letters are rendered and not lost
        #xx is a delimter so the program can see when to make a newline and ofcourse ignore writing the delimiter
        entireword.append(char)
        if counter > 0:
            loopcount = 1
            linecount = 0 # This is to which line we are on
            for prev in entireword:
                if prev == 'xx':
                    global linecount
                    global positiony
                    global loopcount
                    linecount = linecount + 1
                    positiony = 17 * linecount
                    loopcount = 1
                if prev != 'xx':  #ignore writing the delimiter
                    pchar = myfont.render(prev, 1, (255,255,0))
                    screen.blit(pchar, (loopcount * 10, positiony))
                    loopcount = loopcount + 1

        if char != 'xx':
            # render text
            letter = myfont.render(char, 1, (255,255,0))
            #blits the latest letter to the screen
            screen.blit(letter, (positionx, positiony))

        # Appends xx as a delimiter to indicate a new line
        if entire_newline == True:
            entireword.append('xx')
            global entire_newline
            entire_newline = False

        global positionx
        positionx = positionx + 10
        all_sprites.update()
        all_sprites.draw(screen)
        pygame.display.flip()
        screen.fill((0,0,0)) # blackens / clears the screen

        global counter
        counter = counter + 1

#Positions cursor at new line
def newline():
    global positionx
    global positiony
    positionx = 10
    positiony = positiony + 17

all_sprites = pygame.sprite.Group()
cursor = cursors()
all_sprites.add(cursor)

#Main loop
running = True
while running:
    global speed
    global entire_newline

    words = "[i] Initializing ..."
    entire_newline = True
    newline()
    print_screen(words,speed)

    words = "[i] Entering ghost mode ..."
    entire_newline = True
    newline()
    print_screen(words,speed)

    #Stops the endless loop if False
    running = False
sleep(10)

推荐答案

抱歉没有直接回答你的问题,因为你的代码现在对我来说太混乱了,所以我冒昧地重写了你的代码来完成你想要什么.

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:

  • 光标,a) 显示在屏幕上 b) 跟踪要写的文本和位置

  • 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

请注意 Cursor 类上的所有编写逻辑是如何进行的,我们有一个漂亮、简单且笨拙的主循环.

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)

这篇关于打字机效果 Pygame的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆