Pygame: key.get_pressed () no coincide con la cola de eventos

Estoy intentando elaborar controles simples para una aplicación que utiliza pygame en Python. Tengo los conceptos básicos funcionando, pero estoy golpeando una pared rara: estoy usando las teclas de flecha para controlar mi personaje. Si mantengo presionada una tecla de flecha, luego presiono otra tecla de flecha (para mover en diagonal), el personaje se mueve como se espera. Sin embargo, si suelto la segunda tecla que presioné (mientras aún presiono la primera tecla), el personaje deja de moverse, aunque todavía esté presionando esa primera tecla. Aquí está mi código de movimiento simple:

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) 

Ahora, yo estaba naturalmente muy confundido por esto. Así que intenté imprimir algunas líneas para depurar. En la parte superior del bucle de control principal, escribí:

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

… para generar una tupla que muestre el estado de las teclas de flecha hacia abajo y hacia la derecha, y luego mostrar la cola de eventos de pygame. Mis resultados me desconcertaron aún más. Si muevo el carácter diagonalmente hacia abajo y hacia la derecha, presionando primero la tecla hacia abajo y luego la tecla derecha, luego suelte la tecla derecha para hacer que se mueva simplemente hacia abajo, el personaje deja de moverse como antes … pero esto se imprime en la cubierta:

 (1, 0) [] 

Es decir, cuando suelto la tecla de flecha derecha y aún presiono la tecla de flecha hacia abajo, pygame.key.get_pressed () entiende que la tecla de flecha hacia abajo todavía se mantiene presionada, pero no hay nada en la cola de eventos.

Además, anteriormente en el código (antes del bucle de control) estoy invocando

 pygame.key.set_repeat(1, 2) 

para hacer que el personaje continúe moviéndose mientras se mantiene presionada la tecla.

Cualquier ayuda será apreciada! Gracias 🙂

Para cosas como el movimiento, no debes buscar eventos (como KEYDOWN o KEYUP ), sino verificar cada iteración de tu mainloop si tus teclas de movimiento están presionadas (usando get_pressed ).

En su código, verifica las teclas presionadas solo si también hay un evento KEYDOWN .


También hay algunas otras cosas a considerar:

  • Debes separar la asignación de teclas y la velocidad de tu jugador, para que luego sea más fácil cambiar cualquiera de estos.

  • Debe determinar un vector de movimiento y normalizarlo primero, ya que de lo contrario, si su velocidad de movimiento vertical y horizontal es 10 , su velocidad de movimiento diagonal sería ~ 14 .

Ejemplo de trabajo:

 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) 

simplemente use los datos de retorno de eventos, en lugar de intentar sondear, ya está comprobando si se trata de un tipo de evento de desactivación de teclas, ahora solo interrogue el índice KEY, así:

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

rest de codigo …..

También considere usar una estructura de datos separada para almacenar el estado de sus controles, luego simplemente use los eventos para actualizar esa estructura de datos. Eso ayudará a que los controles sean un poco más flexibles ya que no confiará en la cola de eventos para hacer que su personaje se mueva, lo que en mi experiencia causa problemas como: no poder presionar más de dos botones a la vez, y un retraso impar o problemas de tiempo con los movimientos del personaje. así que algo como:

 keystates={'up':False, 'down':False, 'left':False, 'right':False} running=True #start main pygame event processing loop here while running: for event in pygame.event.get(): if event.type == QUIT: running=False #check for key down events if event.type == KEYDOWN: if event.key == K_UP: keystates['up']=True if event.key == K_DOWN: keystates['down']=True if event.key == K_LEFT: keystates['left']=True if event.key == K_RIGHT: keystates['right']=True #check for key up events if event.type == KEYUP: if event.key == K_UP: keystates['up']=False if event.key == K_DOWN: keystates['down']=False if event.key == K_LEFT: keystates['left']=False if event.key == K_RIGHT: keystates['right']=False #do something about the key states here, now that the event queue has been processed if keystates['up']: character.moveUp() #or whatever your call for these are... if keystates['down']: character.moveDown() if keystates['left']: character.moveLeft() if keystates['right']: character.moveRight() #gracefully exit pygame here pygame.quit() 

Está utilizando una entrada basada en eventos, pero en este caso desea una entrada basada en sondeo. Entonces no te metes con las repeticiones de teclas.

 import pygame from pygame.locals import * done = False player.pos = Rect(0,0,10,10) while not done: for event in pygame.event.get(): # any other key event input if event.type == QUIT: done = True elif event.type == KEYDOWN: if event.key == K_ESC: done = True elif event.key == K_F1: print "hi world mode" # get key current state keys = pygame.key.get_pressed() if keys[K_LEFT]: player.pos.left -= 10 if keys[K_RIGHT]: player.pos.left += 10 if keys[K_UP]: player.pos.top -= 10 if keys[K_DOWN]: player.pos.left += 10 if keys[K_SPACE]: print 'firing repeated gun' 

Mi conjetura es que la repetición de conjuntos no funciona de la manera que usted cree que funcionará Básicamente, después de que su segunda tecla suba, la repetición no ocurre. Esto parece tener sentido para mí: abre un editor de texto y mantén presionada la tecla “A”. “A” se dertwigrá a través de la pantalla. Luego, presione la tecla “J” con la tecla “A” aún presionada. Las “A” se detienen. Ese es un sistema típico de repetición de claves.

No estoy seguro de que usar este método “set_repeat” vaya a funcionar al final de todos modos. Básicamente, cualquier tecla que el jugador presione ahora se “repetirá”, incluso si hace clic en “disparar” o “saltar”.

Como alternativa, intente guardar el estado cuando el usuario presiona o suelta. No use set_repeat, pero haga algo como lo siguiente:

 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.moving_left = True if pygame.key.get_pressed()[K_RIGHT]: player.moving_right = True if pygame.key.get_pressed()[K_UP]: player.moving_up = True if pygame.key.get_pressed()[K_DOWN]: player.moving_down = True elif event.type == KEYUP: if pygame.key.get_pressed()[K_LEFT]: player.moving_left = False if pygame.key.get_pressed()[K_RIGHT]: player.moving_right = False if pygame.key.get_pressed()[K_UP]: player.moving_up = False if pygame.key.get_pressed()[K_DOWN]: player.moving_down = False # Somewhere else in your game loop... if player.moving_left: player.pos[0] -= 2 if player.moving_right: player.pos[0] += 2 if player.moving_up: player.pos[1] -= 2 if player.moving_right: player.pos[1] += 2