Criando uma AI simples de C # no Unity

imagem

Quase todo jogo requer inteligência artificial (IA) que interaja com o usuário, na maioria das vezes na forma de uma força hostil ao jogador. Em alguns casos, a IA deve ajudar o jogador, em outros deve combatê-la, mas todos os personagens controlados pelo computador têm algumas semelhanças. Dependendo dos requisitos do projeto, a IA pode usar comportamentos simples ou complexos. Tais requisitos podem ser diplomacia com outro jogador ou um simples passeio pela plataforma. Seja como for, é necessário garantir que a IA faça seu trabalho com eficiência.

Neste projeto, demonstrarei uma inteligência artificial muito simples. Suponha que criamos um jogo no qual um jogador deve se aproximar do quartel-general inimigo. Quando um jogador é notado por uma câmera de segurança, inimigos são criados nas proximidades e, por um curto período de tempo, perseguem o jogador. É isso que estamos implementando no projeto no nível mais simples. Após a conclusão do projeto, você receberá o objeto de um jogador controlado, um círculo usado como câmera de um inimigo e um objeto de inimigo que perseguirá o jogador quando o objeto da câmera informar sobre sua presença.

Preparação


Primeiro, precisamos criar um projeto 3D. Clique no botão Novo na parte superior da janela após iniciar o Unity, como mostra a Figura 1.


Figura 1: criando um novo projeto

Nomeie seu projeto de IA e verifique se é um projeto 3D. Após escolher um local no computador para armazenar o projeto, clique no botão Criar Projeto na parte inferior, mostrado na Figura 2.


Figura 2: tela de configuração do projeto

Depois de criar o projeto, a primeira coisa que precisamos fazer é configurar as pastas na janela Assets para organizar nosso trabalho. Clique com o botão direito na janela Ativos e selecione Criar → Pasta para criar uma nova pasta. Nomeie essa pasta de Materiais . Em seguida, crie uma segunda pasta e nomeie-a como Scripts . A Figura 3 mostra como deve ser.


Figura 3: criando uma nova pasta

Depois de tudo isso, a janela Assets deve se parecer com a mostrada na Figura 4.


Figura 4: Janela Ativos .

Em seguida, crie um piso no qual todos os objetos permaneçam. Na janela Hierarquia , selecione Criar → Objeto 3D → Plano para criar um objeto plano que será usado como piso.


Figura 5: Criando um objeto plano.

Nomeie esse objeto Floor e altere seu valor X Scale para 7 e o valor Z Scale para 3. Depois disso, a janela Inspector com o objeto Floor selecionado deve se parecer com o mostrado na Figura 6.


Figura 6: Definindo as propriedades do objeto Floor .

Agora, precisamos criar um novo material para o Floor para diferenciá-lo dos demais objetos que serão colocados na cena. Na pasta Materiais da janela Ativos , crie um novo material clicando com o botão direito do mouse na janela Ativos e escolhendo Criar → Material .


Figura 7: criando novo material

Quando terminar, nomeie o material como Piso .


Figura 8: Material do piso .

Na parte superior da janela do Inspetor com Piso selecionado, selecione um seletor de cores.


Figura 9: escolhendo um seletor de cores.

Obviamente, você pode escolher qualquer cor para o piso, mas neste exemplo eu escolhi o marrom vermelho, como mostra a Figura 10.


Figura 10: seletor de cores.

Selecione o objeto Piso na janela Hierarquia e, no componente Renderizador de malha , selecione a pequena seta ao lado de Materiais .


Figura 11: Preparando para uma mudança de material.

Arraste o material Piso da janela Ativos para o campo Elemento 0 do componente Renderizador de malha na janela Inspetor .


Figura 12: Definindo o material do piso como o material do objeto Piso .

Depois de terminar com o objeto Floor , precisamos criar em torno da área da parede para que o jogador não possa cair da borda. Volte para Criar → Objeto 3D → Plano para criar um novo plano. Chamamos esse plano de parede e o definimos nas mesmas dimensões que Floor , ou seja, X Scale com um valor de 7 e Z Scale com um valor de 3. Em seguida, crie mais três paredes, selecione um objeto e pressione Ctrl + D três vezes. sexo de acordo com os dados da tabela.

