Nota: Preciso pesquisar, em vez de fazer retornos de chamada devido às limitações da API (SFML). Também peço desculpas pela falta de um título "decente".
Eu acho que tenho duas perguntas aqui; como registrar a entrada que estou recebendo e o que fazer com ela.
Manipulação de entrada
Estou falando após o fato de você ter registrado que a tecla 'A' foi pressionada, por exemplo, e como fazê-lo a partir daí.
Eu já vi uma variedade de todo o teclado, algo como:
bool keyboard[256]; //And each input loop check the state of every key on the keyboard
Mas isso parece ineficiente. Você não apenas está acoplando a tecla 'A' ao 'jogador que se move para a esquerda', por exemplo, mas também verifica todas as teclas, 30 a 60 vezes por segundo.
Então tentei outro sistema que apenas procurava as chaves que queria.
std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.
No entanto, o problema é que agora não posso digitar um nome, por exemplo, sem precisar vincular todas as chaves.
Então, eu tenho o segundo problema, pelo qual não consigo realmente pensar em uma boa solução para:
Entrada de envio
Agora eu sei que a tecla A foi pressionada ou que playerLeft é verdadeiro. Mas como eu vou daqui?
Pensei em apenas checar
if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
Isto acopla muito a entrada às entidades, e acho isso bastante confuso. Prefiro que o jogador lide com seu próprio movimento quando for atualizado. Eu pensei que algum tipo de sistema de eventos poderia funcionar, mas não sei como fazê-lo. (Ouvi sinais e slots eram bons para esse tipo de trabalho, mas aparentemente é muito lento e não consigo ver como se encaixaria).
Obrigado.
fonte
Eu acho que a discussão do OP está reunindo várias coisas e que o problema pode ser simplificado substancialmente, dividindo-o um pouco.
Minha sugestão:
Mantenha sua matriz de estados de chaves. Não há uma chamada de API para obter todo o estado do teclado de uma só vez? (A maior parte do meu trabalho é em consoles, e mesmo no Windows para um controlador conectado, você obtém todo o estado do controlador de uma só vez.) Os estados das teclas são um mapa "rígido" nas teclas do teclado. Não traduzido é o melhor, mas, no entanto, você obtém as APIs com mais facilidade.
Em seguida, mantenha algumas matrizes paralelas que indicam se a chave subiu nesse quadro, outra indicando que ela desceu e uma terceira para indicar simplesmente que a chave está "inativa". Talvez ative um cronômetro para que você possa acompanhar quanto tempo a chave está em seu estado atual.
Em seguida, crie um método para criar um mapeamento de chaves para ações. Você vai querer fazer isso algumas vezes. Uma vez para as coisas da interface do usuário (e tenha o cuidado de consultar os mapeamentos do Windows, porque você não pode assumir o scancode ao pressionar 'A' atribuirá um A no computador do usuário). Outro para cada "modo" no jogo. Estes são os mapeamentos de códigos de chave para ações. Você pode fazer isso de duas maneiras: uma seria manter uma enumeração usada pelo sistema receptor; outra seria um ponteiro de função indicando a função a ser chamada em uma mudança de estado. Talvez até um híbrido dos dois, dependendo de seus objetivos e necessidades. Com esses "modos", você pode empurrá-los e colocá-los em uma pilha do modo do controlador, com sinalizadores que permitem que entradas ignoradas continuem descendo pela pilha ou o que for.
Finalmente, lide com essas ações-chave de alguma forma. Para movimento, você pode querer fazer algo complicado, traduza 'W' para baixo para significar "avançar", mas não precisa ser uma solução binária; você pode fazer com que "W esteja inativo" signifique "aumentar a velocidade em X até um máximo de Y" e "W esteja ativo" para "diminuir a velocidade em Z até atingir zero". De um modo geral, você deseja que sua "interface de manipulação de controlador nos sistemas de jogo" seja bastante estreita; faça toda a tradução das chaves em um só lugar e use os resultados em qualquer outro lugar. Isso contrasta com a verificação direta para ver se a barra de espaço é pressionada em qualquer lugar aleatório do código, porque se estiver em algum local aleatório, provavelmente será atingido em algum momento aleatório quando você não quiser, e você simplesmente não não quero lidar com isso ...
Eu realmente detesto projetar padrões e acho que os componentes trazem mais custo do que bom desenvolvimento, por isso não mencionei nenhum deles. Os padrões surgirão se eles estiverem destinados, assim como os componentes, mas começar a fazê-lo desde o início apenas complicará sua vida.
fonte
No SFML, você tem as teclas na ordem em que foram pressionadas com o tipo de evento KeyPressed. Você processa cada chave por um tempo (getNextEvent ()).
Portanto, se a tecla pressionada estiver no seu mapa Key-> Action, execute a ação correspondente e, se não estiver, encaminhe-a para qualquer widget / material que possa precisar.
Em relação à sua segunda pergunta, eu recomendo que você continue assim, pois facilita o ajuste na jogabilidade. Se você usar sinais ou outros, precisará fazer um slot para o "RunKeyDown" e outro para o "JumpKeySlot". Mas o que acontece se no seu jogo uma ação especial é realizada quando os dois são pressionados?
Se você quiser correlacionar entradas e entidades, você pode transformar sua entrada em um Estado (RunKey = true, FireKey = false, ...) e enviá-la ao jogador como você envia qualquer outro evento para suas IAs.
fonte
A solução correta geralmente é uma combinação dos dois métodos que você discute:
Para a funcionalidade de jogo com um conjunto predefinido de chaves, a pesquisa de todos os quadros é completamente apropriada e você deve pesquisar apenas as chaves que estão realmente ligadas a alguma coisa. Na verdade, isso é análogo ao modo como você consultaria a entrada do controlador em um jogo de console; ele será inteiramente pesquisado, especialmente quando se trata de dispositivos de entrada analógica. Durante o jogo em geral, você provavelmente deseja ignorar os eventos de pressionamento de tecla e usar a pesquisa.
Quando se trata de digitar entradas para coisas como nomes, você deve mudar o jogo para um modo diferente de manipulação de entradas. Por exemplo, assim que o prompt "digite seu nome" aparecer, você poderá modificar o que o código de entrada faz. Ele pode escutar eventos de pressionamento de tecla por meio de alguma interface de retorno de chamada ou pode iniciar a busca de cada tecla, se necessário. Acontece que, normalmente, durante a digitação de eventos, você não se importa tanto com o desempenho, de modo que a pesquisa não será tão ruim.
Portanto, você deseja usar a pesquisa seletiva para entrada no jogo e a manipulação de eventos para entradas de digitação de nome (ou todas as pesquisas de teclado, se a manipulação de eventos não estiver disponível).
fonte
Eu gosto muito da resposta do dash-tom-bang, ela realmente destaca alguns aspectos que você deve ter em mente ao projetar um sistema de entrada.
Eu gostaria de adicionar um pequeno tutorial que encontrei na mesma direção (incluindo contextos de entrada, 3 camadas, ...):
http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/
fonte