Nesta palestra, vamos implementar um sistema GOAP no Unity.
Agora você pode baixar o arquivo inicial a seguir e ele
se chama GOAP. fecho eclair.
Existem 2 arquivos iniciais com esta palestra ... há o GOAP. zip e também há
um goap-master. fecho eclair.
O goap-master é a versão completa desta biblioteca GOAP que eu peguei da URL que você pode ver na
tela.
Portanto, há outros exemplos e outras coisas para você ver mais
tarde e o que fiz com apenas o GOAP é que retirei o máximo que
posso e também o modifiquei para permitir uma navegação Mesh Agent porque usaremos um NavMesh para colocar nossos agentes na
tela entre seus diferentes destinos.
Agora, se você trouxer o GOAP. zip no Unity, você encontrará ISTO quando abrir a cena
da vila.
Eu tenho um agente e ele vai ser um padeiro.
Esta é a padaria dele ...
este é o moinho de vento que fornece a farinha ...
e aqui, temos alguns mercados. Agora, em cada um desses edifícios, incluí um
cubo (que
chamei de 'Porta') e você pode ver isso na Hierarquia. O agente precisa de um local para ir, para executar a tarefa e você
pode levá-los ao prédio real para executar a tarefa, mas eu pensei que seria
bom ter apenas um pequeno marcador para onde eles poderiam ir, então
é por isso que eu os adicionamos aqui e você os verá em uso mais tarde.
Agora, esse agente está em um avião, que é um NavMesh.
Se você abrir a guia Navegação, verá que o NavMesh já está aplicado.
O agente (que se chama Baker porque vamos fazê-lo assar um pouco de pão) na Hierarquia já
tem algumas coisas configuradas.
Então, primeiro de tudo, ele tem o Nav Mesh Agent lá, que é o que todos usamos para
navegar pela cena.
Você também precisa adicionar a qualquer agente (que é um agente GOAP) o script 'Goap Agent' e esse script do Goap Agent está
nos ativos na pasta GOAP.
Chegaremos a isso em um momento, que já está escrito para você. Então, as coisas que você precisa
escrever sobre o sistema GOAP são os scripts que executam o agente em si.
Estamos chamando-o de trabalhador e o agente também tem um inventário, e eu voltarei para ver aqueles em um segundo.
Vamos para o Ativos e dar uma olhada na pasta AI.
Você descobrirá que há uma pasta FSM (Finite State Machine).
Essa é a pequena máquina de estado que apenas direciona o agente de um local para outro para
executar as tarefas.
Ele não usa o State Machine System incorporado ao Unity, tudo é feito por código.
É uma coisa tão simples que ele realmente não precisa do Sistema de Animação para configurar
todos os diferentes estados e transições entre ele, porque são basicamente apenas dois estados com os quais
você precisa lidar.
Depois, há uma pasta GOAP. Vá para a pasta GOAP e é aqui que
você encontrará todas as classes que atendem às diferentes partes da arquitetura GOAP. Primeiro, há o agente GOAP, que cuida das ações básicas do
agente e garante que ele execute o Planejador, procure Objetivos e acompanhe o
Estado Mundial à medida que ele muda.
Temos então uma ação Goap.
Agora, cada ação que você adicionar herdará dessa classe específica e permitirá criar várias ações,
mesmo que não sejam usadas.
Lembre-se: uma ação no sistema GOAP pode ser adicionada.
Ele não está conectado a nada, apenas está sentado ali, como ele mesmo, e possui Condições Prévias e Efeitos, e o que
acontece quando há
um Objetivo que chega é que o
Planejador reúne todas essas Ações e tenta reuni-las. , para ver onde as Condições prévias e os Efeitos se
unem para formar uma cadeia, que se torna seu Plano. Portanto, você pode adicionar o máximo possível
dessas ações ao seu agente, mas se elas
não tiverem condições e efeitos que se unirão a outras ações, elas nunca serão
usadas.
Portanto, essa é uma das coisas que você realmente precisa observar ao projetar suas ações,
mas abordaremos isso quando começarmos a fazer nossas próprias ações e o quão importante é, para que
elas se reúnam.
O próprio GoapPlanner reúne todas as ações disponíveis e as verifica em relação às condições, ao
estado do mundo e a quaisquer metas em particular e cria seu plano de ações encadeado, depois
relata isso ao agente que usa a máquina de estados finitos para executar as ações ao longo da cadeia.
Agora, o código em que estamos interessados e o código que escrevemos para interagir com o sistema GOAP está atualmente em
nosso Baker e esse é o script Worker e o inventário. O script Inventário, se você o soltar
no Inspetor, verá que ele possui níveis para Farinha e Pão.
Então, essas são as coisas que o agente tem, é como a "mochila" ou o "inventário". Se você der uma olhada nesse
código, é realmente bastante simples.
Só existem alguns números inteiros com os valores
e estamos começando nosso agente como tendo 5 sacos de farinha.
Existe um OnGUI realmente simples lá, apenas para imprimi-lo na tela, para que possamos ver esses
valores mudarem enquanto executamos a simulação.
Agora, o código Worker que também está em nosso agente herdará da nossa interface GOAP aqui (IGoap), que é essencialmente nosso
agente GOAP.
Está aí, obviamente, o nosso NavMeshAgent, do qual precisamos contorná-lo.
Há também um vetor de destino3 anterior que está sendo armazenado pelo motivo da navegação, que você verá em um
momento e também
temos um link para o nosso sistema de inventário que está nesse agente.
Essas duas coisas (o NavMeshAgent e o Inventory) são configuradas dentro do Start.
Então, agarramos esses dois componentes, para que
não precisemos continuar fazendo isso por todo o código.
Agora, passando esse código, chegamos a algumas das partes mais importantes desse agente e são
esses dois próximos métodos: GetWorldState e CreateGoalState. O GetWorldState injeta no sistema GOAP,
o estado do mundo.
Agora, vamos usar os estados 'verdadeiro'
e 'falso', como vimos originalmente na palestra anterior e vamos defini-los aqui.
Portanto, isso continuará sendo executado e atualizado para o seu agente, para que o sistema de planejamento possa verificar se
determinados estados foram alcançados ou não.
Agora, neste caso, inicialmente, estamos definindo nosso estado mundial 'hasFlour' como True ou False com
base no inv. flourLevel. Antes de continuarmos, gostaria de explicar a
estrutura das Condições e Efeitos, pois elas são essencialmente a cola que mantém todas as Ações juntas na cadeia.
Todos eles são armazenados em um HashSet no formato 'string, objeto'.
Nesse caso, estamos representando-os com uma sequência que explica o estado e, em seguida, um verdadeiro ou um falso.
Por exemplo, ("hasFood", true) ("hasBread", false). Você verá esses conjuntos de ações posteriormente e elas
são verdadeiramente as condições que unirão cada ação, de modo que, para cada ação Pré-requisito,
você precisará ter outra ação que tenha um efeito que os magnetize e combine-os juntos, para que
eles possam formar uma corrente.
Se você não tiver pessoas em nenhum lugar do seu conjunto de ações, essa ação não será usada e você poderá descobrir que
o Planejador não pode encontrar um plano.
Então, voltando ao nosso código. Onde colocamos essas Condições e Efeitos está dentro
desses 2 métodos que acabamos de falar, entre a declaração inicial para o conjunto 'worldData' e também para o conjunto 'goal'.
Então, este é todos os estados do mundo, como eu disse. Ele é atualizado o tempo todo, portanto, essa
função é chamada o tempo todo para continuar verificando se esse 'hasFlour', por exemplo, é True ou False
e é por isso que podemos colocar essas variáveis aqui, que podemos mudar.
Esse é o nível de farinha no inventário e não vai dizer que você tem farinha a menos que o
nível de farinha seja maior que 1.
Portanto, neste caso, não considera que você tenha farinha suficiente para fazer qualquer coisa até ter 2 sacos
de farinha.
Portanto, isso define o limite de quantos sacos de farinha são considerados 'ter farinha suficiente para
assar'.
Agora, se você tem outras condições nos Estados do mundo que deseja fazer e
que possuem um valor variável, é possível adicioná-las aqui.
Você não pode colocar valores de tipo variável como este dentro de suas Ações, porque não funcionará.
As ações devem corresponder exatamente quando for
planejado e, se não o fizerem, o sistema será paralisado.
Então, vamos ver isso daqui a pouco de qualquer maneira.
Então esse é o seu worldData.
Agora, as próprias metas variam entre o local
em que você declara o conjunto de metas e o local em que as devolve.
Então aqui dentro, quero que você adicione um novo objetivo para o nosso Baker e será assim.
Então aqui está a nossa pequena string aqui e aqui está o nosso valor Verdadeiro ou Falso.
Agora, esse é um objetivo global para o nosso agente e
será chamado de "doJob",
então "doJob" é True e continuará forçando isso no agente, e ele continuará se certificando de
que está tratando disso. objetivo particular.
Então, teremos apenas um objetivo aqui.
Então adicione isso e, mais abaixo, vamos dar uma olhada no restante do código.
Temos o código para mover o agente.
Este é apenas o código de tipo típico que move o NavMeshAgent e
o que ele faz são algumas coisas.
Antes de tudo, ele verifica nosso destino anterior (lembre-se de que Vector3 na parte superior deste código)
verifica se não é o mesmo de onde precisamos ir para o próximo porque se um NavMeshAgent estiver no seu destino
quando receber um novo objetivo, então, ele não planejará um caminho e isso se tornará um problema para
determinar se alcançamos nosso próximo destino para realizar nossa próxima tarefa.
Portanto, se a tarefa estiver na mesma posição que a última, isso será resolvido porque o
agente não precisa se mover fisicamente pelo ambiente, no momento em que
definimos nextAction. setInRange para true.
Agora, cada ação não será executada, A menos que o seu agente esteja dentro do alcance de onde isso precisa acontecer.
Então é isso que esta linha aqui está fazendo.
Então, se não formos obrigados a permanecer no mesmo destino (precisamos ir para outro lugar), usaremos nosso NavMesh
com SetDestination usando o nextAction. alvo. transformar. posição para nos empurrar
para o próximo local e, em seguida, executaremos verificações como fizemos anteriormente com o NavMeshes para verificar
se chegamos ao nosso destino.
Portanto, se temos um caminho e estamos a uma distância de 2, chegamos ao nosso destino.
Essa é basicamente a sua precisão de quão perto você deseja chegar e, em seguida,
fazemos a mesma coisa.
Portanto, estamos dentro do
alcance e atualizamos nosso Destino anterior, para que isso registre onde estamos e retornemos True,
para que o sistema saiba que estamos no nosso destino e que estamos prontos para a próxima ação.
Tudo certo.
Portanto, passando para a atualização, você não precisa de nada dentro da atualização, mas
o que eu fiz aqui é apenas adicionar um pouco de código que ajudará seu agente a desacelerar
e acelerar melhor nos cantos e você pode realmente aplicar isso bloco if inteiro para qualquer código do Nav Mesh
Agent que
você tenha, se desejar que seus agentes tomem partido.
Então, desenvolvi isso para outra coisa em que estava trabalhando e pensei em colocá-lo aqui.
Isso funciona muito bem se você está tentando fazer com que seus agentes se desloquem pelas ruas e estradas
e deseja que eles permaneçam lá e não vire para a calçada, o que eles farão se
estiverem indo muito rápido .
Isso irá atrasá-los nos cantos para você, então
tome nota disso e, mais adiante,
temos alguns métodos que na verdade não estamos implementando, mas apenas precisamos deles, caso contrário, ele irá reclamar
e mais tarde
quando você Se estiver mais confortável com esse sistema, você pode voltar
e colocar seu próprio código aqui.
Então, primeiro de tudo, há um que é chamado quando o plano falha ... um quando o plano é encontrado ... quando sua ação
terminar ...
e quando seu plano foi abortado. Portanto, se você quiser explorá-las, coloque aqui as
instruções Debug para ver quando
elas realmente são executadas, mas não as usaremos.
Está bem.
Nesse ponto, se você pressionar Play, verá no console (se você for lá) as mensagens que saem do
sistema.
Portanto, essas mensagens estão nas instruções Debug em toda a biblioteca GOAP que você está usando e você pode encontrá-las se
der uma olhada, mas elas vão lhe dar uma idéia do que está acontecendo.
Então, o que estamos recebendo no momento é que são encontradas ações.
Agora, na verdade, ele não encontrou nenhuma ação porque ainda não
colocamos nenhuma ação, mas ainda assim foi encontrado um conjunto de ações vazio e, em seguida, tentando fazer um plano que
satisfaça a meta "doJob" e não consegue encontrar uma. , obviamente, apenas faz isso (SEM PLANO) e, em
seguida, fornece a mensagem 'Falha no plano'.
Então você saberá à medida que avança e programa esse sistema, quando as coisas não estão funcionando. Ok, deixaremos esta palestra aqui e, na
próxima palestra, começaremos a criar ações para o nosso agente.