Título
Posição X
Posição Y
Posição z
Rotação x
Rotação z
Parede
-35
21
0 0
0 0
-90
Parede (1)-1
11
-15
90
0 0
Parede (2)
-1
11
13,5
-90
0 0
Parede (3)
34
21
0 0
0 0
90

Tabela 1: Posições e rotações de todos os objetos da parede .

Depois de concluir tudo isso, você precisa alterar a posição da câmera para que ela olhe para o chão de cima. Selecione o objeto Câmera principal e defina a posição Y para 30, a posição Z para 0 e a rotação X para 80.


Figura 13: configurando o objeto da câmera.

A cena está preparada, então é hora de criar o personagem do jogador. Na janela Hierarquia , clique em Criar → Objeto 3D → Esfera para criar um objeto de esfera. Nomeie esse objeto como Player e clique no botão Adicionar componente na parte inferior da janela do Inspetor .


Figura 14: adicionando um novo componente.

Agora encontre o corpo rígido . Depois disso, selecione o componente Rigidbody na lista e adicione o Rigidbody ao objeto Player .


Figura 15: adicionando um componente Rigidbody .

Em seguida, você precisa atribuir uma tag ao jogador, que mais tarde será útil para nós no código. Clique no menu suspenso Tag , no canto superior esquerdo da janela Inspetor , e selecione a tag Player .


Figura 16: Definindo uma nova tag.

Precisamos definir a posição do jogador para que ele não fique embaixo do objeto Floor . No exemplo, coloquei o player no canto superior esquerdo com a posição X igual a 26, a posição Y igual a 1 e a posição Z igual a -9.


Figura 17: posicionamento do jogador.

Para que nosso código futuro funcione corretamente, é claro que precisamos anexá-lo ao objeto. Volte para a janela Hierarquia e desta vez selecione Criar → Objeto 3D → Cubo . Chame esse cubo Guard , adicione o componente Rigidbody e o componente NavMesh Agent usando o botão Add Component na janela Inspector . Em seguida, coloque-o em algum lugar no canto superior esquerdo da cena. Depois disso, a janela Inspetor do objeto Guard ficará assim:


Figura 18: Objeto de guarda na janela Inspetor .

E este objeto deve estar localizado assim:


Figura 19: Colocação do objeto Guard .

Finalmente, precisamos de um objeto usado como o "olho" do objeto Guarda , que notificará o Guarda que o jogador está tocando nele. Pela última vez, vá para a janela Hierarquia e selecione Criar → Objeto 3D → Esfera para criar outro objeto de esfera. Nomeie esse objeto Looker . Desta vez, não precisamos adicionar outros componentes a ele. No entanto, redimensionaremos o objeto. Depois de escolher o Looker , altere as seguintes variáveis ​​do componente Transform na janela Inspector .

  • Escala X em 9.
  • Escala Y a 0,5.
  • Escala Z em 9.

Depois disso, posicione o Looker de forma que ele esteja localizado na parte superior central do piso, como mostra a Figura 20.


Figura 20: Localização do Looker.

É o momento certo para fornecer ao Looker um material exclusivo, para que você possa ver que vale a pena evitar. Na pasta Materiais da janela Ativos , clique com o botão direito do mouse e crie um novo material. Nomeie-o Looker e dê uma cor vermelha brilhante. Depois disso, designe esse material como o material do objeto Looker para alterar sua cor. Depois disso, a cena deve ficar assim:


Figura 21: Objeto visualizador com novo material.

A única coisa que resta para nós é criar uma malha de navegação para o Guard , na qual ele pode se mover. Há um menu Janela na parte superior do editor do Unity. Escolha Janela → Navegação para abrir a janela Navegação mostrada na Figura 22.


Figura 22: Janela de navegação .

Selecione o objeto Piso na Hierarquia e, na janela Navegação , marque a caixa de seleção Estática da Navegação .


Figura 23: Estática de navegação .

Em seguida, selecione a opção Assar na parte superior da janela.


Figura 24: Alterne para o menu Bake .

O menu Bake é aberto, no qual você pode alterar as propriedades da malha de navegação que vamos criar. No nosso exemplo, nada precisa ser alterado. Basta clicar no botão Bake no canto inferior direito.


Figura 25: criando uma nova malha de navegação.

Nesse ponto, o Unity solicitará que você salve a cena. Salve-o, após o qual uma malha de navegação será criada. Agora a cena ficará assim:


Figura 26: A cena atual com a malha de navegação adicionada.

