AI de combate realista para jogo 2D

imagem

Embora o Close Quarters seja predominantemente um jogo multiplayer, ainda existem bots complexos de IA para manter os jogadores jogando quando a conexão com a Internet é ruim ou não há outros jogadores online. Além disso, os bots desempenham um papel importante de suporte em alguns modos de jogo. Portanto, eles devem se comportar com credibilidade e demonstrar um conjunto de comportamentos complexos, incluindo o uso de abrigos, o uso de objetos no momento certo, contornando os flancos, jogando granadas e fugindo deles.

Ambiente e restrições


O ambiente de jogo consiste em polígonos. A maioria dos polígonos bloqueia o movimento, a visibilidade e o disparo, mas também existem polígonos “baixos” que apenas bloqueiam o movimento. O ambiente está totalmente coberto de obstáculos e abrigos.

A IA também é limitada por vários fatores técnicos. O mais importante deles: o servidor no qual os bots são executados, quando há poucos jogadores on-line, deve trabalhar rapidamente em um VPS barato com pelo menos dez bots. Além disso, a carga da CPU deve permanecer baixa o suficiente para permitir várias instâncias do servidor no mesmo VPS, sem exceder o limite da CPU e sem causar sanções por parte do provedor de serviços VPS.


Figura 1: ambientes


Figura 2: vista da face do jogador, obstáculos que impedem a visualização (áreas cinzas são invisíveis para ele)

Malha de navegação e visibilidade, busca tática de uma maneira


Os robôs usam uma malha de navegação densa que consiste em pontos discretos. A malha é gerada da seguinte forma: primeiro, os polígonos que compõem o ambiente são expandidos e combinados . Nós adicionais são adicionados perto dos cantos, porque é mais provável que esses locais sejam posições de abrigo adequadas. O espaço de movimento resultante é então triangulado para gerar uma malha.


Figura 3: malha de navegação

Como os robôs devem realizar uma busca tática pelo caminho , a malha de navegação deve conter dados de visibilidade que permitem verificar rapidamente se o nó contém abrigo do inimigo selecionado. Portanto, cada nó contém uma matriz de 24 bytes, cada um dos quais representa uma distância aproximada pré-calculada entre o nó e o obstáculo mais próximo, bloqueando o campo de visão em uma determinada direção.


Figura 4: Dados de visibilidade armazenados no nó (linhas azuis). Cada linha representa um valor de byte único que define a visibilidade em uma determinada direção.

Graças a esses dados, você pode pesquisar os gráficos usando o algoritmo A *na malha de navegação, na qual os nós que podem ser abertos para inimigos conhecidos recebem prioridade mais baixa sem verificações dispendiosas da linha de visão. Para verificar se um determinado nó está aberto ao inimigo, determinamos a direção e a distância do nó ao inimigo e, em seguida, verificamos se essa distância é menor que a distância armazenada no elemento da matriz mais próximo dessa direção. Além disso, podemos verificar se o inimigo está olhando para o nó. Em seguida, podemos aplicar o fator de penalidade ao custo de mover-se pelos nós abertos aos inimigos, e o caminho resultante tenderá a evitar esses nós.

Os mesmos dados de visibilidade, além de encontrar o caminho entre dois pontos dados, podem ser usados ​​para outras ações "táticas". Por exemplo, o bot procura abrigo realizando uma pesquisa abrangente e para assim que encontra um site protegido. Testes de linha de visão são usados ​​para verificar se o local realmente oferece abrigo. Da mesma forma, podemos gerar caminhos de ataque a partir dos flancos pesquisando A * pelo alvo; ao mesmo tempo, multas altas são impostas aos nós abertos dentro do cone de tiro ao alvo. A busca para assim que alcançamos um nó aberto fora deste cone de disparo. (Um dos problemas dessa abordagem é que os robôs que ficam fora do escopo constantemente tentam se aproximar da meta e, portanto, parecem muito agressivos; isso provavelmente pode ser corrigido definindo a heurística A * parapara que o bot não se mova diretamente para o alvo, mas para quaisquer nós localizados a uma distância selecionada do alvo).

Sentimentos e memória de bots


Para que os bots se comportem de forma convincente, eles não devem parecer trapaceiros. Em outras palavras, as informações com as quais o bot trabalha devem ser semelhantes às informações que o jogador possui. Por exemplo, o inimigo por trás do obstáculo deve ser invisível para o bot, assim como não é visível para o jogador.


Existem duas maneiras pelas quais um jogador pode detectar a posição de um inimigo: ele pode ver o inimigo ou ouvir como ele se move, atira ou executa alguma outra ação.

Cada bot mantém uma lista de "fatos" conhecidos sobre as posições e a direção do olhar dos inimigos. Sem atualizações, esses fatos são excluídos após dez segundos. Um fato relacionado a um inimigo específico é atualizado quando o bot pode ouvir ou ver esse inimigo. Quando um bot ouve um inimigo, para simular incertezas, a posição do fato correspondente é deslocada da posição real do inimigo em uma direção e distância aleatórias, dependendo de quão perto o bot estava o som (veja o vídeo, 1:28).


Figura 5: fatos (círculos cor de rosa) na memória do bot

Árvore de comportamento


