Pygame表面非顺序更新

13

我正在尝试实现一个简单的Pygame脚本,它应该:

  1. 首先,检查用户是否按下了 Space 键;
  2. 在按下 Space 键时,显示一些文本;然后
  3. 暂停2秒钟,然后将屏幕更新到其原始状态。

请注意,上述所有事件必须按顺序发生,且不能颠倒顺序

我遇到了问题,程序首先暂停,然后只显示文本并在屏幕更新到其原始状态前出现了一个短暂的时间(或根本不显示)。

程序似乎跳过了第2步,然后才执行了第3步的暂停操作,而没有显示文本。我的代码如下:

import pygame
import sys
from pygame.locals import *

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

pygame.init()
wS = pygame.display.set_mode((500, 500), 0, 32)


# Method works as intended by itself
def create_text(x, y, phrase, color):
    """
    Create and displays text onto the globally-defined `wS` Surface
    (params in docstring omitted)
    """
    # Assume that the font file exists and is successfully found
    font_obj = pygame.font.Font("./roboto_mono.ttf", 32)
    text_surface_obj = font_obj.render(phrase, True, color)
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.center = (x, y)
    wS.blit(text_surface_obj, text_rect_obj)


while True:
    wS.fill(BLACK)
    for event in pygame.event.get():
        if event.type == KEYDOWN and event.key == K_SPACE:

            # Snippet containing unexpected behavior
            create_text(250, 250, "Hello world!", WHITE)
            pygame.display.update()
            pygame.time.delay(2000)
            # Snippet end

        if event.type == QUIT:
            pygame.quit()
            sys.exit(0)
    pygame.display.update()

提前致谢!


尝试删除 pygame.time.delay(2000) 下面的两行代码。它们似乎是不必要的,可能会引起问题。 - skrx
@skrx,一旦我删除了delay()方法调用下面的两行代码,我确实看到了“Hello World!”文本被blitted;但是,它只会显示一瞬间(一个帧?),而不是预期的2秒。 - Jerrybibo
很奇怪。在delay调用后,程序的执行应该停止。顺便说一下,我一开始很难复现这个错误。我想我只看到过一次,而且时间非常短,但是再也无法复现了。也许重新构建程序并使用其中一个计时器会更好。 - skrx
2个回答

9

由于某些原因,该程序在我更改字体的唯一情况下就可以运行。这与@Omega0x013所做的相同,但您拥有无限帧速率。它之所以有效,是因为FPS.tick()返回自上次调用以来经过的时间量,如果您没有指定帧速率,它将不会保持程序。

import pygame
import sys
from pygame.locals import *
displayText = False
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

pygame.init()
wS = pygame.display.set_mode((500, 500), 0, 32)


# Method works as intended by itself
def create_text(x, y, phrase, color):
    """
    Create and displays text onto the globally-defined `wS` Surface
    (params in docstring omitted)
    """
    # Assume that the font file exists and is successfully found

    font_obj = pygame.font.Font(None,30)
    text_surface_obj = font_obj.render(phrase, True, color)
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.center = (x, y)
    wS.blit(text_surface_obj, text_rect_obj)

FPS = pygame.time.Clock()
while True:
    wS.fill(BLACK)
    for event in pygame.event.get():
        if event.type == KEYDOWN and event.key == K_SPACE:
            totalTime = 0
            FPS.tick()
            displayText = True

        if event.type == QUIT:
            pygame.quit()
            sys.exit(0)
    if displayText:
        totalTime += FPS.tick()
        create_text(250, 250, "Hello world!", WHITE)
        if totalTime >= 2000:
            displayText = False
    pygame.display.update()

哇,这个解决方案非常适合我的使用。谢谢!(另外,如果从事件循环中删除FPS.tick()调用,应该也没问题吧?) - Jerrybibo
4
Fps.Tick() 函数返回自上次调用以来的时间量。如果我按下空格键,然后在5秒钟后再次按下空格键并调用FPS.tick(),它将返回5秒钟,这意味着屏幕会立即变黑。通过将其保留在事件循环中,每当我按下空格键时,时间都会被重置。 - user10030086

8

你应该尝试这个:

import pygame
import sys
from pygame.locals import *

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

pygame.init()
wS = pygame.display.set_mode((500, 500), 0, 32)
clock = pygame.time.Clock()

showing = False
timer = 0
# Method works as intended by itself
def create_text(x, y, phrase, color):
    """
    Create and displays text onto the globally-defined `wS` Surface
    (params in docstring omitted)
    """
    # Assume that the font file exists and is successfully found
    font_obj = pygame.font.Font("./roboto_mono.ttf", 32)
    text_surface_obj = font_obj.render(phrase, True, color)
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.center = (x, y)
    wS.blit(text_surface_obj, text_rect_obj)


while True:
    wS.fill(BLACK)
    for event in pygame.event.get():
        if event.type == KEYDOWN and event.key == K_SPACE:
            showing = True
            timer = 0

        if event.type == QUIT:
            pygame.quit()
            sys.exit(0)

    if showing:
        timer += 1
        create_text(250, 250, "Hello world!", WHITE)

    if timer == 20:
        timer = 0
        showing = False

    pygame.display.update()
    clock.tick(100)

每次按下空格键时,它会显示文本2秒钟,通过显示文本,计数2000毫秒,然后不再显示。

4
缩进有点问题,你可能需要修复一下。此外,我知道这个问题没有具体说明,但 pygame.Clock.tick() 存在帧速率有限的缺点。我更倾向于不涉及这种限制的解决方案。 - Jerrybibo
如果我将最后两个 if 子句取消缩进并与 for event 循环处于同一级别,则此解决方案有效;我已经给你点赞了。但我还在寻找一种更优雅的解决方案,它不依赖于 pygame.Clock.tick() - Jerrybibo
我同意pygame.Clock.tick()存在一些限制,@Jerrybibo,但它可以使得时间恰好为两秒钟,且保持恒定和可测量。 - Omega0x013

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接