Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
500 views
in Technique[技术] by (71.8m points)

python - Pygame: key.get_pressed() does not coincide with the event queue

I'm attempting to work out simple controls for an application using pygame in Python. I have got the basics working, but I'm hitting a weird wall: I am using the arrow keys to control my character. If I hold down one arrow key, then hold down another arrow key (to move diagonally), the character moves as expected. However, if I release the second key that I pressed (while still holding down the first key), the character stops moving, even though I am still holding down that first key. Here is my simple movement code:

for event in pygame.event.get():
    if event.type == QUIT:
        pygame.quit()
        sys.exit()
    elif event.type == KEYDOWN:
        if pygame.key.get_pressed()[K_LEFT]:
            player.pos = (player.pos[0] - 2, player.pos[1])
        if pygame.key.get_pressed()[K_RIGHT]:
            player.pos = (player.pos[0] + 2, player.pos[1])
        if pygame.key.get_pressed()[K_UP]:
            player.pos = (player.pos[0], player.pos[1] - 2)
        if pygame.key.get_pressed()[K_DOWN]:
            player.pos = (player.pos[0], player.pos[1] + 2)

Now, I was naturally very confused by this. So I tried to print some lines to debug. In the top of the main control loop, I wrote:

print (pygame.key.get_pressed()[K_DOWN], pygame.key.get_pressed()[K_RIGHT])
print pygame.event.get()

...to output a tuple displaying the state of the down and right arrow keys, and then display the pygame event queue. My results baffled me even more. If I move the character diagonally down and right, pressing the down key first and then the right key, then release the right key to make it move simply downward, the character stops moving as before... but this is printed to the shell:

(1, 0)
[]

That is, when I release the right arrow key and still hold down the down arrow key, pygame.key.get_pressed() understands that the down arrow key is still being held down, but there is nothing in the event queue.

Also, earlier in the code (before the control loop) I am invoking

pygame.key.set_repeat(1, 2)

to make the character continue to move while the key is held down.

Any help will be appreciated! Thanks :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For things like movement, you should not check for events (like KEYDOWN or KEYUP), but check every iteration of your mainloop if your movement keys are pressed (using get_pressed).

In your code, you check the pressed keys only if there's also a KEYDOWN event.


There are also some other things to consider:

  • You should seperate the key-mapping and the speed of your player, so it will be easier later on to change either of this.

  • You should determine a movement vector and normalize it first, since otherwise, if your vertical and horizontal movement speed is 10, your diagonal movement speed would be ~14.

Working example:

import pygame

pygame.init()

screen = pygame.display.set_mode((200, 200))
run = True
pos = pygame.Vector2(100, 100)
clock = pygame.time.Clock()

# speed of your player
speed = 2

# key bindings
move_map = {pygame.K_LEFT: pygame.Vector2(-1, 0),
            pygame.K_RIGHT: pygame.Vector2(1, 0),
            pygame.K_UP: pygame.Vector2(0, -1),
            pygame.K_DOWN: pygame.Vector2(0, 1)}

while run:
  for e in pygame.event.get():
    if e.type == pygame.QUIT: run = False

  screen.fill((30, 30, 30))
  # draw player, but convert position to integers first
  pygame.draw.circle(screen, pygame.Color('dodgerblue'), [int(x) for x in pos], 10)
  pygame.display.flip()

  # determine movement vector
  pressed = pygame.key.get_pressed()
  move_vector = pygame.Vector2(0, 0)
  for m in (move_map[key] for key in move_map if pressed[key]):
    move_vector += m

  # normalize movement vector if necessary
  if move_vector.length() > 0:
    move_vector.normalize_ip()

  # apply speed to movement vector
  move_vector *= speed

  # update position of player
  pos += move_vector

  clock.tick(60)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...