Cursos / Jogos Digitais / Inteligência Artificial para Jogos / Aula
Adapte o cenário da aula anterior para esse novo comportamento, com os mesmos elementos, porém, coloque mais jogadores no campo. Crie um tipo de jogador, porque, por enquanto, você quer que apenas um jogador siga as instruções (deslocar-se dentro do campo em direção ao alvo clicado). É interessante, então, criar o prefab de um jogador adversário, defini-lo como obstáculo e ver se o jogador (o que você controla) percebe que há adversários à frente e consegue desviar deles.
Inicialmente, você precisa criar um objeto para ser um modelo de jogador adversário. Para isso, há uma imagem de jogador do time laranja na pasta Sprites. Carregue essa imagem para a cena do jogo e crie um objeto com o componente Sprite Renderer. Ajuste-o na posição, rotação e escala desejadas (na aula anterior, você utilizou uma escala de 0.5 para o jogador). Para ele ser detectado, insira o componente CircleCollider2D. Como você está trabalhando com apenas um raio ( pode trabalhar com dois se assim desejar, um para o lado esquerdo e outro para o direito), dobre o raio do collider para que leve em conta o corpo do NPC que está desviando e do que será desviado, como ilustra a Figura 06.
Além desse ajuste, informe no collider que ele é um gatilho (Is Trigger). Esse ajuste é apenas para informar que nenhuma física será aplicada quando houver colisão. Você está apenas querendo “prever" uma possível colisão através de um raio a ser disparado a partir da posição do jogador que está sendo controlado.
Uma vez que o objeto foi criado, crie um prefab dele para poder replicá-lo em diferentes posições do campo, uma pasta chamada Prefabs e, em seguida, um novo objeto prefab vazio nela. O próximo passo é arrastar e soltar o jogador recém-construído sobre o prefab vazio. Replique o objeto arrastando-o sobre o cenário o número de vezes que desejar (5 é um bom número, pois você fará um time de 5).
Agora, você precisa alterar o script de comportamento do jogador que está sendo controlado.
A única variável pública a mais que se precisa é uma para definir a distância em que o jogador vai começar a se desviar dos obstáculos. Essa variável vai delimitar o vetor “adiante", explicado anteriormente. Em seguida, crie um método da classe para calcular a força de navegação para o desvio de obstáculos, seguindo as explicações anteriores. O Código 01 mostra o resultante dessas explicações.
Preste atenção nos "..." porque eles representam partes omitidas de cada código!
No código, você inicializou a variável steer com um vetor nulo (0,0). Se houver colisão à frente, você irá alterar o valor dessa variável antes de retorná-la. Caso contrário, o retorno de um vetor nulo indica que não há força alguma a aplicar para desviar de obstáculos.
Em seguida, calcule a distância que levará em conta no teste do que há à frente, cuja variável ahead armazenará. Para isso, use o atributo público da classe aheadDistance multiplicado pela fração da atual velocidade pela velocidade máxima do NPC. Ou seja, caso o NPC esteja na velocidade máxima, essa fração será 1, fazendo com que ahead seja o próprio valor de aheadDistance. Quanto menor a velocidade do atual, menor será ahead, que é utilizado na linha seguinte para computar quais os colliders existentes se traçar um raio da posição atual do NPC, na direção de sua velocidade e de tamanho ahead. O método Physics2D.RaycastAll() retorna um arranjo de informações sobre as colisões desses colliders. O arranjo é, então, armazenado na variável obs (de obstáculos), sendo cada um dos elementos do tipo RaycastHit2D.
O teste em seguida verifica se o número de elementos em obs é maior do que 1, ou seja, se há mais de um collider à frente. Na verdade, sempre haverá pelo menos um, pois o próprio jogador que o script está controlando possui um collider, então haverá no mínimo ele. Se houver mais de um, então é porque há obstáculos (além dele) à frente. Nesse caso, como você quer apenas o obstáculo mais próximo, ordene o arranjo retornado. Na ordenação através do método Sort(), passe um delegate que recebe dois objetos do tipo RaycastHit2D e retorna -1, 0 ou 1, dependendo se a distância do primeiro é menor, igual ou maior do que a do segundo, respectivamente. Apenas com essa informação, o algoritmo do método de ordenação consegue colocar os elementos do arranjo em ordem de distância. Com o arranjo ordenado, o objeto que você precisará desviar, hit, é o segundo elemento do arranjo, pois o primeiro é o próprio NPC.
As linhas seguintes seguem a mesma estratégia de cálculo de vetores dos comportamentos apresentados anteriormente (Seek e Arrival), só que agora no sentido contrário. O vetor to é o que vai da posição atual do NPC à posição do obstáculo a ser desviado. Ou seja, ele indica a direção do obstáculo. Use a mudança de tipo explícita (cast) para Vector2 porque, por padrão, a transform.position de qualquer objeto no Unity é um vetor 3D. Para calcular a direção da força que desvia do obstáculo, use a diferença do vetor velocidade (com o tamanho da distância do NPC para o obstáculo) pelo vetor com a posição do obstáculo. Com a direção de força calculada, ajuste para que seja dada a maior força de navegação possível.
Por fim, só precisa alterar a chamada para ObstacleAvoidance() no método FixedUpdate(). Se não houver força alguma, aplique a busca pelo objetivo. Caso contrário, você irá se desviar, como implementado no Código 02.
Muito bem! Você está fazendo o jogador correr em uma direção desejada (Seek). ir parando quando estiver chegando (Arrival), desviar de obstáculos (Obstacle avoidance), bem como outros comportamentos vistos aula 02 (escapar de um adversário (Flee) e perseguir um alvo em movimento (Pursuit)). Falta agora ele começar a fazer jogadas ensaiadas. O primeiro passo é fazê-lo seguir uma sequência de pontos de um caminho, veja na seção a seguir.
Versão 5.3 - Todos os Direitos reservados