Desenvolvimento orientado a testes para jogos complexos

8

Estou codificando um jogo no meu tempo livre, mas ainda sou iniciante na programação. Sinto muito se esta questão está fora de tópico ou se acaba não sendo útil para mais ninguém, mas espero que seja.

Passei muito tempo lendo livros sobre o design do código, bem como diferentes metodologias e abordagens para a codificação. No curso desta pesquisa, continuo me deparando com o conceito de Desenvolvimento Orientado a Testes. As pessoas que adotam essa idéia geralmente parecem muito apaixonadas por ela. Eu acredito que isso pode ajudar a velocidade e eficiência de escrever software. O tempo é um recurso muito precioso, por isso prefiro aprender a fazer as coisas da melhor maneira do que ficar confuso sem tentar expandir meus conhecimentos sobre o ofício da programação.

De qualquer forma, possivelmente porque sou iniciante, não consigo imaginar como aplicar o desenvolvimento orientado a testes nos jogos. Encontrei alguns artigos sobre o assunto, mas eles não foram muito úteis. A maioria dos exemplos de testes de unidade que eu vi são exemplos muito simples, ou exemplos de software que não é de todo um jogo.

Na minha própria codificação, tento abordá-lo com uma mentalidade semelhante para testar o desenvolvimento orientado, embora eu tenha certeza de que ele não se qualifica como TDD. Escrevo a quantidade mínima de código para tentar implementar qualquer recurso que estou adicionando ao jogo e testo imediatamente o jogo para ver se funciona. Se as coisas não acontecerem como eu pretendia, faço alterações imediatamente para aproximar-me do que quero. Se não estiver funcionando ou quebrado, e se não conseguir encontrar os erros lendo o código, passo os métodos no depurador até encontrar o comportamento inesperado e removo-o. O que estou tentando dizer é que estou constantemente testando o jogo, praticamente após cada mudança incremental. Testar impulsiona meu desenvolvimento. O "teste de unidade" está na minha cabeça,

Para a minha pergunta real. Como escrever testes de unidade para um jogo complexo? Por complexo, quero dizer com muitos aspectos emergentes da jogabilidade, de modo que a carne da jogabilidade emerge da interação entre os muitos elementos diferentes dentro do jogo combinados com as escolhas do jogador. Por exemplo, um rpg roguelike com um mundo processual. Que tipo de testes de unidade alguém escreveria para um jogo como esse? Como se poderia aplicar o desenvolvimento orientado a testes para esse jogo?

bazola
fonte
2
Esse rei das perguntas pode ser mais adequado à seção Desenvolvimento de jogos: gamedev.stackexchange.com
glampert
1
Vale a pena notar que o desenvolvimento orientado a testes encoraja você a dividir seu projeto em pequenas unidades gerenciáveis. Uso testes de unidade para testar a lógica que pode ou não ser usada para a funcionalidade do projeto; em vez disso, às vezes, seu objetivo é testar o próprio conceito. Olhar para amadurecer jogos de código aberto para bons exemplos de trabalho de como o teste de unidade pode ser usado no desenvolvimento de jogos
Keldoniano Alleyne

Respostas:

12

Os testes de unidade não testam a jogabilidade . Não há critérios programáticos para ver se um jogo é divertido ou se um nível é a dificuldade certa. Os testes de unidade testarão se o seu mapgen roguelike realmente produz um nível com uma escada para cima e uma escada para baixo. Ele testará se suas regras de oneração estão configuradas e se seu personagem realmente se move mais devagar quando ponderado. Isso garantirá que seu personagem não possa usar 50 chapéus . Isso garantirá que todas as mecânicas sejam implementadas corretamente em relativo isolamento.

