Pergunta

O que é uma boa maneira de implementar manipulação de teclado? Em qualquer língua, onde eu escrever um programa de teclado interativo (como um jogo de tetris), eu acabar tendo algum código parecido com este:

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)

(encurtado). Eu não gosto, como este tem que ir no meu loop principal, e isso mexe com todas as partes do programa. Isso também faz com que seja impossível ter uma tela de configuração do usuário onde eles podem mudar qual tecla mapeia para qual a ação. Existe um bom padrão de fazer isso usando alguma forma de retornos de chamada de função?

Foi útil?

Solução

Você pode criar um dicionário onde as chaves são a entrada e o valor é uma função que manipula o keypress:

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

Em seguida, alterando as chaves é uma questão de modificar chaves do dicionário.

Outras dicas

Além de superjoe30 resposta , você pode usar dois níveis de mapeamento (dois dicionários)

  • key => string de comando
  • string command => função

Eu acho que isso tornaria mais fácil para permitir mapeamentos definidos pelo usuário. ou seja, para que os usuários podem mapear suas chaves com "comandos" em vez de "o nome de uma função"

O que eu faço hoje em dia é ter algum tipo de entrada de coleta de classe / função / discussão que irá verificar uma lista de pré-definido chave-> ligações de eventos.

Algo parecido com isto:

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

É basicamente o que superjoe30 está fazendo, só que em vez de chamar retornos de chamada diretamente, eu adicionar outro nível de separação usando um evento do sistema despachar, de modo que qualquer código que se preocupa com as teclas sendo pressionadas simplesmente ouvir para esse evento.

Além disso, as chaves podem ser facilmente vinculados a diferentes eventos, que poderiam ser lidos de um arquivo de configuração ou algo assim e qualquer tecla que não esteja vinculado a um evento é simplesmente ignorado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top