Nesta palestra, examinaremos o conceito de 'Fugir'.
É uma técnica comum usada em A. EU. para fazer com que um NPC se afaste de um local.
A técnica pode ser usada em qualquer tipo de NPC. Nesse caso, aplicaremos à nossa multidão
em que estamos trabalhando. Matematicamente, fugir funciona assim ... um objeto ou local é introduzido
em um ambiente.
O NPC determina onde o objeto está em relação à sua própria posição. Eles então calculam um novo local da
meta que está longe do objeto.
Nesse caso, usaremos a direção oposta exata.
Isso pode ser calculado usando o vetor em direção ao objeto e retirando-o da posição dos NPCs.
Com a nova localização do objetivo,
o agente pode se virar e começar a segui-lo, sendo retirado do objeto em questão. Outros fatores que podemos considerar são
o 'raio de influência do objeto' e o 'período de espera'. O raio determina o quão perto um
NPC deve estar de um objeto a ser afetado e a recarga é por quanto
tempo o NPC foge antes de retornar ao comportamento normal. Para implementar a fuga na multidão atual da cidade e chegar
ao ponto em que estou agora, você precisará adicionar um cilindro e fazer uma pré-fabricação a partir dele.
Então, o que eu fiz foi acessar a Hierarquia e clicar com o botão direito do mouse> Objeto 3D> Cilindro 'e eu
não alteramos o tamanho, mas o que fiz foi criar um material verde e anexá-lo a esse cilindro.
Peguei esse cilindro da Hierarquia e arrastei-o para o Ativo, o que criará uma
pré-fabricação desse cilindro para você. Vou apenas excluir minha segunda versão.
Agora, este cilindro não está fazendo nada além de marcar o local em que vamos clicar.
Então, precisamos de algum código para posicionar o cilindro no NavMesh, onde clicamos com o mouse.
Então, vamos criar um novo código C # e vamos chamá-lo de 'DropCylinder', abrir esse código e
adicionaremos esse código.
Então, primeiro de tudo, temos um objeto de jogo público exposto que estamos chamando de 'obstáculo'.
É aqui que passaremos pela nossa pré-fabricada do cilindro.
Vamos então manter uma matriz de todos os agentes que estão em cena e,
portanto, no Start, coletaremos todos esses agentes encontrando os objetos do jogo que possuem a
tag 'agent'.
Isso significa que você terá que criar a tag 'agente' e adicioná-la aos seus personagens.
Então, eu tenho meus personagens. Coloquei-os em 'Multidão' e os duplicou. Eu criei alguns deles. Não tenha muitos, porque quanto mais
você tem, mais lento isso vai acontecer, mas você quer apenas
o suficiente.
Agora, sob esse 'Multidão', se você clicar em todos eles, poderá adicionar uma tag 'agente'.
Então, eu criei uma nova tag chamada 'agent', com uma letra minúscula 'a' e apenas defini-a para todos os personagens que
estão na multidão.
Então, voltando ao código, esses agentes estarão sentados nessa matriz de 'agentes' e isso significa que,
quando descartamos o objeto, podemos enviar uma mensagem a todos eles dizendo que esse objeto
está lá. É
como o Agent Manager que tivemos em palestras anteriores. Agora, na atualização, é onde o botão do
mouse será testado e, em seguida, faremos um RaycastHit no mundo a partir da posição da tela, usando
a posição do mouse na câmera principal.
Isso significa que sua câmera está marcada
como 'MainCamera'.
Então lembre-se de onde isso é ... vá para
a câmera e a etiqueta deve ser 'MainCamera' aqui, para que ela capte isso.
Agora, estamos fazendo nosso Raycast de física no mundo, descobrindo onde ele atinge ... onde ele atinge, instanciamos uma
cópia do nosso cilindro.
Então esse é o obstáculo, vamos colocá-lo no local da ocorrência e depois usaremos a rotação padrão
da pré-fabricada para isso, porque realmente não é tão importante.
Em seguida, temos uma declaração 'foreach' que percorre todos os agentes da
cena e chama um método para eles (que ainda não escrevemos), mas será chamada 'DetectNewObstacle' e
nós ' vou passar o hitInfo. point, que é o local de onde estamos colocando o cilindro.
Então, isso é essencialmente dizer ao nosso agente que há um obstáculo sendo colocado e agora
é seu trabalho fugir dele. Então salve isso ... isso lhe dará um pequeno erro, porque ainda não
escrevemos esse DetectNewObstacle,
mas é isso que faremos a seguir.
Abra o script AIControl e este é o script que você deve anexar a cada
agente na
cena; portanto, é sempre uma boa ideia criar um e
duplicá-lo para que você não precise adicioná-lo. Meu código AIControl é um pouco diferente do que eu
deixei na última palestra, então eu o analisarei rapidamente e mostrarei as alterações.
Primeiro de tudo, eu criei esse 'speedMult' aqui em cima. Ele foi incorporado no código mais abaixo, como uma
variável
local, mas agora vamos usá-lo em alguns lugares diferentes.
Portanto, o objetivo agora é ter 2 tipos diferentes de animações e 2 tipos diferentes de velocidade. Temos a caminhada e também
a
corrida, de modo que, quando o obstáculo for derrubado e o personagem
estiver fugindo, queremos que ele fuja.
Então coloque isso no topo. Em
seguida, criei uma função chamada 'ResetAgent', porque eu redefiniria a velocidade do agente aqui e ali, dependendo de você estar fugindo
ou apenas vagando e, portanto, é bom ter tudo disso
em um único local, para que seja fácil mudar e atualizar.
Agora, aqui você pode ver no ResetAgent, quando isso acontecer, ele definirá o multiplicador de velocidade como um valor aleatório.
Antes, fazia isso e a função Iniciar para que o agente sempre tivesse a mesma velocidade.
Agora isso mudará a velocidade do
agente toda vez que houver uma redefinição.
Portanto, é uma ótima maneira de tornar seus personagens um pouco mais aleatórios em seus movimentos, para
que eles nem sempre estejam na mesma velocidade para o mesmo personagem.
Agora, a seguir, temos a velocidade do agente definida aqui.
Lembre-se de que é 2 como padrão nos caracteres, multiplicado pelo valor speedMult.
Então, é só ter certeza de que está definido como 2
e também estou configurando a velocidade angular.
Se você der uma olhada no angularSpeed padrão no NavMesh Agent em um de seus
personagens, verá que ele é 120.
A velocidade angular é a rapidez com que o personagem se vira.
Agora, o que eu quero é aumentar isso quando o personagem tiver que fugir.
Então você quer que eles vejam algo de que precisa fugir e se virar muito rapidamente, o
que significa que você precisa aumentar a velocidade angular e também quando, quando voltarem a andar, você terá
que abaixá-lo novamente. .
Então, estou colocando aqui de volta para 120. No ResetAgent, quando for
redefinido, ele definirá o valor speedMult que está no sistema de animação como speedMult e definirá a
animação
curta novamente e, em seguida, estou fazendo um ResetPath aqui que limpa o caminho atual que o agente
possui. calculado e basicamente o retorna de volta a 0 para que possa
estar pronto para gerar outro caminho no sistema NavMesh.
Agora, a função Iniciar ... o que faz é praticamente o que tínhamos antes.
Por isso, ele captura todos os locais de
meta do mundo, os agentes NavMesh, define o destino com um valor
aleatório (esse código é exatamente o mesmo de antes, apenas aumentarei para
que você possa vê-lo), localização aleatória fora da matriz goalLocations, agarra o animador que está no personagem e
também define o deslocamento de caminhada (para que eles não andem todos juntos) para um valor entre aqui e
depois executamos o ResetAgent (que seguirá em frente e definirá todos esses valores que estão aqui em
cima para nós).
Agora, na atualização, é a mesma coisa que tínhamos antes, exceto que estamos fazendo um ResetAgent antes
de definir o próximo destino.
O que isso significa é que, se estivermos correndo para um local porque estamos fugindo
dele, quando chegarmos lá, voltaremos a andar e buscaremos outro local
de objetivo e continuaremos vagando por aí. As novidades que adicionaremos a este código para facilitar a fuga ...
Em primeiro lugar, precisamos de um float, que será o 'detectionRadius' e essa é a distância de 'onde o objeto
é descartado' a 'até que ponto os agentes próximos precisam estar para poder ouvi-lo'.
Agora, se você tiver esse tamanho, todos os agentes da área responderão a ele. Se for menor, apenas os que estão dentro de
um raio de 5 irão responder, o que é bom porque você pode ter uma pequena
distração em fuga ou pode ter algo que é bastante grande como uma distração em fuga.
Também precisamos de um carro alegórico para o 'fleeRadius' e é
assim que você deseja que os personagens fuja do objeto antes que eles se esqueçam dele e comecem a
voltar e procurar um novo local para o objetivo.
Então, vamos definir isso para 10, neste caso.
Certo, agora, com isso, o que vamos fazer é criar o método que eu
falei antes (DetectNewObstacle) que está sendo chamado a partir da queda dos objetos no outro script de clique.
Portanto, o novo método ficará assim.
Então será público porque está sendo chamado de outro lugar e estamos passando pela
posição do obstáculo que está sendo jogado em cena.
Vamos então fazer um teste de distância da 'posição do objeto' e da 'posição do agente'.
Agora, se estiver dentro do raio de detecção, o agente reagirá a ele.
Se o agente vai fugir, ele precisa determinar em qual direção
ele vai fugir, que está longe da posição do obstáculo e determinar isso, é a posição
do agente menos a posição do obstáculo. Observe que eu estou normalizando para ter um vetor
de comprimento 1 e vou usá-lo como 1 para multiplicá-lo pelo fleeRadius, que você pode ver aqui.
Portanto, é o fleeDirection para um comprimento de fleeRadius, adicionado à posição atual do agente e é
aí que está o novo objetivo.
Agora, com essas novas informações sobre a meta, podemos definir o destino do
agente, mas de antemão, vamos ver se conseguimos chegar a esse local.
Então você poderia ter um agente. setDestination newgoal, mas, nesse caso, é
possível calcular um local que esteja totalmente fora do NavMesh do agente ou não ser
totalmente acessível e isso significa que você ainda deseja que o agente tente
acessá-lo, se possível.
Portanto, essa é uma maneira diferente de trabalhar o caminho.
O que fazemos é criar um objeto de caminho NavMesh e esse objeto de caminho pode ser calculado com
CalculatePath.
Então, criamos esse valor para o caminho e o passamos para calcular o caminho, dada a nova posição do objetivo.
Agora, esse caminho manterá o caminho que o agente seguirá para chegar
ao objetivo, mas se ele puder apenas fazer parte do caminho ou não conseguir, você
poderá testá-lo. status.
Nesse caso, se o caminho. status não é igual a um caminho inválido,
ele definirá o destino para o final do caminho que é calculado. Então, o próprio 'caminho' termina com uma matriz chamada 'cantos' e essa é uma matriz de
todos os pontos de referência, essencialmente, que o personagem seguirá à medida que for de onde está
até a localização do objetivo.
Agora, se não for possível chegar até o local da meta, você ainda terá essa matriz de cantos,
mas isso levará apenas parte do caminho, o que significa que se você obtiver o
último valor na matriz de cantos (que é esse um aqui), você chegará ao final do caminho
que foi calculado, mesmo que não tenha atingido a meta exata. Portanto, você fará com que o agente se afaste pelo menos de alguma maneira de onde
você colocou o obstáculo.
Nesse ponto, configuramos a animação para execução e, em seguida, aceleramos o agente com o agente. velocidade e aumentamos a velocidade angular bastante alta, porque
queremos que o agente dê meia-volta muito rapidamente e depois
siga na direção totalmente oposta.
Tudo bem, então salve isso e depois voltaremos para o Unity. O que você precisa fazer para testar isso (você pode
ver que removi todos os prédios, dupliquei
meus agentes) Tenho quatro objetivos e os coloquei em um quadrado ao redor da área,
então os agentes quando eu pressiono Play, apenas andamos aleatoriamente entre esses objetivos.
Agora, para configurar o clique para o cilindro, temos nosso script DropCylinder aqui. Vou apenas adicioná-lo à câmera (arraste
e solte na câmera).
Ele só precisa estar em cena para que seja executado e, em seguida, o script DropCylinder exija nosso Cilindro
pré-fabricado que criamos anteriormente.
Então pegue isso e coloque-o lá. Agora, quando pressionamos Play, se soltarmos um cilindro, você verá
que os agentes fogem dele e depois voltam porque só fogem o mais longe que precisam
para encontrar a localização do objetivo e então começam a vagar
de volta e procurando outros objetivos. Então eles ainda estão se movendo aleatoriamente em torno
desses 4 objetivos diferentes, que estão nesses quatro cantos, onde eles tendem a se agrupar.
Certo, então, se você quiser mudar isso para que todos reajam, se voltarmos ao nosso AIControl, vá para o
topo aqui e se mudarmos esseradio de detecção para 20, isso provavelmente deve abranger
todo mundo nessa cena. Salve isso.
Volte e pressione Play. Quando deixarmos isso aqui, todos vão fugir.
Agora eles ainda não estão fugindo muito, porque você ainda tem esse raio de 10 (ou o que quer que
tenhamos lá) e pode mudar isso se quiser empurrá-los até as bordas do NavMesh.
Agora, as chances são de que, quando você estiver fazendo isso, haverá um agente estranho que aparentemente estará ignorando o
obstáculo e isso acontecerá porque no seu script do AIControl logo abaixo, onde você está calculando o caminho,
pode ser possível se você tem um fleeRadius muito, muito grande para tentar calcular um novo objetivo que está
tão distante do NavMesh atual que apenas retornará um caminho inválido e não há realmente nada
que você possa fazer sobre isso.
Então você tem que viver com isso.
A outra alternativa é que você teria que programar manualmente como uma parte 'outra' para isso aqui,
o agente girando e saindo na direção oposta, o que significa que você perde
o controle do agente e o agente não estaria mais navegando via NavMesh
e isso pode causar problemas.
Portanto, você decide se deseja ou não fazer isso ou
se está feliz em aceitar o fato de que isso não funciona.
Caso contrário, você realmente precisa ter certeza de que seu fleeRadius estará dentro do NavMesh ou, pelo menos, não
muito ridiculamente longe do NavMesh, para que não calcule um caminho válido para você.
Então é assim que seus NPCs fogem de um espaço.
Isso está usando o método NavMesh, mas o cálculo do vetor a ser executado e a nova localização da meta é exatamente
a mesma, se você quiser implementar isso em seu próprio sistema de waypoint manual.
Você apenas criaria um novo waypoint em tempo real e forneceria essa nova posição de objetivo, com a matemática vetorial
que está neste programa em particular.