Os materiais didáticos aqui disponibilizados estão licenciados através de Creative Commons Atribuição-SemDerivações-SemDerivados CC BY-NC-ND. Você possui a permissão para visualizar e compartilhar, desde que atribua os créditos do autor. Não poderá alterá-los e nem utilizá-los para fins comerciais.
Atribuição-SemDerivações-SemDerivados
CC BY-NC-ND
Cursos / Jogos Digitais / Inteligência Artificial para Jogos / Aula
Comece a implementação do Path Following pela definição do caminho. Como dito anteriormente, o C# possui uma classe própria para a estrutura de dados Fila chamada Queue. Essa é uma classe genérica, na qual se precisa detalhar o tipo de dados que ela armazena. Como o caminho é formado por pontos no campo de futebol, o que você irá armazenar são valores do tipo Vector2. A definição dessa classe encontra-se em um namespace específico. Logo, para usá-la, é necessário declarar seu uso através da palavra-chave using.
A interação do usuário com o NPC-jogador pode se dar da seguinte forma: sempre que o usuário clicar sobre uma parte do campo, um novo ponto é inserido no caminho do jogador. Assim, você precisa alterar o método Update() para que o clique do mouse não mais atualize a variável goal, mas adicione o ponto na fila. Para facilitar a visualização dos pontos presentes nessa fila, você precisa também adicionar um código que desenha uma cruz nos pontos.
O Código 03 apresenta parte da solução. Nele, além da variável path, contendo os pontos do caminho, tem-se também as constantes (readonly) crossX e crossY. Esses atributos são utilizados apenas para o desenho da cruz em cada ponto do caminho, através do método de Debug DrawLine().
using UnityEngine;
using System.Collections.Generic;
public class SoccerPlayerBehavior : MonoBehaviour {
...
private Queue<Vector2> path;
private readonly Vector2 crossX = new Vector2(0, 0.1f);
private readonly Vector2 crossY = new Vector2(0.1f, 0);
...
void Start () {
body = GetComponent<Rigidbody2D>();
path = new Queue<Vector2>();
AdjustSpriteRotation();
}
void Update () {
if (Input.GetButtonDown("Fire1")) {
Vector2 p = Input.mousePosition;
path.Enqueue(Camera.main.ScreenToWorldPoint(p));
}
foreach (Vector2 p in path) {
Debug.DrawLine(p - crossX, p + crossX);
Debug.DrawLine(p - crossY, p + crossY);
}
}
...
}
Você já pode fazer um teste do novo código! Veja o caminho de marcas sobre o campo ao clicar sobre ele. Porém, o jogador ainda não está seguindo os pontos que você marcou. Claro! O método FixedUpdate() continua o mesmo e ainda não implementamos o Path Following propriamente dito.
No método FixedUpdate(), a única alteração que você precisa realizar é dizer que a força de navegação a ser utilizada, agora, é a que retorna de um novo método, que você criará, chamado PathFollowing(). Antes de implementar esse método, você precisa definir qual será a distância mínima para considerar que o jogador “tocou" no ponto do caminho. Pode-se colocar esse valor como um atributo público da classe para facilmente ajustá-la. Em seguida, o algoritmo será simples: se houver mais de um ponto no caminho, chame o comportamento Seek, se houver apenas um, o comportamento Arrival, caso contrário (não há pontos no caminho), retorne um vetor nulo. Nesse entretempo, se a distância entre o jogador e o ponto do início da Fila for menor do que a distância mínima (ou seja, se ele “tocou" no ponto), pode-se retirar o ponto da Fila. O Código 04 mostra em mais detalhes a implementação aqui descrita.
...
public float touchDist = 1.5f;
...
void FixedUpdate () {
Vector2 steering = ObstacleAvoidance();
if (steering == Vector2.zero) {
steering = PathFollowing();
}
...
}
Vector2 PathFollowing() {
if (path.Count > 1) {
if (Vector2.Distance(body.position, path.Peek()) < touchDist) {
path.Dequeue();
}
goal = path.Peek();
return Seek();
}
else if (path.Count == 1) {
goal = path.Peek();
return Arrival();
}
else {
return Vector2.zero;
}
}
...
Agora, você pode testar de verdade e ver se o jogador está, de fato, seguindo suas ordens.
Versão 5.3 - Todos os Direitos reservados