Como implementar um inimigo inteligente em um shoot-em-up?

13

Imagine um tiroteio muito simples, algo que todos sabemos:

shoot-em-up 1

Você é o jogador (verde). Seu movimento é restrito ao Xeixo. Nosso inimigo (ou inimigos) está no topo da tela, seu movimento também é restrito ao Xeixo. O jogador dispara balas (amarelas) contra o inimigo.

Eu gostaria de implementar uma IA para o inimigo que deve ser realmente boa em evitar as balas dos jogadores. Minha primeira idéia foi dividir a tela em seções discretas e atribuir pesos a elas:

shoot-em-up ponderada

Existem dois pesos: O "peso da bala" (cinza) é o perigo imposto por uma bala. Quanto mais próxima a bala estiver do inimigo, maior o "peso da bala" ( 0..1onde 1 é o maior perigo). As faixas sem uma bala têm um peso igual a 0. O segundo peso é o "peso à distância" (verde-limão). Para cada faixa eu adiciono 0.2custo de movimentação (esse valor é meio arbitrário agora e pode ser ajustado).

Simplesmente adiciono os pesos (branco) e vou para a pista com o menor peso (vermelho). Mas essa abordagem tem uma falha óbvia, porque ela pode facilmente errar os mínimos locais, pois o lugar ideal para ir seria simplesmente entre duas balas de entrada (como indicado pela seta branca).

Então, aqui está o que estou procurando:

destruição total shoot-em-up

  • Deve encontrar um caminho para a tempestade de balas, mesmo quando não há lugar que não imponha a ameaça de uma bala.
  • O inimigo pode desviar de maneira confiável das balas escolhendo uma solução ótima (ou quase ótima).
  • O algoritmo deve ser capaz de levar em consideração a velocidade de movimento da bala (como eles podem se mover com velocidades diferentes).
  • Maneiras de ajustar o algoritmo para que diferentes níveis de dificuldade possam ser aplicados (mudos para inimigos super inteligentes).
  • O algoritmo deve permitir objetivos diferentes, pois o inimigo não apenas deseja fugir das balas, mas também deve ser capaz de atirar no jogador. Isso significa que as posições em que o inimigo pode disparar contra o jogador devem ser preferidas quando se desviar de balas.

Então, como você lidaria com isso? Ao contrário de outros jogos desse gênero, eu gostaria de ter apenas alguns inimigos, mas muito "habilidosos", em vez de muitos inimigos estúpidos.

bummzack
fonte
2
Você já pensou em usar algo como comportamentos de direção? Há um para evitar obstáculos especificamente: red3d.com/cwr/steer/Obstacle.html
Tétrada
@Tetrad Eu pensei em comportamentos de direção .. também porque eles podem ser trocados, como "tente atirar no jogador" e quando o perigo estiver à frente, mude para "fugir". Receio que uma versão 1D (é com isso que estou lidando basicamente) de evade seja burra demais para tomar boas decisões. Eu posso estar errado embora.
#

Respostas:

8

Eu acho que sua idéia básica é sólida, mas não é analógica. Você precisa de um campo de valor analógico que atravessa a tela. Portanto, gradiente de difusão 1D, a partir do qual você pode derivar um valor em um ponto exato nessa linha, em tempo real. Gradientes de difusão são baratos e podem ser usados ​​por vários inimigos de uma só vez, pois descrevem o ambiente, e não a visão da entidade (um pouco como a iluminação de radiosidade) - provavelmente por que você optou pela abordagem adotada em sua pergunta . Esse gradiente deve ser relativamente suave, de modo a evocar o movimento orgânico do inimigo, e obviamente é atualizado como o seu gamestate. Talvez média móvel ?

O gradiente deve combinar:

  • Proximidade
  • Velocidade
  • Largura da bala
  • (opcional) Posição dos alvos (jogadores)

Para desviar, precisamos encontrar uma solução com precisão sempre que houver uma solução . É o caso sempre que existe uma lacuna pequena o suficiente para o inimigo se esquivar. Ou seja, você só pode fazer o que pode; portanto, a abordagem de gradiente não funcionará pior do que qualquer outra abordagem nesse sentido, eu diria.

O gradiente de difusão deve empurrar o inimigo em direção às ótimas locais (sendo os picos no gráfico) com menos imperatividade de se mover, quanto mais perto estivermos de um mínimo local, portanto, um efeito de retorno decrescente ao se esquivar. Isso abre a porta para uma tomada de decisão mais inteligente sobre quando o inimigo tem uma boa abertura para disparar.

