Nesta palestra, veremos a criação de um sistema de waypoint que
pode ser navegado com o algoritmo A *. Para começar, faça o download do arquivo de recursos que acompanha esta palestra e nela você encontrará
esta cena com o tanque.
Se você já fez algum dos outros tutoriais fornecidos pelo Unity, já viu esses modelos antes e eu
os uso com bastante frequência porque eles são agradáveis de olhar e convenientes e fáceis, por isso não temos para
montar nosso próprio mapa.
Obviamente, se você deseja montar seu próprio mapa, vá em frente.
Isso é bom.
Agora temos um mapa e também temos um pequeno tanque.
O tanque será nosso personagem NPC.
O que vamos fazer é colocar alguns pontos de referência ao redor do mapa e depois vinculá-los às bordas e colocar
alguns botões na tela para dar as ordens dos tanques para onde ir. A primeira coisa que faremos é colocar
alguns pontos de referência.
O importante a lembrar aqui é que não há detecção física ou de colisão neste projeto, o que significa
que você deve colocar pontos de referência onde o tanque possa se mover.
Então serão os caminhos. No projeto, criei um
ativo de objeto de jogo do WayPoint aqui.
Portanto, esta pré-fabricada, se eu arrastar e soltar na cena, você verá que ela automaticamente fornecerá um número
e, toda
vez que você adicionar um waypoint, ele contará para você.
Isso é para que você possa acompanhar qual waypoint é qual, sem ter que clicar nele na
Hierarquia de cada vez.
Então, vamos diminuir o zoom. Vou colocar alguns pontos de referência em torno deste mapa para
chegar ao heliporto,
que fica aqui embaixo e um para chegar até aqui e contornar este prédio, mas
você pode colocá-los onde quiser. Então, eu vou fazer isso rapidamente.
Com todos os waypoints no lugar, eles se tornarão os nós em nosso gráfico.
Portanto, precisamos agora determinar onde as bordas estarão e as bordas são as linhas que conectam os nós e
nos dirão para onde o tanque pode viajar.
Como eu disse no começo, esses pontos de referência também vão especificar para onde o tanque
NÃO PODE viajar, por isso não queremos colocar nenhum caminho na geometria.
Portanto, ele também funciona como um sistema de prevenção de colisões.
Você pode colocar pontos de referência como esses nos prédios, se quiser que seus
NPCs viajem por lá e pareçam inteligentes, porque estão evitando obstáculos.
Portanto, neste caso, podemos conectar o waypoint '1 com 2' e '2 com 3' e '1 com 3', em qualquer lugar onde houver
uma linha de visão clara, podemos nos juntar a eles. Portanto, não podemos chegar daqui para o número 7 na parte de trás, indo por esse caminho.
Então, vamos colocar linhas aqui e aqui e eu posso até colocar um caminho de mão única que sobe até
aqui, para que o tanque, se estiver aqui e quiser voltar, tenha que percorrer esse caminho.
Com todos os seus caminhos planejados, você pode anotá-los para ter uma
referência de quando vamos colocar essas informações de volta no Unity.
Agora é hora de começar a
criar algum código, mas, pouco antes de fazê-lo, precisamos de um objeto na cena que gerencie todos os pontos de referência.
Portanto, na Hierarquia, clique com o botão direito do mouse e em Criar Vazio e chamaremos esse objeto de WPManager.
Então este é o nosso gerenciador de waypoints. Nisso, colocaremos algum código.
Então, vamos ao projeto e criaremos um novo script C # e também o chamaremos de WPManager.
Não importa se não são os
mesmos, eu apenas gosto de mantê-lo consistente.
Agora, com esse WPManager, vou arrastá-lo e soltá-lo em nosso objeto de jogo vazio e,
em seguida, abriremos e começaremos a editá-lo. Acima da classe WPManager, vamos adicionar um pouco de estrutura
e está aí para ajudar a facilitar a entrada e o armazenamento de dados do nosso gráfico.
O gráfico está entrando em outro sistema, mas ainda precisamos colocar o gráfico no WPManager de
alguma forma, e a
maneira mais simples no momento é fazer o Inspector parecer
bom para facilitar isso, essencialmente.
Portanto, este é um link e um link será basicamente a borda.
Portanto, define os nós em cada extremidade de uma aresta, a direção e se é unidirecional, o que significa que é de uma maneira ou se
é bi, o que significa que viaja em duas direções ... e isso é armazenado aqui na
variável direction.
Portanto, existem apenas três coisas aqui essencialmente.
Em seguida, definiremos os waypoints, os links e também criaremos um gráfico a partir deles.
Então, no topo aqui, adicione isso.
Portanto, temos uma matriz GameObject segurando nossos waypoints.
Essas serão todas as esferas que colocamos no nosso mapa.
Então temos um conjunto de links, que também definiremos e isso nos permite dizer
'este se conecta a esse' e 'este se conecta a esse' e se você pode
viajar nas duas direções ou não e se
não há link para waypoints, então eles obviamente não estão conectados. Então, com tudo isso,
criaremos um novo gráfico do tipo 'Graph'.
Agora, o código do gráfico e o algoritmo A * foram todos escritos para você e eu forneci isso dentro da pasta
'Graphs' em Assets. Se você der
uma olhada lá, você encontrará 3 aulas. Há um para o Graph, um para o Node e um para o Edge e
todos são muito elementares.
Portanto, dê uma olhada nelas, mas não entrarei em detalhes de seu funcionamento interno, exceto para dizer
que eles usam o algoritmo A *.
De volta ao código do WPManager, trabalharemos na função Iniciar para configurar tudo.
Então aqui, basta adicionar este código. Vamos percorrer a matriz de waypoints que está no topo
e é a que alimentamos nossos waypoints manualmente.
Se houver pontos de referência nesse array, percorreremos cada um deles e o alimentaremos em nosso
gráfico que criamos aqui.
O código do gráfico possui um método AddNode e você pode alimentar os objetos do jogo até
lá, para que cada nó exista.
Cada objeto do jogo precisa ser adicionado a esse gráfico antes que você possa fazer qualquer coisa com seus links.
Depois disso, faremos a mesma coisa com os links, passaremos por
eles e usaremos o gráfico. Método AddEdge para criar uma borda entre um nó e o outro.
Agora, este AddEdge faz apenas bordas unidirecionais (portanto, unidirecionais). Se a borda que definimos for bidirecional, então eu tenho um pequeno
teste aqui apenas para verificar se você a tornou bidirecional e, se
for, ela adiciona outra borda e troca os dois nós.
Tudo certo.
Portanto, é tudo o que você precisa para construir o gráfico e agora você pode colocar o máximo de pontos de referência e
definições de arestas nessas coisas por meio do Inspetor
e se criar tudo para você.
Agora, uma última coisa será realmente interessante: se podemos ver as bordas, porque já podemos ver os nós
no mapa.
Mas se pudermos ver as bordas, isso nos ajudará a depurar o programa. No gráfico, ele tem um
método debugDraw assim. Se colocarmos isso na atualização, poderemos ver as arestas que criamos.
Tudo certo.
Portanto, salve tudo isso e
preencheremos o Inspetor com nossos nós e bordas. Agora no WPManager
você encontrará Waypoints e Links.
Então, temos 11 waypoints (então coloque 11 aqui para abrir) e esses são todos os waypoints separados
e eu quero que eles estejam em ordem.
Isso significa que eu preciso arrastá-los um por um, então eu vou fazer isso rapidamente ...
A próxima coisa a preencher são os links. Eu tenho 13 links e esse é o número de caminhos
individuais entre cada um dos seus nós.
Então eu vou colocar 13 lá, que irá expor todos os elementos.
Então, agora eu vou criar esses links um por um.
O primeiro link que eu tenho é aquele entre o waypoint 1, aqui e o waypoint 2, lá embaixo.
Então, eu vou pegar o waypoint 1 da Hierarquia e arrastá-lo para lá e o waypoint 2 para lá.
Agora, se você possui um link unidirecional, que segue apenas em uma direção, deseja colocar o nó inicial em primeiro lugar
e o segundo nó em seguida. Com este conjunto para
UNI, ele somente deixará o tanque seguir nessa direção.
Não poderia voltar novamente.
Então, eu vou definir isso para BI, porque eu quero que o tanque possa ir e voltar entre
os dois.
O próximo elemento que colocarei, apenas para mostrar o que está acontecendo com o link entre 8 e 9.
Lembra que eu disse que queria colocar apenas em uma direção?
Então, eu quero que ele passe de 8 (que será o primeiro) para 9 (que será o próximo aqui)
e, em seguida, deixe-o unidirecional em vez de alterá-lo.
Então, só vai em uma direção.
Tudo bem, então eu vou fazer o resto
e provavelmente será mais fácil se você tiver tudo isso escrito em um pedaço de papel
como o meu e você puder atravessar cada caminho ao fazê-lo , o que tornará muito mais simples.
Quando você achar que terminou todos os seus caminhos, pressione Play e, em seguida, volte para a
exibição de Cena e poderá vê-los.
Então, eles são desenhados onde você criou um link e podem vê-los lá.
Agora, se você aumentar o zoom um pouco mais perto, a linha ou a borda terá uma marca azul no final.
Então isso mostra a direção em que está indo.
Nesse caso, você pode ver que há uma marca azul nas duas extremidades dessa linha.
Então isso significa que você pode viajar para frente e para trás.
Agora, a única unidirecional no momento, se eu vier
por aqui, é esta linha aqui e você pode ver (espero que você possa ver,
é bem pequeno, não é! Deixe-me subir ... ) Então, tem um pouco
de azul e, do
outro lado, não tem azul, o que significa que está viajando nessa direção em
nossa unidirecional.
Portanto, se nosso tanque acabar aqui, a única maneira de poder voltar a qualquer lugar daqui
é contornando esse galpão ou o que quer que seja.
Ok, agora temos nossos waypoints, apenas
temos que informar nosso tanque sobre eles.
Vamos criar um código de direção para o tanque.
Vá para 'Criar> Script C #' e chamaremos esse FollowPath e esse código é baseado no código
MoveLocal que usamos anteriormente.
Então, aqui vamos adicionar algum código.
Vou colocar tudo de uma só vez e depois passar por isso com você.
Está bem.
Então aqui está. Como antes, temos um objetivo, mas desta vez não
é exposto porque não estamos passando o objetivo como algo que o NPC possa agarrar.
O objetivo virá do nosso algoritmo A *.
Em seguida, temos os suspeitos do costume.
Temos nossa velocidade, precisão e velocidade de rotação, por isso precisamos desses valores novamente.
Depois disso, precisaremos de um valor exposto ao público para o WPManager porque o WPManager contém todos os pontos de referência
e as informações do gráfico e o NPC precisa saber sobre isso.
Então, passaremos isso para esse código no Inspetor. Em seguida, estou criando alguns valores locais, portanto, um
'wps' aqui, que agarrará todos os waypoints do gerente e, em seguida, temos um
GameObject representando o nó atual que estamos tentando acessar e que, Eu acho que essencialmente, é o nosso objetivo
a qualquer momento.
Depois disso, existe um int chamado currentWP.
Agora, este é o índice do waypoint ao longo do caminho que estamos seguindo.
Portanto, se estivermos seguindo um caminho e digamos que há três pontos de referência,
o primeiro será 0,
o próximo será 1 e o próximo será 2.
Portanto, isso é apenas para acompanhar como avançamos no caminho que o algoritmo
A * calculou para nós. Não tem nada a ver com a posição do waypoint
em nossa matriz de waypoints.
Então é uma coisa completamente diferente.
Agora, depois disso, tenho o Graph declarado também e essas coisas, este
'wps' e 'Graph' é apenas para tornar nosso código um pouco mais curto mais tarde e você verá
o porquê imediatamente, porque no Start é onde eu defini eles.
Se eu não tivesse essas duas coisas, teríamos que digitar esse código
toda vez que quiséssemos agarrar algo do gerenciador de waypoints.
Portanto, é muito mais fácil atribuí-lo a essas variáveis aqui, onde podemos obtê-lo.
Em seguida, precisamos definir o nó atual que é esse objeto de jogo aqui em cima, que aponta para o nó físico, a
esfera do objeto de jogo físico que está em nosso mundo.
Isso aqui é definido como 7 neste caso, porque meu tanque (se dermos uma olhada aqui) está próximo de 7.
Na verdade, NÃO está perto de 7, estava perto de 7, está perto de 1 agora.
Meus waypoints foram renumerados.
Então, vamos mudar isso para 0, porque para o waypoint 1 na matriz, estamos posicionados em 0.
Portanto, seja qual for o waypoint em que seu tanque esteja próximo, é isso que
você deseja para o seu início, para que ele tenha algum tipo de referência sobre onde está atualmente e como calculará como ele
se move através do algoritmo A *.
Então esse é o começo.
Agora, depois disso, há duas funções às quais voltarei ... vamos descer aqui.
Agora, no LateUpdate, existe antes de tudo
uma instrução 'if' perguntando se o comprimento do caminho do nosso gráfico (então se
(g. getPathLength ()
== 0) que basicamente diz que não há comprimento do caminho, ou o índice do waypoint atual é igual ao
comprimento do caminho.
Se você possui um caminho com três nós e está no terceiro nó, o comprimento do caminho também é 3,
porque há
três coisas nele.
Se esses dois forem iguais, significa que você está no fim.
Portanto, se você tem um caminho vazio ou está no final do caminho, basta retornar.
Você não quer seguir em direção a nenhum objetivo, porque não existe.
Depois disso, configuramos o nó atual para obter o ponto do caminho no valor atual do waypoint.
Portanto, se estamos nos movendo ao longo de um caminho e podemos dizer a posição número 3, dizemos que queremos
o terceiro nó nesse caminho e ele nos dará o nó físico que precisamos seguir aqui.
Depois disso, temos uma declaração 'if' de aparência muito familiar, que está testando nossa precisão.
Então, se a distância entre o tanque (que é essa transformação. posição) e o ponto no waypoint atual é menor
que a nossa precisão, então estamos perto o suficiente para atingir nosso waypoint, assim como os
outros algoritmos que já escrevemos.
Nesse caso, apenas aumentamos a contagem atual ao longo do nosso caminho e isso nos permitirá calcular o próximo
ponto e seguir em direção ao próximo ponto.
Em seguida, estamos fazendo outro teste para garantir que não atingimos o final do caminho (porque
esse código aqui em cima pode significar que atingimos o final do caminho), então podemos avançar nosso tanque
e nós ' movendo o tanque usando exatamente o mesmo código (que é esse aqui) que você verá que desenvolvemos anteriormente em nosso
script MoveLocal para mover e girar em direção a um ponto.
Portanto, isso é
exatamente o mesmo e o objetivo que estou definindo para ser igual à transformação da esfera atual que
está na posição 'currentWP' no caminho.
Então, exatamente o mesmo código, o mesmo tipo de movimento.
Tudo o que estamos fazendo agora é seguir um caminho que nos foi dado pelos pontos de referência, em vez
de dar ao agente uma posição a seguir, porque está seguindo algo no mapa.
Por fim (e como estou ficando sem tempo neste vídeo de 20 minutos), você precisa adicionar essas
duas funções públicas que mostraremos como usar na próxima aula.
São funções públicas que podem ser executadas fora, portanto, conectaremos botões na tela até eles.
O que eles estão fazendo é executar o algoritmo A *, então esse é o processo que faz todo o trabalho.
Se quisermos ir para o heliponto, então o heliponto está no waypoint 2.
Eu ainda tenho meus antigos sistemas de waypoint aqui. O waypoint 2 será o waypoint 1 na matriz, porque lembre-se
de que as matrizes começam a contar em zero.
E o Ruin é o waypoint 7 para mim, que seria 6 no array lá.
Portanto, pega o nó atual em que você está, o destino e o executa através do algoritmo A *, que
fornecerá o caminho que agora é usado no LateUpdate. Após cada uma das chamadas A *, certifique-se
de definir seu contador de waypoints de volta para 0, para que você possa começar no ponto
0 do mapa e seguir adiante.
Portanto, esse é todo o código para o FollowPath. Salve isso e eu conversarei com você na próxima aula,
onde implementaremos isso com alguns botões.