【问题标题】:Pygame needs "for event in pygame.event.get()" in order not to crashPygame 需要“for event in pygame.event.get()”才能不崩溃
【发布时间】:2017-07-02 17:38:21
【问题描述】:

该程序像这样可以正常工作,但是,我不明白为什么它需要gameOver 中的gameOver while 语句中的无用for event in pygame.event.get(): None game_loop。如果您能找到删除它的方法或解释为什么没有它就无法运行,那就太好了!

import pygame, time, random

pygame.init()

# SOUND/TEXTURES
icon = pygame.image.load("textures\snakeicon.png")
pygame.display.set_icon(icon)

# VARIABLES
white = (255, 255, 255)
black = (0, 0, 0)
red = (200, 0, 0)
green = (0, 155, 0)
bright_green = (0, 250, 0)
bright_red = (255, 0, 0)

font_size = 50
font = pygame.font.SysFont(None, font_size)

# FUNCTIONS

def text_objects(text, font):
    textSurface = font.render(text, True, black)
    return textSurface, textSurface.get_rect()


def button(msg, x, y, w, h, ic, ac, action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()

    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(gameWindow, ac, (x, y, w, h))
        if click[0] == 1 and action != None:
            if action == "play":
                game_loop()

            elif action == "quit":
                gameRun = False
                gameWindow.fill(white)
                message_to_screen("Closing Game...", black, 280, 280)
                pygame.display.update()
                time.sleep(1)
                pygame.quit()
                quit()

    else:
        pygame.draw.rect(gameWindow, ic, (x, y, w, h))

    smallText = pygame.font.Font("freesansbold.ttf", 20)
    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x + (w / 2)), (y + (h / 2)))
    gameWindow.blit(textSurf, textRect)

def snake(rect_x, rect_y, block_size):
    pygame.draw.rect(gameWindow, green, [rect_x, rect_y, block_size, block_size])

def message_to_screen(msg, color, x, y):
    screen_text = font.render(msg, True, color)
    gameWindow.blit(screen_text, [x, y])


# WINDOW/SURFACE
display_w = 800
display_h = 600
window_title = "Window"

gameWindow = pygame.display.set_mode((display_w, display_h))
pygame.display.set_caption(window_title)

# FPS/Clock
clock = pygame.time.Clock()


# Game Loop


def game_loop():
    # RECT OPTIONS
    moveSpeed = 10
    block_size = 10

    rect_x = display_w / 2
    rect_y = display_h / 2

    change_x = 0
    change_y = 0

    randApplex = round(random.randrange(0, display_w - block_size) / 10.0) * 10.0
    randAppley = round(random.randrange(0, display_h - block_size) / 10.0) * 10.0

    global gameRun, gameOver
    gameRun = True
    gameOver = False

    while gameRun:

        while gameOver:
            gameRun = False
            gameWindow.fill(white)
            # button(msg, x, y, w, h, ic, ac, action=None)
            message_to_screen("Game Over!", red, 300, 300)
            button("Restart", 150, 450, 100, 50, green, bright_green, "play")
            button("Quit", 550, 450, 100, 50, red, bright_red, "quit")
            pygame.display.update()

           # RIGHT HERE!

            for event in pygame.event.get():
                None

           # RIGHT THERE!

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameRun = False
                gameOver = False
                gameWindow.fill(white)
                message_to_screen("Closing Game...", black, 280, 280)
                pygame.display.update()
                time.sleep(1)
                pygame.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    change_y = -moveSpeed
                    change_x = 0
                elif event.key == pygame.K_s:
                    change_y = moveSpeed
                    change_x = 0
                elif event.key == pygame.K_a:
                    change_x = -moveSpeed
                    change_y = 0
                elif event.key == pygame.K_d:
                    change_x = moveSpeed
                    change_y = 0

        # BOARDER CRASH
        if rect_x >= display_w or rect_x < 0 or rect_y >= display_h or rect_y < 0:
            gameOver = True
        # LOGIC
        rect_x += change_x
        rect_y += change_y

        if rect_x == randApplex and rect_y == randAppley:
            randApplex = round(random.randrange(0, display_w - block_size) / 10.0) * 10.0
            randAppley = round(random.randrange(0, display_h - block_size) / 10.0) * 10.0

        # RENDER
        gameWindow.fill(white)

        pygame.draw.rect(gameWindow, red, [randApplex, randAppley, block_size, block_size])
        snake(rect_x, rect_y, block_size)
        pygame.display.update()

        clock.tick(15)

    message_to_screen("You Lose!", red, 325, 300)
    pygame.display.update()
    time.sleep(1)
    message_to_screen("Closing Game!", black, 280, 350)
    pygame.display.update()
    time.sleep(1)

    # QUIT
    pygame.quit()
    quit()


game_loop()

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    基本上,操作系统希望 pygame 在您的程序期间处理事件。如果操作系统注意到未处理事件,它会提醒用户。该程序实际上并没有崩溃或冻结,操作系统只是说您的程序已经变得无响应(它有,因为您没有响应任何用户事件),但它仍然有效。

    当您的游戏进入小场景时,您可能认为您不需要处理事件,但您应该始终检查一个事件:pygame.QUIT 事件(当用户按下关闭按钮时发送顶角)。在您的示例中,您不允许用户在游戏结束序列期间退出(您为玩家提供了一个可供点击的按钮,但用户也希望点击关闭按钮也会关闭游戏)。

    另一个原因是事件队列不断被填满。因此,如果用户会发送多个键并用鼠标按下多个区域,那么直到他/她再次进入游戏(您有一个事件循环)之前什么都不会发生。然后每一个事件都会被执行。因此,定期清空队列很重要。每次调用pygame.event.get()pygame.event.clear() 时,队列都会清空。

    函数pygame.event.pump()是将所有事件放入事件队列的函数(它不会清除以前的事件,它只是添加)。如果未调用该函数,则不会用任何事件填充/更新事件队列。但是,该函数在函数pygame.event.get()pygame.event.clear()pygame.event.poll()pygame.event.wait()pygame.event.peek() 内部被隐式调用,因此很少有理由显式调用它。如果您确定不想在某个时间处理事件,您可以使用pygame.event.clear(),这样当您再次开始处理事件时事件队列为空。如果您根本不想处理事件,请使用pygame.event.pump()

    【讨论】:

      【解决方案2】:

      您可以将其替换为pygame.event.pump()。文档解释了为什么您需要调用它或必须在每一帧使用事件循环。

      对于游戏的每一帧,您都需要对事件队列进行某种调用。这确保您的程序可以在内部与操作系统的其余部分进行交互。如果您在游戏中没有使用其他事件函数,则应调用 pygame.event.pump() 以允许 pygame 处理内部操作。

      如果您的程序始终通过其他 pygame.eventpygame 模块处理队列上的事件以与事件和队列函数交互,则此函数不是必需的。

      有一些重要的事情必须在事件队列内部处理。主窗口可能需要重新绘制或响应系统。如果您长时间未能调用事件队列,系统可能会判断您的程序已锁定。

      【讨论】:

        【解决方案3】:

        每个带有 GUI 的进程都需要维护一个 Message Pump(至少在 Windows 中这很关键)

        大多数时候,您的 GUI 框架(例如 QT)将为您维护泵 - 并为您的回调(鼠标点击、键盘等)调度匹配事件。

        我猜pygame 想让您更好地控制如何处理消息(如果我没记错的话,游戏引擎会希望在每次渲染单个帧时等待并泵送所有事件)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-04
          • 1970-01-01
          • 1970-01-01
          • 2013-12-09
          • 1970-01-01
          • 2011-06-02
          相关资源
          最近更新 更多