Agora tudo no Unity está configurado, então é hora de criar os scripts necessários para o projeto funcionar. Na janela Ativos , clique com o botão direito do mouse e selecione Criar → Script C # . Nomeie esse script como Player . Repita esta operação mais duas vezes, criando scripts com os nomes Guard e Looker .


Figura 27: criando um novo script.

Depois disso, a pasta Scripts na janela Assets ficará assim:


Figura 28: Pasta Scripts .

Primeiro, começaremos a escrever o código de script do Player . Clique duas vezes no script Player na janela Assets para abrir o Visual Studio e começar a criar o código.

Código


O script Player é bastante simples, basta permitir que o usuário mova o objeto bola. Sob a declaração de classe, precisamos obter um link para o componente Rigidbody que criamos anteriormente no projeto.

private Rigidbody rb; 

Logo depois, na função Start , comandamos o Unity para definir o atual componente Rigidbody do objeto Player como rb .

 rb = GetComponent<Rigidbody>(); 

Depois disso, o script Player ficará assim:


Figura 29: Script do jogador no momento.

Agora que o valor rb está atribuído, precisamos permitir que o objeto Player se mova quando pressionamos as teclas de seta. Para mover o objeto, usaremos a física, aplicando força ao objeto quando o usuário pressionar as teclas de seta. Para fazer isso, basta adicionar o seguinte código à função Atualizar :

 if (Input.GetKey(KeyCode.UpArrow)) rb.AddForce(Vector3.forward * 20); if (Input.GetKey(KeyCode.DownArrow)) rb.AddForce(Vector3.back * 20); if (Input.GetKey(KeyCode.LeftArrow)) rb.AddForce(Vector3.left * 20); if (Input.GetKey(KeyCode.RightArrow)) rb.AddForce(Vector3.right * 20); 

Com isso, concluímos o script do Player . O script final terá a seguinte aparência:


Figura 30: o script Player concluído.

Salve seu trabalho e retorne ao Unity. Desta vez, selecione o script Guard na janela Assets . Para fazer o código do Guard funcionar, você precisa adicionar a construção using na parte superior do script.

 using UnityEngine.AI; 

Em seguida, declare as seguintes variáveis ​​imediatamente após a declaração da classe.

 public GameObject player; private NavMeshAgent navmesh; 

O objeto Player é usado como o valor da variável player do objeto Guard . Isso será útil mais tarde, quando comandarmos o objeto Guarda para perseguir o jogador. Em seguida, a variável navmesh é declarada para receber o componente NavMeshAgent do objeto. Nós o usaremos mais tarde quando o Guarda começar a perseguir o jogador depois que ele descobrir que o jogador está tocando o objeto Looker . Na função Start , precisamos definir o valor da variável navmesh para o componente NavMesh Agent do objeto:

 navmesh = GetComponent<NavMeshAgent>(); 

Em seguida, na função Atualizar , adicionamos uma única linha de código:

 navmesh.destination = player.transform.position; 

Esta linha define o destino para o objeto Guard . No nosso caso, ele assumirá a posição atual do objeto Player e se moverá para este ponto. Após a operação, o objeto perseguirá constantemente o jogador. A questão é: como é realizado o processo de resposta? Não será codificado no script Guard , mas no script Looker . Antes de passar para o script Looker, observe a Figura 31 para verificar seu código de script do Guard .


Figura 31: o script Guard concluído.

Dentro do Looker, novamente precisamos declarar as seguintes variáveis:

 public GameObject guard; private float reset = 5; private bool movingDown; 

Depois disso, comentamos a função Iniciar , da qual não precisamos neste script. Vamos para a função Update e adicione o seguinte código:

 if (movingDown == false) transform.position -= new Vector3(0, 0, 0.1f); else transform.position += new Vector3(0, 0, 0.1f); if (transform.position.z > 10) movingDown = false; else if (transform.position.z < -10) movingDown = true; reset -= Time.deltaTime; if (reset < 0) { guard.GetComponent<Guard>().enabled = false; GetComponent<SphereCollider>().enabled = true; } 

É aqui que as principais ações do projeto ocorrem, então vamos analisar o código. Primeiramente, dependendo do valor da variável booleana movingDown , o objeto ao qual esse script está anexado será movido para cima ou para baixo. Assim que ele chegar a um certo ponto, ele mudará de direção. Em seguida, o Looker reduzirá o valor de redefinição com base em tempo real. Assim que o cronômetro se tornar menor que zero, ele pegará o script Guard do objeto Guard e o desativará. Depois disso, o objeto Guard começará a se mover para a última posição conhecida do jogador até então e depois parará. O Looker também liga novamente o colisor para que todo o processo possa começar de novo. Agora, nosso script fica assim:


Figura 32: Script do visualizador .

Falando em coletores: é hora de criar um código de conflito que redefina o timer do Looker e inclua o script Guard . Na função Atualizar , crie o seguinte código:

 private void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Player") { guard.GetComponent<Guard>().enabled = true; reset = 5; GetComponent<SphereCollider>().enabled = false; } } 

O OnCollisionEnter Unity o reconhece automaticamente como um código de colisão e, portanto, o executa quando ocorre uma colisão com outro objeto. No nosso caso, ele primeiro verifica se o objeto em colisão possui uma tag Player . Caso contrário, ele ignora o restante do código. Caso contrário, ele ativa o script Guard , define o timer de redefinição para 5 (ou seja, cinco segundos) e desativa o colisor para que o jogador ainda possa se mover pelo objeto e não ficar preso acidentalmente no objeto Looker . A função é mostrada na Figura 33.


Figura 33: Código de colisão para o Looker.

É tudo o que o código do projeto está pronto! Você pode fazer mais algumas coisas antes de terminar o projeto. Salve todo o trabalho e retorne ao Unity.

Conclusão do projeto


Para concluir o projeto, basta anexar scripts aos objetos correspondentes e definir várias variáveis. Primeiro, vá da janela Navegação para a janela Inspetor :


Figura 34: transição para a janela Inspetor.

Depois disso, vamos começar com o objeto Player . Selecione-o na janela Hierarquia e, na parte inferior da janela Inspetor , clique no botão Adicionar componente e adicione o script Player . Isso completa o objeto Player .


Figura 35: Componente de script do Player.

Em seguida, selecione o objeto Guard . Como antes, anexe o script Guard ao objeto. Desta vez, precisamos dizer ao guarda quem é o jogador. Para fazer isso, arraste o objeto Player da Hierarquia para o campo Player do componente de script Guard , como mostra a Figura 36.


Figura 36: Fazendo com que o Player objete o valor do campo Player .

Também precisamos desativar o script Guard . Em nosso projeto, Guard perseguirá o jogador depois de ativar seu script. Esse script de guarda deve ser incluído somente depois que o jogador tocar no objeto Looker . Tudo que você precisa fazer é desmarcar a caixa ao lado do texto Guard (Script) no componente:


Figura 37: Desativando o script Guard .

Por fim, vamos para o objeto Looker e anexamos o script Looker . Dessa vez, o objeto Looker precisará de um objeto Guard como o valor de sua variável Guard . Assim como atribuímos o objeto Player à variável Player do script Guard , faremos o mesmo com o objeto Guard e o script Looker . Arraste o Guard da Hierarquia para o campo Guard do script Looker . E o projeto está concluído! Clique no botão Play na parte superior do editor do Unity para testar seu projeto.


Figura 38: Testando um projeto.

Tente mover o objeto Player para o objeto Looker (lembre-se de que o movimento é feito com setas!). Observe que, depois disso, o objeto Guard começará a perseguir o jogador. Ele continuará a busca por cerca de 5 segundos, após o que desistirá.


Figura 39: Um projeto totalmente concluído em ação.

Conclusão


Essa IA é muito simples, mas pode ser facilmente expandida. Suponha que, se imaginarmos que o objeto Looker é uma câmera, e o guarda o olhar para encontrá-lo, será lógico atribuir ao objeto o seu próprio par de olhos. O jogador pode se aproximar das câmeras, mas deve levar em conta os olhos do guarda. Você também pode combinar este projeto com o conceito de encontrar o caminho : dê ao guarda o caminho que ele seguirá, criando um ambiente mais interessante para o jogador.

Uma IA tão simples pode ser desenvolvida de várias maneiras diferentes. Você pode não querer fazer nada do que precede e decidir fazer algo de sua preferência. Eu aconselho você a experimentar, talvez você tenha a idéia de um projeto interessante, que vale a pena levar ao fim.

Source: https://habr.com/ru/post/pt419641/


All Articles