简体   繁体   中英

Pygame KEYUP, KEYDOWN causing ghost movement

I took a stab at learning KEYUP and KEYDOWN. Bascily, after the user crashes into any side of the window the game resets like intended. What is not intended is for the square to begin moving again even though no key has been pressed or released.

Ideal series of events: - User Crashes - Game resets with square in the original starting potion (stationary) - press a movement key and square moves

Any insight into why this is happening would be great.

Thanks

import pygame
import time

pygame.init()

display_width = 800
display_height = 600

black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)

car_width = 75

gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('A bit Racey')
clock = pygame.time.Clock()


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


def message_display(text):
    largeText = pygame.font.Font('freesansbold.ttf', 115)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = ((display_width / 2), (display_height / 2))
    gameDisplay.blit(TextSurf, TextRect)

    pygame.display.update()

    time.sleep(2)

    game_loop()


def crash():
    message_display('You Crashed')


def game_loop():
    x = 200
    y = 200

    x_change = 0
    y_change = 0

    gameExit = False

    while not gameExit:

        # Movement logic
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    x_change += 5
                if event.key == pygame.K_LEFT:
                    x_change += -5

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_RIGHT:
                    x_change += -5
                if event.key == pygame.K_LEFT:
                    x_change += 5

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    y_change += -5
                if event.key == pygame.K_DOWN:
                    y_change += 5

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_UP:
                    y_change += 5
                if event.key == pygame.K_DOWN:
                    y_change += -5

        x += x_change
        y += y_change

        gameDisplay.fill(white)
        pygame.draw.rect(gameDisplay, red, [x, y, 75, 75])

        # Check if border hit
        if x > display_width - car_width or x < 0:
            crash()
        if y > display_height - car_width or y < 0:
            crash()

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


game_loop()
pygame.quit()
quit()

Screw global variables, events and lots of flags.

Just use pygame.key.get_pressed to get the current state of the keyboard. Assign each arrow key a movement vector, add them up, normalize it, and there you go.

Also, if you want to do something with something rectangular, just use the Rect class. It will make your live a lot easier.

Here's a running example:

import pygame
import time

pygame.init()

display_width = 800
display_height = 600

black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)

car_width = 75

gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('A bit Racey')
clock = pygame.time.Clock()


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


def message_display(text):
    largeText = pygame.font.Font('freesansbold.ttf', 115)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = ((display_width / 2), (display_height / 2))
    gameDisplay.blit(TextSurf, TextRect)

    pygame.display.update()

    time.sleep(2)

    game_loop()


def crash():
    message_display('You Crashed')

keymap = {
    pygame.K_RIGHT: pygame.math.Vector2(1, 0),
    pygame.K_LEFT: pygame.math.Vector2(-1, 0),
    pygame.K_UP: pygame.math.Vector2(0, -1),
    pygame.K_DOWN: pygame.math.Vector2(0, 1)
}

def game_loop():

    # we want to draw a rect, so we simple use Rect
    rect = pygame.rect.Rect(200, 200, 75, 75)

    gameExit = False

    while not gameExit:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        # get the state of the keyboard
        pressed = pygame.key.get_pressed()
        # get all the direction vectors from the keymap of all keys that are pressed
        vectors = (keymap[key] for key in keymap if pressed[key])
        # add them up to we get a single vector of the final direction
        direction = pygame.math.Vector2(0, 0)
        for v in vectors:
            direction += v

        # if we have to move, we normalize the direction vector first
        # this ensures we're always moving at the correct speed, even diagonally
        if direction.length() > 0:
            rect.move_ip(*direction.normalize()*5)

        gameDisplay.fill(white)
        pygame.draw.rect(gameDisplay, red, rect)

        # Check if border hit
        # See how easy the check is
        if not gameDisplay.get_rect().contains(rect):
            crash()

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


game_loop()
pygame.quit()
quit()

There are some other issues with your code:

For example, if you use time.sleep(2) , your entire program will freeze. This means you can't close the window while waiting and the window will not be redrawn by the window manager etc.

Also, your code contains an endless loop. If you hit the wall often enough, you'll run into a stack overflow, because game_loop calls crash which in turn calls game_loop again. This is probably not a big issue at first, but something to keep in mind.

What you need is to set your game variables (x, y, x_change, y_change) back to defaults, most probably in crash() function after crash. pygame won't do that for you.

Either make your variables global, or use some mutable object (like dictionary) to access them from other methods.

As Daniel Kukiela says, you can make "x_change" and "y_change" into global variables, along with giving them the value of 0 at the start, here is the working project as far as I understand.

import pygame
import time

pygame.init()

display_width = 800
display_height = 600

black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)

car_width = 75
x_change = 0
y_change = 0

gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('A bit Racey')
clock = pygame.time.Clock()


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


def message_display(text):
    largeText = pygame.font.Font('freesansbold.ttf', 115)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = ((display_width / 2), (display_height / 2))
    gameDisplay.blit(TextSurf, TextRect)

    pygame.display.update()

    time.sleep(2)

    game_loop()


def crash():
    message_display('You Crashed')


def game_loop():
    x = 200
    y = 200
    global x_change
    x_change == 0
    global y_change
    y_change == 0



    gameExit = False

    while not gameExit:

        # Movement logic
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    x_change += 5
                if event.key == pygame.K_LEFT:
                    x_change += -5

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_RIGHT:
                    x_change += -5
                if event.key == pygame.K_LEFT:
                    x_change += 5

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    y_change += -5
                if event.key == pygame.K_DOWN:
                    y_change += 5

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_UP:
                    y_change += 5
                if event.key == pygame.K_DOWN:
                    y_change += -5

        x += x_change
        y += y_change

        gameDisplay.fill(white)
        pygame.draw.rect(gameDisplay, red, [x, y, 75, 75])

        # Check if border hit
        if x > display_width - car_width or x < 0:
            crash()
        if y > display_height - car_width or y < 0:
            crash()

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


game_loop()
pygame.quit()
quit()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM