Cursos / Jogos Digitais / Inteligência Artificial para Jogos / Aula

arrow_back Aula 03 - Comportamentos de navegação II

Passo 02 – Implementar no Unity o Path Following

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().

AخA
1
        using UnityEngine;
2
        using System.Collections.Generic;
3
         
4
        public class SoccerPlayerBehavior : MonoBehaviour {
5
            ...
6
            private Queue<Vector2> path;
7
         
8
            private readonly Vector2 crossX = new Vector2(0, 0.1f); 
9
            private readonly Vector2 crossY = new Vector2(0.1f, 0);
10
            ...
11
         
12
            void Start () {
13
                body = GetComponent<Rigidbody2D>();
14
                path = new Queue<Vector2>();
15
                AdjustSpriteRotation();    
16
            }
17
            
18
            void Update () {
19
                if (Input.GetButtonDown("Fire1")) {
20
                    Vector2 p = Input.mousePosition;
21
                    path.Enqueue(Camera.main.ScreenToWorldPoint(p));
22
                }
23
                foreach (Vector2 p in path) {
24
                    Debug.DrawLine(p - crossX, p + crossX);
25
                    Debug.DrawLine(p - crossY, p + crossY);
26
                }
27
            }
28
         
29
            ...
30
        }
31
    

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.

31
1
        ...
2
        public float touchDist = 1.5f;
3
        ...
4
         
5
        void FixedUpdate () {
6
            Vector2 steering = ObstacleAvoidance();
7
         
8
            if (steering == Vector2.zero) {
9
                steering = PathFollowing();
10
            }
11
            ...
12
        }
13
         
14
        Vector2 PathFollowing() {
15
            if (path.Count > 1) {
16
                if (Vector2.Distance(body.position, path.Peek()) < touchDist) {
17
                    path.Dequeue();
18
                }
19
                goal = path.Peek();
20
                return Seek();
21
            }
22
            else if (path.Count == 1) {
23
                goal = path.Peek();
24
                return Arrival();
25
            }
26
            else {
27
                return Vector2.zero;
28
            }
29
        }
30
        ...
31
    

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