“You should name a variable using the same care with which you name a first-born child.”
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
Related Stack Overflow questions:
How to get keyboard input in pygame?
How can I make a sprite move when key is held down
📁 minimal example - Move object with keys
repl.it/@Rabbid76/PyGame-ContinuousMovement
📁 minimal example - Move object with keys limit it to the window borders
📁 minimal example - Move object fast when key is hit twice
📁 minimal example - Move object fast when key is in opposite direction is hit
I have a function that detects if i press a key in pygame, but it only detects one key?
📁 minimal example - Move object with keys continuous or step by step.py
How can I allow keyboard inputs to override each other in pygame?
When does it make sense to use keyboard events (pygame.KEYDOWN
, pygame.KEYUP
see pygame.event
), and when is it better to get the state of the keys (pygame.key.get_pressed()
)?
pygame.key.get_pressed()
returns a sequence with the state of each key. If a key is held down, the state for the key is 1
, otherwise 0
. It is a snapshot of the keys at that very moment The new state of the keys must be retrieved continuously in each frame. So you can calculate the resulting movement when 2 keys are pressed with keys[pygame.K_d] - keys[pygame.K_a]
and keys[pygame.K_s] - keys[pygame.K_w]
. Use pygame.key.get_pressed()
to evaluate the current state of a button and get continuous movement.
while True:
keys = pygame.key.get_pressed()
x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed
y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN
event occurs once every time a key is pressed. KEYUP
occurs once every time a key is released. Use the keyboard events for a single action like jumping or spawning a bullet or a step-by-step movement.
Single Action:
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
fire_bullet()
Step-by-step movement:
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x -= speed
if event.key == pygame.K_RIGHT:
x += speed
if event.key == pygame.K_UP:
y -= speed
if event.key == pygame.K_DOWN:
y += speed
Related Stack Overflow questions:
How can i shoot a bullet with space bar?
How do I stop more than 1 bullet firing at once?
The general approach to firing bullets is to store the positions of the bullets in a list (bullet_list
). When a bullet is fired, add the bullet’s starting position ([start_x, start_y]
) to the list. The starting position is the position of the object (player or enemy) that fires the bullet. Use a for
-loop to iterate through all the bullets in the list. Move position of each individual bullet in the loop. Remove a bullet from the list that leaves the screen (bullet_list.remove(bullet_pos)
). For this reason, a copy of the list (bullet_list[:]
) must be run through (see How to remove items from a list while iterating?). Use another ` for-loop to
blit` the remaining bullets on the screen:
bullet_list = []
while run == True:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_list.append([start_x, start_y])
for bullet_pos in bullet_list[:]:
bullet_pos[0] += move_bullet_x
bullet_pos[1] += move_bullet_y
if not screen.get_rect().colliderect(bullet_image.get_rect(center = bullet_pos))
bullet_list.remove(bullet_pos)
# [...]
for bullet_pos in bullet_list[:]
screen.blit(bullet_image, bullet_image.get_rect(center = bullet_pos))
# [...]
What does pygame.key.get_pressed()
do?
Related Stack Overflow questions:
Related Stack Overflow questions:
What is pygame.KEYDOWN
, pygame.KEYUP
?
Related Stack Overflow questions:
The keyboard events KEYDOWN
and KEYUP
(see pygame.event module) create a pygame.event.Event
object with additional attributes. The key that was pressed can be obtained from the key
attribute (e.g. K_RETURN
, K_a
) and the mod
attribute contains a bitset with additional modifiers (e.g. KMOD_LSHIFT
). The unicode
attribute provides the Unicode representation of the keyboard input.
pygame.key.get_pressed()
returns a list with the state of all keyboard buttons. This is not intended to get the key of a keyboard event. The key that was pressed can be obtained from the key
attribute of the pygame.event.Event
object:
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
# [...]
unicode
contains a single character string that is the fully translated character:
if event.type == pg.KEYDOWN:
if event.unicode == 'a':
# [...]
See also pygame.event
module and pygame.key.
If you press UP + LEFT + SPACE then the SPACE key doesn’t appear to be pressed immediately. You’ve to release the UP or LEFT key to get the pygame.KEYDOWN
event for SPACE.
This is a known bug in pygame and doesn’t seem to be solved yet: Incorrect handling of pressed keys #235.
Sadly even pygame.key.get_pressed()
doesn’t state the SPACE key in this case, so I can’t even think a workaround.
While pygame.K_f
is a key enumerator constant (see pygame.key
) the content of event.type
is event enumerator constant (see pygame.event
).
If you want to determine if a certain key is pressed, the you’ve to verify if the event type is pygame.KEYDOWN
(or pygame.KEYUP
for button release) and if the .key
attribute of the event is equal the key enumerator. e.g.:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quit()
# [...]
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_f:
# [...]
Related Stack Overflow questions:
A user friendly name of a key can be get by pygame.key.name()
:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))