Se a necessidade de disparar for maior que a necessidade de se mover, faça-o; seu código também pode determinar isso em quanto diferença. Você pode implementá-lo como parte do gráfico base. Nesse caso, a posição do jogador reduz os valores circundantes no gráfico (supondo que os inimigos gravitem até o ponto mais baixo), que combina toda a tomada de decisão em um gráfico ou você pode manter o " gráfico desejo de acionar "separado do gráfico principal" desejo de esquivar ", que oferecerá um controle mais direto.

IRL, eu não me incomodaria em desviar de um projétil até que esteja a uma distância que eu sei que, na minha velocidade máxima de esquiva, está começando a se tornar difícil de evitar. Experiência em primeira mão ao jogar pedras como um rapaz. Uma bala na x distância percorrida na velocidade y tem a mesma classificação de perigo que uma bala na 2x distância percorrida em 2y. Portanto, isso precisa ser levado em consideração corretamente.

As maneiras de ajustar o algoritmo para a dificuldade do inimigo incluem

  • introdução de uma latência nas atualizações do gráfico (Born Too Slow)
  • introdução de imprecisões aleatórias e localizadas no gráfico
  • simplesmente não fazer com que os inimigos obedeçam ao que o gráfico diz a eles, em uma sequência de atualizações (digamos 1 a 10 quadros) devido à pura preguiça da IA.

Novamente, você pode implementar todos os fatores em um gráfico (menos controle e menos útil para vários inimigos) ou em vários gráficos que você olha juntos para obter os resultados (mais modular, provavelmente funciona melhor para vários inimigos). É difícil ser mais específico, pois existem várias orientações para você seguir essa abordagem.

Engenheiro
fonte
1
Caro Nick. Fui adiante e implementei uma pequena versão de teste desse comportamento em flash e estou muito satisfeito com o resultado (os marcadores são gerados aleatoriamente). Atualmente, estou usando três gradientes, um para ameaça, custo de movimento e um estático para as bordas (para que as bordas da tela sejam menos desejáveis). Eles são visualizados no aplicativo flash. Eu sinto que com alguns ajustes posso alcançar resultados muito bons e também levar em consideração outros pesos, como posições de tiro. Muito obrigado companheiro.
bummzack
1
Hey @bummzack, é um prazer, é uma demonstração legal! Sua visão do problema era nova para mim e parecia interessante - fico feliz em ver que funciona! Fico feliz em ajudar com isso, e obrigado por compartilhar.
Engenheiro de
7

Isso pode ser encarado como um problema de correção. Em vez de pensar em como o bandido evita as balas, a imagem das balas é estática e o bandido deve viajar através delas até a parte inferior da tela.

    E    
B  B**B
  B***B  B
 B***B   B
B**B** B 
 B**B**BB
B*****B B
      P

E = inimigo
B = marcador
P = jogador
* = opções de caminho para a parte inferior da tela

Depois que o bandido traça um caminho bem-sucedido, ele só precisa dar o próximo passo a cada vez. Provavelmente já existem alguns bons algoritmos para encontrar caminhos como esse. Se o bandido se mover na mesma velocidade que as balas, pode ser um exemplo de algoritmo;

Comece no baddy e marque as posições seguras em espaços vazios à esquerda abaixo, diretamente abaixo e abaixo à direita. Em seguida, considere cada espaço seguro que você acabou de criar e repita. Se a qualquer momento você achar que não há espaços seguros abaixo, marque o espaço como não seguro e volte.

Qwerky
fonte
1
Abordagem interessante. Receio que isso seja meio caro, pois o ambiente muda muito rápido e é difícil usar algoritmos comuns de localização de caminhos, pois funcionam melhor com "mapas" discretos.
bummzack
Não deve ser muito caro, não esqueça que você só precisa calcular a linha inferior a cada turno, não precisa recalcular a coisa toda.
Qwerky 11/11/11
@bummzack O ambiente não é "rápido", pelo menos em termos de computador. Para o desenvolvedor de jogos, você deve entender que quase todos os jogos são baseados em etapas, são do tamanho dessa etapa. Mas, em cada etapa, é possível fazer cálculos, de modo que a solução Qwerky é o que você precisa.
Deele
Na verdade, eu concordo com @bummzack. Embora essa abordagem seja logicamente sólida, será mais cara que a abordagem 1D proposta na questão. Pode ser uma otimização prematura, mas acho que essa abordagem é muito mais elegante. Veja minha resposta para uma elaboração sobre isso.
Engenheiro
2
Esta é provavelmente a resposta correta , mas não exatamente realista . No tempo que o inimigo leva para descobrir um caminho, o campo pode ter outro conjunto de marcadores invalidando o caminho completamente, o que significa que recalcular o caminho seria uma obrigação. E recálculo é uma vadia . Além disso, sua idéia de retropropagação a um ponto em que era seguro torna ainda mais caro! @Nick Wiggill Eu não acho que seja otimização prematura, apenas uma boa previsão para garantir que você não se chute na virilha.
Ray Dey