Em uma versão anterior do Close Quarters, a AI usou o STRIPS, uma solução popularizada pelo FEAR em 2005. No STRIPS, o relacionamento entre diferentes comportamentos de IA não é predefinido pelo programador. Em vez disso, cada comportamento contém uma lista de pré-condições e resultados binários. Cada bot tem um estado do problema no mundo e usa a pesquisa no gráfico A * para encontrar a sequência de comportamento de sua conquista. Essa solução funcionou bem, mas achei que era muito complexa para a minha aplicação e mais adequada para a IA, que precisava desenvolver planos complexos envolvendo muitos comportamentos diferentes. Na maioria dos casos, eu já sabia as circunstâncias sob as quais o bot tinha que executar esse ou aquele comportamento; portanto, usar A * para esse algoritmo era um desperdício desnecessário de recursos da CPU.

Portanto, os bots agora usam uma árvore e um comportamento simples de decisão. Em cada medida, o bot percorre a árvore, começando pela raiz, até atingir o comportamento. Se esse comportamento for o mesmo que o já realizado, o bot continuará esse comportamento. Caso contrário, o bot inicia o comportamento e começa a executá-lo.

Alguns comportamentos podem "bloquear", ou seja, impedir que o bot atravesse repetidamente a árvore até que uma determinada condição seja atendida. Isso é útil, por exemplo, para garantir que os bots atendam antes de decidir atacar. Além disso, os comportamentos podem "anular" um ao outro, forçando o bot a ignorar novamente a árvore e reiniciar o comportamento. Isso é útil, por exemplo, quando um bot escapa de uma granada e aparece outra granada que compromete as posições de escape selecionadas.


Figura 6: A árvore de decisão e comportamento atualmente em uso

Alguns comportamentos secundários são codificados em outros comportamentos mais gerais. Por exemplo, se um bot tenta atacar um inimigo e descobre que o inimigo não está na posição esperada, ele assume onde o inimigo pode estar agora e calcula um novo caminho de ataque sem sair do comportamento do ataque.

Distribuição de carga


Cada bot não precisa ser atualizado em todos os quadros da física, ou seja, 40 vezes por segundo. Para reduzir os custos de CPU, cada bot "pensa" apenas 20 vezes por segundo (esse número pode ser reduzido se necessário). Portanto, apenas metade dos bots são atualizados em cada ciclo de física.

Trabalhar com granadas


Um problema sério era o uso significativo de granadas por bots. Trabalhar com granadas é muito mais difícil do que atirar, porque as granadas podem voar pelas paredes, têm um raio de destruição e tempo para jogar. Felizmente, os robôs não precisam usar granadas perfeitamente, persuasão suficiente.

A solução tradicional para esse problema é pré-calcular os caminhos das granadas nos nós de navegação , mas, quando implementados, são adicionados alguns segundos ao tempo de carregamento de cada mapa, o que contradiz o meu objetivo: o Close Quarters deve lançar os jogadores na batalha em questão de segundos após o início do jogo.

Portanto, os robôs estão procurando oportunidades de usar granadas, calculando os caminhos das granadas em tempo real. Em cada ciclo, o bot atacante verifica várias trajetórias possíveis em uma determinada direção em até 60 graus em relação à direção do alvo selecionado. Se uma granada lançada ao longo de um caminho comprovado pode matar o alvo e o alvo estiver fora de alcance, o bot lança uma granada. A direção verificada é repetida em cada relógio AI.


Figura 7: direções verificadas pelo bot por um segundo (linhas rosa pálidas) e trajetórias testadas (círculos azuis) ao longo da direção selecionada na medida atual (linha rosa brilhante).

Ou seja, os robôs usam granadas sempre que possível e não se movem para uma posição específica para lançar uma granada. No entanto, o caminho escolhido pelo bot para atacar o inimigo geralmente é um caminho sensato para lançar uma granada.

Uma desvantagem significativa de tal sistema é que, devido ao número limitado de direções verificadas, os bots perdem a oportunidade de lançar granadas, de modo que saltam em pequenos obstáculos. O mais notável é que fica ao lado das portas, onde os robôs geralmente não reconhecem a possibilidade de usar uma granada. Esse problema pode ser resolvido testando várias direções em um quadro e reduzindo o ângulo entre a direção que está sendo verificada e a próxima.

Movimento para um comportamento mais humano


Esse problema rapidamente se torna aparente: os bots são rápidos demais para puxar o gatilho, porque é muito difícil derrotá-los em uma batalha individual. O tempo médio de reação humana aos estímulos visuais é de 250 milissegundos, mas a 20 batimentos por segundo, o tempo máximo de reação de bot é de apenas 50 milissegundos!

Para resolver esse problema, eu adicionei deliberadamente um atraso entre o momento em que o bot teve a oportunidade de disparar e o tiro em si, para que seu tempo de reação fosse comparável ao tempo de reação de uma pessoa.

Outras melhorias


Os sistemas apresentados acima fornecem uma forte IA fundamental, mas não oferecem oportunidades para grandes melhorias. Por exemplo, agora o pensamento espacial do bot é limitado por seu entorno imediato; portanto, embora o bot geralmente tente desviar o inimigo do flanco, muitas vezes perde as rotas de prevenção do flanco em torno de grandes obstáculos. Além disso, os bots sabem apenas sobre a presença de colegas de equipe; portanto, às vezes eles se acumulam em um só lugar, em vez de serem divididos e contornarem os flancos.

All Articles