Separo e como separo as preocupações de objetos de entrada e de jogo?

20

Provavelmente em todos os jogos que um desenvolvedor precisa, de alguma forma, lidar com a entrada, sejam simples eventos de teclado e mouse, eventos de toque ou algo como entrada do acelerômetro. Essa entrada afeta diretamente objetos no jogo. Às vezes, a mesma entrada pode afetar objetos diferentes. Agora eu tenho pensado em como modelar isso. Na minha opinião, existem duas abordagens diferentes.

  • Deixe o próprio objeto do jogo lidar com isso, assine os eventos e chame seus próprios métodos. Isso tem a vantagem de deixar os próprios objetos do jogo decidirem quais entradas causam qual ação. Uma desvantagem parece ser que o código de entrada é mutilado com o código de objeto do jogo "principal". Além disso, os objetos do jogo desconhecem o estado do restante do jogo e, às vezes, talvez não atuem sobre os eventos de entrada. Isso não parece certo.

  • Peça a um controlador de entrada geral que cuide de toda a entrada e tome decisões sobre quem deve lidar com qual evento. Isso parece separar as preocupações melhor, mas acopla firmemente a classe do controlador de entrada aos objetos do jogo. De alguma forma, é necessário saber quem deseja receber qual evento e em qual estado. Isso também não parece certo.

Quais estratégias você está usando para lidar com isso?

Robert Massa
fonte

Respostas:

7

Eu recomendo separar os eventos de entrada dos objetos do jogo para que você possa alterar / atualizar rapidamente as metodologias de entrada sem precisar editar e depurar 10 classes de objetos. Exemplos passando de controles somente de teclado para mouse + teclado ou simplesmente reatribuindo teclas.

Em vez de acoplar fortemente a entrada aos objetos individuais do jogo, chame apenas um método por sinal de entrada exclusivo no objeto do jogo e deixe-o decidir a maneira de executá-lo.

Use um controlador de entrada para acompanhar o estado da entrada:

Up press event   -> dir = up
Down press event -> dir = down

Sempre que o estado de entrada mudar, avalie se os objetos do jogo estão prontos para serem modificados:

set dir  ->  if gamestate != paused && battlemode == false
             ->  character.changeDir(dir);

Implemente métodos gerais nos objetos do jogo, que podem ser chamados pelo controlador de entrada ou outros objetos do jogo, conforme necessário:

changeDir (dir)
setSpeed (walk/run)
Eduardiano
fonte
7

Eu recomendo a abordagem MVC. No MVC, os objetos do jogo precisam se preocupar em modelar o sistema de jogo e fornecer uma interface de alto nível, como move_left. Em seguida, tenha um objeto controlador que se preocupe com o mapeamento de entrada para modelar chamadas. Ele não apenas permite a troca fácil de controles, como também fornece uma boa interface para a IA, eles são apenas outro controlador.

Na sua segunda opção, eu dividiria o controlador de entrada em duas partes, uma que lida com o toque real do dispositivo, teclado, aceleração, qualquer outra coisa que você possa usar, mapeando-as em um conjunto genérico de entradas. Depois, tenha uma segunda parte que mapeia entradas genéricas para entradas específicas do jogo. Digamos que os teclados para cima mapeiam as setas para a entrada1 e, em seguida, tocar na parte superior da tela de toque também mapeia para a entrada1, agora você escreve uma segunda peça que mapeia a entrada 1 para pular. Agora você pode mapear qualquer dispositivo de E / S, bem como as entradas de reprodução ou AI armazenadas neste sistema de entrada genérico e ter uma pequena parte específica do jogo que carrega o que a entrada1 significa para o modelo.

pedregoso
fonte
5
Há muita discussão em outras partes deste site sobre por que o MVC geralmente não é um padrão apropriado para jogos; o que o stonemetal descreve nem é MVC, é apenas abstração; e "Usar MVC" não é uma resposta, pois o MVC é uma descrição de toda uma classe de arquiteturas e não uma maneira específica de separar preocupações (nem a única maneira de fazê-lo).
2
O MVC deve fornecer a A) um artigo da Wikipedia para ler B) uma série de variações sobre como abordar a solução que foi mostrada para funcionar C) Menciono a maneira como eu a configuraria onde o modelo expõe uma interface de alto nível que o O controlador mapeia a entrada de baixo nível (real ou sintética) para a ação de alto nível e manipula diretamente o modelo em vez de algum sistema de eventos.
Stonemetal
1

Sugiro que o seu jogo (o Modelo ) defina uma lista de possíveis eventos de entrada (implementados como enumerações ou objetos com uma interface básica em comum). Coisas como MovingRightStarted, MovingRightStopped, FiredWeapon1, Escape, etc ...

O jogo define uma estrutura de dados (por exemplo, a queue) que seu código de entrada (o Controlador ) pode preencher com eventos de entrada.

Então seu jogo pode pesquisar a estrutura de dados para obter os eventos de entrada.

Dessa forma, você pode conectar diferentes tipos de controladores para alimentar o modelo:

  • Apenas teclado
  • Teclado + Mouse
  • Controle de video game
  • Tela sensível ao toque
  • Inteligência artificial

Você apenas os tem para enviar eventos de entrada para o modelo.

Splo
fonte
Acho que entendi o que você quis dizer, exceto a escolha de um queuetipo de dados como para armazenar isso. Você poderia explicar o porquê?
Robert Massa
Entre duas pesquisas de eventos de entrada do modelo, o controlador pode ter enviado vários eventos de ação, e é importante manter a ordem de entrada do usuário. Por isso escolhi uma estrutura de dados FIFO. Na verdade, você também pode precisar especificar a que horas a entrada ocorreu.
Splo