2008-11-23 8 views
9

Was ist eine gute Methode zur Tastaturbedienung? In jeder Sprache, in der ich eine Tastatur-interaktive Programm (wie ein Tetris-Spiel) zu schreiben, habe ich am Ende einen Code mit, die wie folgt aussieht:Effektive Tastatureingabe

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) 

(verkürzt). Ich mag das nicht, da dies in meiner Hauptschleife liegen muss und es mit allen Teilen des Programms zusammenhängt. Dies macht es auch unmöglich, einen Benutzerkonfigurationsbildschirm zu haben, wo sie ändern können, welcher Schlüssel welcher Aktion zugeordnet ist. Gibt es ein gutes Muster, um dies mit einer Art von Funktionsrückrufen zu tun?

+0

Siehe auch http://stackoverflow.com/questions/292095/polling-the-keyboard-in-python –

Antwort

17

Sie könnten ein Wörterbuch erstellen, in dem der Schlüssel der Eingang und der Wert ist, ist eine Funktion, die die keypress Griffe:

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]() 

Dann Änderung des Schlüssels ist eine Frage des Schlüssel des Wörterbuchs zu ändern.

+0

Ich bin mir nicht sicher, aber ich glaube, dass diese Funktion defs * über * die Zuweisung von Zweig gehen müssen, sonst Du wirst nur ein Wörterbuch voller Nones bekommen. Gute Antwort, so würde ich es wahrscheinlich auch machen. – luqui

+0

ich denke, diese müssen noch innerhalb der main() Schleife definiert werden - oder vielleicht ein Argument zu einer GameState Klasse nehmen – Claudiu

+0

Es könnte besser sein das inverse Wörterbuch zu pflegen: 'func2keys = {handle_quit: [K_q], handle_left: [ K_LEFT, K_a], ...} '. Und generieren Sie ein neues 'Zweig'-Wörterbuch, wenn die Konfiguration geändert wird. 'branch = dict ((k, f) für f, keys in func2keys.items() für k in keys)' – jfs

3

zusätzlich zu superjoe30's answer, können Sie zwei Ebenen von Mapping (zwei Wörterbücher)

  • key => Befehlsfolge
  • Befehl string => Funktion

ich das denken würde Es ist einfacher, benutzerdefinierte Zuordnungen zuzulassen. Das heißt, Benutzer können ihre Schlüssel den "Befehlen" und nicht dem "Namen einer Funktion" zuordnen.

+0

Sie könnten auch einen Namen des Befehls aus dem Docstring der Funktion erhalten. –

+0

Sie können Objekte mit '__call__' Attribut anstelle von Funktionen verwenden. – jfs

2

Was ich heute mache, ist eine Art Eingabe-Klasse/Funktion/Thread, die eine Liste vordefinierter Schlüssel-> prüft Ereignisbindungen.

Etwas wie folgt aus:

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 ist im Grunde, was superjoe30 tut, außer daß anstelle von Rückrufe direkt anrufen, ich eine andere Ebene der Trennung hinzufügen, indem Sie ein Event Dispatching-System, so dass jeder Code, der kümmert sich um die gedrückten Tasten hören einfach auf dieses Ereignis.

Außerdem können Schlüssel leicht an verschiedene Ereignisse gebunden werden, die aus einer Konfigurationsdatei oder etwas gelesen werden können und jeder Schlüssel, der nicht an ein Ereignis gebunden ist, wird einfach ignoriert.

+0

'Wenn das Ereignis nicht ist, None' sieht besser aus. – jfs