Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pygame needs "for event in pygame.event.get()" in order not to crash

Tags:

python

pygame

The program works fine like this but, I don't understand why it needs the useless for event in pygame.event.get(): None in the gameOver while statement inside game_loop. If you could find a way to delete it or explain why it doesn't run without it, that would be great!

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()
like image 403
Lh9901 Avatar asked May 30 '17 05:05

Lh9901


Video Answer


2 Answers

Basically, the OS expects pygame to handle events during your program. If the OS notice that events aren't handled, it'll alert the user. The program doesn't actually crash or freeze, the OS is just saying that your program has become unresponsive (which it has because you're not responding to any user events), but it still works.

When your game is entering small scenes you might think that you don't need to handle events, but there is one event you should always check for: the pygame.QUIT event (sent when the user press the close button at the top corner). In your example you're not allowing the user to quit during the game over sequence (you're providing the player a button to click but a user would also expect clicking the close button would close the game as well).

Another reason is that the event queue is constantly filling up. So if the user would spam multiple keys and press multiple areas with the mouse, nothing would happen until he/she enters the game again (where you have an event loop). Then every event would be executed. Therefore it's important to regularly empty the queue. The queue is emptied every time you call pygame.event.get() or pygame.event.clear().

The function pygame.event.pump() is the function that put all events into the event queue (it doesn't clear the previous events, it just adds). The event queue won't be filled/updated with any events if the function isn't called. However, the function is implicitly called inside the functions pygame.event.get(), pygame.event.clear(), pygame.event.poll(), pygame.event.wait() and pygame.event.peek(), so there is rarely a reason to call it explicitly. If you are sure you don't want to handle events at some time, you could use pygame.event.clear() so the event queue is empty when you start processing events again. If you don't want to handle events at all, then use pygame.event.pump().

like image 193
Ted Klein Bergman Avatar answered Dec 23 '22 00:12

Ted Klein Bergman


You can replace it with pygame.event.pump(). The documentation explains why you need to call this or have to use an event loop each frame.

For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system. If you are not using other event functions in your game, you should call pygame.event.pump() to allow pygame to handle internal actions.

This function is not necessary if your program is consistently processing events on the queue through the other pygame.eventpygame module for interacting with events and queues functions.

There are important things that must be dealt with internally in the event queue. The main window may need to be repainted or respond to the system. If you fail to make a call to the event queue for too long, the system may decide your program has locked up.

like image 22
skrx Avatar answered Dec 22 '22 23:12

skrx