Telastyn
fonte
1
Sua resposta me ajuda a entender as coisas um pouco melhor, mas não completamente. Pelo meu entendimento, para que seja realmente um desenvolvimento orientado a testes, os testes devem ser escritos primeiro. Portanto, escreva testes com falha, escreva o código para fazê-lo passar e corrija o código. Como isso pode ser aplicado para testar se um mapgen produz um nível com escadas para cima e para baixo? Que tipo de teste de unidade atenderia aos requisitos do TDD?
22414 bazola
1
@ azola - eu tenho medo que eu não entendo? Você escreve um teste para chamar o mapgen e depois verifica se o resultado tem escadas para cima e para baixo. Isso não compila, pois você tem um mapa nem o conceito de escada. Então você faz isso. Então você faz o mapgen realmente cumprir os critérios ...
Telastyn
Isso faz sentido. Muito apreciado!
22414 bazola
4
Relevante: TDD não significa necessariamente que seus testes de unidade são o único driver no desenvolvimento. Você pode iniciar o "drive" escrevendo um teste de "aceitação" e / ou integração com falha de alto nível, do qual você pode conceber uma solução e escrever seu primeiro teste de unidade com falha ... porém, sinceramente, não tenho certeza do que é preciso escrever um teste de aceitação automatizado e significativo para um jogo não trivial.
Svidgen
2

É difícil escrever testes de unidade para códigos não determinísticos. Se você tiver um código envolvendo números aleatórios, não poderá escrever um teste de unidade que afirme o resultado esperado.

Portanto, os testes de unidade são mais apropriados para o código determinístico. Quando dou a um método essas entradas, espero essas saídas. Como exemplo: quando um lutador com 15 pontos de força usa sua espada de duas mãos para acertar com sucesso um ghoul morto-vivo com 10 armaduras, espero 8 de dano. A parte não determinística (se a ocorrência foi bem-sucedida ou não) não pode necessariamente ser testada em unidade, mas o que acontece depois disso pode ser. Mesmo que se espere que a quantidade de dano esteja dentro de um intervalo, você pode testar isso.

Se você estiver com dificuldade para encontrar código para escrever testes de unidade, precisará refatorar para que a lógica determinística seja isolada em métodos ou classes. Jogue os dados primeiro para determinar o sucesso e depois passe as informações relevantes (classe, força, armadura etc.) para um método testável.

Para o seu comentário sobre ter o teste de unidade em sua cabeça, o objetivo do teste de unidade não é apenas um código recém-escrito. Também é preciso ter confiança de que o código ainda funcionará após fazer alterações inevitáveis .

Sam Jones
fonte
3
Uma maneira de testar o código da unidade que usa a aleatoriedade é executá-lo várias vezes e verificar se os resultados estão estatisticamente em conformidade com a distribuição esperada. Portanto, quando um ataque deve causar 10 + 2d6 de dano, você executa o código 1000 vezes e verifica se não há resultado maior que 22, menor que 12 e se existe uma distribuição aproximadamente em forma de sino nesse intervalo.
Philipp
1
Você também pode aplicar esse método a situações mais complexas, como garantir que um personagem de nível 1 vença uma luta simulada contra um duende cerca de 90% das vezes.
Philipp
3
Normalmente, se parte do seu código usa números aleatórios, você abstrai seu gerador de números aleatórios em um serviço ( IRandomNumberGenerator) e qualquer coisa que precise usar números aleatórios aceita uma referência a essa interface de serviço em seu construtor. Então, quando seu teste cria esse objeto para executar um teste de unidade, ele injeta um MockRandomNumberGeneratorque alimenta um fluxo conhecido fixo de números. Então você tem um teste repetível. A mesma idéia é útil para qualquer coisa que precise obter a data / hora atual ou baixar informações de um serviço da Web - basta injetar um serviço simulado.
Scott Whitlock
... então você pode escrever um teste separado que usa métodos estatísticos para verificar o funcionamento real de sua implementação real de RandomNumberGenerator.
Scott Whitlock
Eu votaria se pudesse. As características estatísticas do resultado devem ser testadas para o algoritmo aleatório.
Riga