pygame hold key to move

I’m trying to move the player left in the four main directions, but it only moves when pressed not held down, so I have to repeatedly press the button to move across the screen and up and down don’t work.

import pygame

#Start pygame

pygame.init()

#Window/Screen/Display

display_x = 1280
display_y = 720
display = pygame.display.set_mode((display_x,display_y))
pygame.display.set_caption('Platforms')

clock = pygame.time.Clock()

#Colors

black = (0,0,0)
green = (1,166,17)

#Images
character = pygame.image.load('character.gif')
def chrctr(x,y):
display.blit(character,(x,y))
x_c = (display_x  / 2)
y_c = (display_y / 2)
x_change = 0
y_change = 0

floor_1 = pygame.image.load('wood.jpg')
def floor(x,y):
    display.blit(floor_1,(x,y))
x = (display_x * 0)
y = (display_y * 0.9)

not_dead=True
while not_dead:
    for event in pygame.event.get():
        if (event.type==pygame.QUIT):
            not_dead=False 

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x_change = - 5
            elif event.key == pygame.K_RIGHT:
                x_change = 5
        if event.key == pygame.K_UP:
                y_change = - 5
        elif event.key == pygame.K_DOWN:
                y_change = 5


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

    x_c += x_change
    if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                y_change = 0

    y_c += y_change

    display.fill(green) 
    pygame.draw.rect(display, black, [0, 550, 200, 50])
    pygame.draw.rect(display, black, [0, 450, 200, 50])
    pygame.draw.rect(display, black, [0, 350, 200, 50])
    pygame.draw.rect(display, black, [0, 250, 200, 50])
    pygame.draw.rect(display, black, [0, 150, 200, 50])
    pygame.draw.rect(display, black, [0, 50, 200, 50])
    pygame.draw.rect(display, black, [1080, 550, 200, 50])
    pygame.draw.rect(display, black, [1080, 450, 200, 50])
    pygame.draw.rect(display, black, [1080, 350, 200, 50])
    pygame.draw.rect(display, black, [1080, 250, 200, 50])
    pygame.draw.rect(display, black, [1080, 150, 200, 50])
    pygame.draw.rect(display, black, [1080, 50, 200, 50])

    floor(0,display_y * 0.9)
    floor(236, display_y * 0.9)
    floor(472, display_y * 0.9)
    floor(708, display_y * 0.9)
    floor(944, display_y * 0.9)
    floor(1180, display_y * 0.9)
    chrctr(x_c, y_c)


    pygame.display.update()
    clock.tick(60)
print ("Hello")

pygame.quit()

Answer

Ok so I made a simple demo where your character (hero) is centered in the screen and you can move him around with the arrow keys. Since there was a lot of refactoring, let me know what stuff I need to clear up in the comments and I will add explanations to this answer.

import pygame
import sys

class Character(object):
    def __init__(self, x=0, y=0, speed=0):
        self.x = x
        self.y = y
        self.speed = speed
        self.image = pygame.image.load('hero.png')

    def get_size(self):
        return self.image.get_size()

    def draw(self):
        display.blit(self.image, (self.x, self.y))

pygame.init()
(width, height) = (800, 600)
display = pygame.display.set_mode((width, height))
pygame.display.set_caption('Platforms')
clock = pygame.time.Clock()
hero = Character(speed=5)
hero_width, hero_height = hero.get_size()
hero.x = width/2.0 - hero_width/2.0
hero.y = height/2.0 - hero_height/2.0
black = (0,0,0)
pressed_keys = {"left": False, "right": False, "up": False, "down": False}

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                pressed_keys["left"] = True
            if event.key == pygame.K_RIGHT:
                pressed_keys["right"] = True
            if event.key == pygame.K_UP:
                pressed_keys["up"] = True
            if event.key == pygame.K_DOWN:
                pressed_keys["down"] = True
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                pressed_keys["left"] = False
            if event.key == pygame.K_RIGHT:
                pressed_keys["right"] = False
            if event.key == pygame.K_UP:
                pressed_keys["up"] = False
            if event.key == pygame.K_DOWN:
                pressed_keys["down"] = False

    if pressed_keys["left"]:# == True is implied here
        hero.x -= hero.speed
    if pressed_keys["right"]:
        hero.x += hero.speed
    if pressed_keys["up"]:
        hero.y -= hero.speed
    if pressed_keys["down"]:
        hero.y += hero.speed

    display.fill(black) 
    hero.draw()
    pygame.display.update()
    clock.tick(60)

EDIT: I see that the pressed_keys dictionary caused some confusion, so I will explain that. You might want to read something like this if my explanation is unclear.

Dictionaries in python are basically like physical dictionaries in real life. Say you are looking up a word like “aardvark” (a key) and want to know what it means. You would open the dictionary book and find the definition (a value) of “aardvark.” Dictionaries are simply a bunch of these key:value pairs.

When I initially created the pressed_keys variable, I defined four key:value pairs, one for each of the directions. The keys were left, right, up, and down while the corresponding values were all False. This should make sense since at the beginning of the game, we are not pressing any buttons and the player is not moving. Lines of code like pressed_keys["left"] = True update the value that matches with the key left in pressed_keys whenever a keypress occurs according to pygame.

After I get all of the events that happened in pygame (window closing, mouse movement, keyboard presses, etc.) at that particular instant of time, I now can check the status of my pressed_keys dictionary. If the value that corresponds to the dictionary key left is True, then I simply shift the hero’s x-position left a little. The same is true for all of the other directions.

Leave a Reply

Your email address will not be published. Required fields are marked *