2008-11-23 29 views
9

¿Cuál es una buena manera de implementar el manejo del teclado? En cualquier idioma, donde escribo un programa de teclado interactivo (como un juego de Tetris), que acaban de tener un código que se parece a esto:Manejo efectivo de la entrada del teclado

for event in pygame.event.get(): 
    if event.type == KEYDOWN: 
     if False: pass   #make everything an elif 
     elif rotating: pass 
     elif event.key == K_q: 
     elif event.key == K_e: 
     elif event.key == K_LEFT: 
      curpiece.shift(-1, 0) 
      shadowpiece = curpiece.clone(); setupshadow(shadowpiece) 
     elif event.key == K_RIGHT: 
      curpiece.shift(1, 0) 
      shadowpiece = curpiece.clone(); setupshadow(shadowpiece) 

(abreviada). No me gusta esto, ya que esto tiene que ir en mi ciclo principal, y se mete con todas las partes del programa. Esto también hace que sea imposible tener una pantalla de configuración de usuario donde puedan cambiar qué mapas de teclas y qué acción. ¿Hay un buen patrón para hacer esto usando alguna forma de devoluciones de función?

+0

También vea http://stackoverflow.com/questions/292095/polling-the-keyboard-in-python –

Respuesta

17

Se puede crear un diccionario donde las claves son la entrada y el valor es una función que se encarga de la pulsación de tecla:

def handle_quit(): 
    quit() 

def handle_left(): 
    curpiece.shift(-1, 0) 
    shadowpiece = curpiece.clone(); setupshadow(shadowpiece) 

def handle_right(): 
    curpiece.shift(1, 0) 
    shadowpiece = curpiece.clone(); setupshadow(shadowpiece) 

def handle_pause(): 
    if not paused: 
     paused = True 

branch = { 
    K_q: handle_quit 
    K_e: handle_pause 
    K_LEFT: handle_left 
    K_RIGHT: handle_right 
} 

for event in pygame.event.get(): 
    if event.type == KEYDOWN: 
     branch[event.key]() 

A continuación, cambiar las claves es una cuestión de modificar las claves del diccionario.

+0

No estoy seguro, pero creo que las funciones defs tienen que ir * arriba * a la asignación de la rama, de lo contrario obtendrás un diccionario lleno de Nones. Buena respuesta, sin embargo, esta es probablemente la forma en que lo haría también. – luqui

+0

Supongo que aún tendrán que definirse dentro del bucle principal() o tal vez llevar un argumento a una clase GameState – Claudiu

+0

Sería mejor mantener el diccionario inverso: 'func2keys = {handle_quit: [K_q], handle_left: [ K_LEFT, K_a], ...} '. Y genere un nuevo diccionario 'branch' si se cambia la configuración. 'branch = dict ((k, f) para f, teclas en func2keys.items() para k en claves)' – jfs

3

además de superjoe30's answer, se pueden utilizar dos niveles de mapeo (dos diccionarios)

  • clave => cadena de comandos
  • cadena de comandos => función

Creo que esto haría es más fácil permitir asignaciones definidas por el usuario. es decir, los usuarios pueden asignar sus claves a "comandos" en lugar de "el nombre de una función"

+0

También podría obtener un nombre del comando fuera de la función docstring. –

+0

Puede usar objetos con el atributo '__call__' en lugar de funciones. – jfs

2

Lo que hago hoy en día es tener algún tipo de clase de recopilación de datos/función/hilo que verificará una lista de teclas predefinidas-> enlaces de eventos.

Algo como esto:

class InputHandler: 
    def __init__ (self, eventDispatcher): 
     self.keys = {} 
     self.eventDispatcher = eventDispatcher 
    def add_key_binding (self, key, event): 
     self.keys.update((key, event,)) 
    def gather_input (self): 
     for event in pygame.event.get(): 
      if event.type == KEYDOWN: 
       event = self.keys.get(event.key, None) 
       if not event is None: 
        self.eventDispatcher.dispatch(event) 

.... 
inputHandler = InputHandler(EventDispatcher) 
inputHandler.add_key_binding(K_q, "quit_event") 
... 
inputHandler.gather_input() 
.... 

Es básicamente lo superjoe30 está haciendo, excepto que en lugar de llamar directamente devoluciones de llamada, añado otro nivel de separación mediante el uso de un evento sistema de despacho, por lo que cualquier código que se preocupa por las teclas presionadas simplemente escuchan ese evento.

Además, las claves se pueden vincular fácilmente a diferentes eventos, que se pueden leer desde un archivo de configuración o algo así y cualquier clave que no esté vinculada a un evento simplemente se ignora.

+0

'if event is not None' se ve mejor. – jfs

Cuestiones relacionadas