{"id":52118,"date":"2019-11-01T00:00:00","date_gmt":"2019-10-31T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih"},"modified":"2020-02-18T13:59:47","modified_gmt":"2020-02-18T10:59:47","slug":"kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","title":{"rendered":"Como criar uma IA para jogos: guia para iniciantes","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/9e57175b233a104e0df98383b374eded.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEncontrei um material interessante sobre intelig\u00eancia artificial em jogos. Com explica\u00e7\u00f5es b\u00e1sicas sobre IA usando exemplos simples, al\u00e9m de muitas ferramentas e m\u00e9todos \u00fateis para seu desenvolvimento e design pr\u00e1ticos. Como, onde e quando us\u00e1-los \u2014 tamb\u00e9m est\u00e1 inclu\u00eddo.<\/p>\n<p>A maioria dos exemplos est\u00e1 escrita em pseudoc\u00f3digo, portanto, conhecimentos profundos de programa\u00e7\u00e3o n\u00e3o ser\u00e3o necess\u00e1rios. Na sequ\u00eancia, h\u00e1 35 p\u00e1ginas de texto com imagens e gifs, ent\u00e3o prepare-se.<\/p>\n<p>UPD. Pe\u00e7o desculpas, mas j\u00e1 fiz minha pr\u00f3pria tradu\u00e7\u00e3o deste artigo no Habrahabr <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/PatientZero\/\">PatientZero<\/a><\/noindex>. Voc\u00ea pode ler a vers\u00e3o dele <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/420219\/\">aqui<\/a><\/noindex>, mas por algum motivo, o artigo passou despercebido por mim (usei a pesquisa, mas algo n\u00e3o funcionou). E como escrevo em um blog dedicado ao desenvolvimento de jogos, decidi deixar minha vers\u00e3o da tradu\u00e7\u00e3o para os assinantes (alguns pontos est\u00e3o formatados de maneira diferente, outros \u2014 intencionalmente omitidos por conselho dos desenvolvedores).<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>O que \u00e9 IA?<\/h2>\n<p>\nA IA em jogos se concentra nas a\u00e7\u00f5es que um objeto deve realizar, com base nas condi\u00e7\u00f5es em que se encontra. Isso \u00e9 geralmente chamado de gerenciamento de \"agentes inteligentes\", onde o agente pode ser um personagem do jogo, um ve\u00edculo, um bot ou, \u00e0s vezes, algo mais abstrato: um grupo inteiro de entidades ou at\u00e9 mesmo uma civiliza\u00e7\u00e3o. Em cada caso, \u00e9 algo que deve perceber seu ambiente, tomar decis\u00f5es com base nisso e agir de acordo. Isso \u00e9 chamado de ciclo Sense\/Think\/Act (Perceber\/Pensar\/Agir):<\/p>\n<ul>\n<li>Sense: o agente encontra ou recebe informa\u00e7\u00f5es sobre coisas em seu ambiente que podem afetar seu comportamento (amea\u00e7as pr\u00f3ximas, itens para coleta, locais interessantes para explora\u00e7\u00e3o).<\/li>\n<li>Think: o agente decide como reagir (considera se \u00e9 seguro coletar itens ou se primeiro deve lutar\/escapar).<\/li>\n<li>Act: o agente executa a\u00e7\u00f5es para realizar a decis\u00e3o anterior (come\u00e7a a se mover em dire\u00e7\u00e3o ao inimigo ou ao item).<\/li>\n<li>\u2026agora a situa\u00e7\u00e3o mudou devido \u00e0s a\u00e7\u00f5es dos personagens, portanto, o ciclo se repete com novos dados.<\/li>\n<\/ul>\n<p>\nA IA, geralmente, se concentra na parte Sense do ciclo. Por exemplo, carros aut\u00f4nomos fazem imagens da estrada, as combinam com dados de radar e lidar, e interpretam. Normalmente, isso \u00e9 feito por meio de aprendizado de m\u00e1quina, que processa os dados de entrada e lhes atribui significado, extraindo informa\u00e7\u00f5es sem\u00e2nticas como \"h\u00e1 mais um carro a 20 jardas \u00e0 sua frente\". Esses s\u00e3o chamados de problemas de classifica\u00e7\u00e3o.<\/p>\n<p>Os jogos n\u00e3o precisam de um sistema complexo para extrair informa\u00e7\u00f5es, pois a maior parte dos dados j\u00e1 faz parte integrante deles. N\u00e3o \u00e9 necess\u00e1rio rodar algoritmos de reconhecimento de imagens para determinar se h\u00e1 um inimigo \u00e0 frente \u2014 o jogo j\u00e1 sabe e transmite informa\u00e7\u00f5es diretamente no processo de tomada de decis\u00e3o. Portanto, a parte do ciclo Sense \u00e9 muitas vezes muito mais simples do que Think e Act.<\/p>\n<h2>Limita\u00e7\u00f5es da IA em jogos<\/h2>\n<p>\nA IA tem uma s\u00e9rie de limita\u00e7\u00f5es que precisam ser observadas:<\/p>\n<ul>\n<li>A IA n\u00e3o precisa ser treinada antecipadamente, como se fosse um algoritmo de aprendizado de m\u00e1quina. \u00c9 sem sentido criar uma rede neural durante o desenvolvimento para observar dezenas de milhares de jogadores e aprender a melhor forma de jogar contra eles. Por qu\u00ea? Porque o jogo n\u00e3o foi lan\u00e7ado e n\u00e3o h\u00e1 jogadores.<\/li>\n<li>O jogo deve entreter e desafiar, portanto, os agentes n\u00e3o devem encontrar a melhor abordagem contra humanos.<\/li>\n<li>Os agentes precisam parecer realistas, para que os jogadores sintam que est\u00e3o jogando contra pessoas reais. O programa AlphaGo superou os humanos, mas os passos selecionados estavam muito distantes da compreens\u00e3o tradicional do jogo. Se o jogo imita um oponente humano, esse sentimento n\u00e3o deve existir. O algoritmo precisa ser ajustado para que ele tome decis\u00f5es plaus\u00edveis, e n\u00e3o ideais.<\/li>\n<li>A IA deve operar em tempo real. Isso significa que o algoritmo n\u00e3o pode monopolizar o uso da CPU por longos per\u00edodos para tomar decis\u00f5es. At\u00e9 mesmo 10 milissegundos para isso \u00e9 muito tempo, pois a maioria dos jogos precisa de entre 16 a 33 milissegundos para processar tudo e passar para o pr\u00f3ximo quadro gr\u00e1fico.<\/li>\n<li>\u00c9 ideal que pelo menos parte do sistema seja controlada por dados, para que \"n\u00e3o-codificadores\" possam fazer mudan\u00e7as e para que os ajustes ocorram mais rapidamente.<\/li>\n<\/ul>\n<p>\nVamos considerar abordagens para a IA que abrangem todo o ciclo Sense\/Think\/Act.<\/p>\n<h3>Tomando decis\u00f5es b\u00e1sicas<\/h3>\n<p>\nCome\u00e7aremos com um jogo simples \u2014 Pong. O objetivo \u00e9 mover a plataforma (paddle) de forma que a bola rebata nela, em vez de passar de lado. \u00c9 como um t\u00eanis, onde voc\u00ea perde se n\u00e3o rebater a bola. Aqui, a IA tem uma tarefa relativamente f\u00e1cil \u2014 decidir em que dire\u00e7\u00e3o mover a plataforma.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/e1935d657b9f090bf60c365c21e8f92b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Operadores condicionais<\/h3>\n<p>\nPara a IA em Pong, a solu\u00e7\u00e3o mais \u00f3bvia \u00e9 sempre tentar posicionar a plataforma sob a bola.<\/p>\n<p>Um algoritmo simples para isso, escrito em pseudoc\u00f3digo:<\/p>\n<p><i>toda vez que o jogo est\u00e1 em execu\u00e7\u00e3o:<br \/>\nse a bola est\u00e1 \u00e0 esquerda da plataforma:<br \/>\n mover a plataforma para a esquerda<br \/>\nsen\u00e3o, se a bola est\u00e1 \u00e0 direita da plataforma:<br \/>\n mover a plataforma para a direita<\/i><\/p>\n<p>Se a plataforma se move na mesma velocidade que a bola, esse \u00e9 o algoritmo ideal para a IA em Pong. N\u00e3o \u00e9 necess\u00e1rio complicar, se os dados e as poss\u00edveis a\u00e7\u00f5es para o agente n\u00e3o s\u00e3o t\u00e3o numerosos.<\/p>\n<p>Essa abordagem \u00e9 t\u00e3o simples que todo o ciclo Sense\/Think\/Act \u00e9 quase impercept\u00edvel. Mas ele existe:<\/p>\n<ul>\n<li>A parte Sense est\u00e1 nos dois operadores if. O jogo sabe onde est\u00e1 a bola e onde est\u00e1 a plataforma, ent\u00e3o a IA consulta essa informa\u00e7\u00e3o. <\/li>\n<li>A parte Think tamb\u00e9m \u00e9 composta por dois operadores if. Eles encapsulam duas decis\u00f5es que, neste caso, s\u00e3o mutuamente exclusivas. Como resultado, uma das tr\u00eas a\u00e7\u00f5es \u00e9 escolhida \u2014 mover a plataforma para a esquerda, mover para a direita, ou n\u00e3o fazer nada se ela j\u00e1 estiver na posi\u00e7\u00e3o correta.<\/li>\n<li>A parte Act est\u00e1 nos operadores Mover Plataforma para a Esquerda e Mover Plataforma para a Direita. Dependendo do design do jogo, eles podem mover a plataforma instantaneamente ou a uma certa velocidade. <\/li>\n<\/ul>\n<p>\nEssas abordagens s\u00e3o chamadas de reativas \u2014 existe um conjunto simples de regras (neste caso os operadores if no c\u00f3digo) que reagem ao estado atual do mundo e agem.<\/p>\n<h3>\u00c1rvore de decis\u00f5es<\/h3>\n<p>\nO exemplo do jogo Pong equivale, de fato, a um conceito formal de IA chamado \u00e1rvore de decis\u00f5es. O algoritmo passa por ela para alcan\u00e7ar uma 'folha' \u2014 a decis\u00e3o sobre qual a\u00e7\u00e3o tomar.<\/p>\n<p>Vamos fazer um fluxograma da \u00e1rvore de decis\u00f5es para o algoritmo da nossa plataforma:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/d3b7290ba93144967cd849416cd5eef3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCada parte da \u00e1rvore \u00e9 chamada de node (n\u00f3) \u2014 a IA usa a teoria dos grafos para descrever tais estruturas. Existem dois tipos de n\u00f3s:<\/p>\n<ul>\n<li>N\u00f3s de decis\u00e3o: a escolha entre duas alternativas com base na verifica\u00e7\u00e3o de uma determinada condi\u00e7\u00e3o, onde cada alternativa \u00e9 representada por um n\u00f3 separado.<\/li>\n<li>N\u00f3s finais: uma a\u00e7\u00e3o a ser executada, representando a decis\u00e3o final.<\/li>\n<\/ul>\n<p>\nO algoritmo come\u00e7a pelo primeiro n\u00f3 ('raiz') da \u00e1rvore. Ele pode tomar uma decis\u00e3o sobre qual n\u00f3 filho deve acessar ou executar uma a\u00e7\u00e3o armazenada no n\u00f3 e, em seguida, finalizar.<\/p>\n<p>Qual \u00e9 a vantagem, ent\u00e3o, se a \u00e1rvore de decis\u00f5es realiza a mesma tarefa que operadores if na se\u00e7\u00e3o anterior? H\u00e1 um sistema geral, onde cada decis\u00e3o tem apenas uma condi\u00e7\u00e3o e dois poss\u00edveis resultados. Isso permite que o desenvolvedor crie IA a partir de dados que representam decis\u00f5es na \u00e1rvore, evitando a hardcoding. Vamos imaginar na forma de uma tabela:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/6875293a60ff9d0efa26fb5e1aa4b21c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDo lado do c\u00f3digo, voc\u00ea ter\u00e1 um sistema para ler linhas. Crie um n\u00f3 para cada uma delas, conecte a l\u00f3gica de tomada de decis\u00f5es com base na segunda coluna e os n\u00f3s filhos com base na terceira e quarta colunas. Voc\u00ea ainda precisar\u00e1 programar as condi\u00e7\u00f5es e a\u00e7\u00f5es, mas agora a estrutura do jogo ficar\u00e1 mais complexa. Nela, voc\u00ea adiciona decis\u00f5es e a\u00e7\u00f5es adicionais e, em seguida, configura toda a IA simplesmente editando um arquivo de texto com a defini\u00e7\u00e3o da \u00e1rvore. Depois, voc\u00ea passa o arquivo para o game designer, que poder\u00e1 alterar o comportamento sem recompilar o jogo ou modificar o c\u00f3digo.<\/p>\n<p>As \u00e1rvores de decis\u00f5es s\u00e3o bastante \u00fateis quando s\u00e3o constru\u00eddas automaticamente com base em um grande conjunto de exemplos (por exemplo, usando o algoritmo ID3). Isso as torna uma ferramenta eficaz e de alto desempenho para classificar situa\u00e7\u00f5es com base nos dados recebidos. No entanto, estamos indo al\u00e9m de um sistema simples para escolha de a\u00e7\u00f5es por agentes.<\/p>\n<h3>Cen\u00e1rios<\/h3>\n<p>\nAnalisamos o sistema de \u00e1rvore de decis\u00f5es, que usou condi\u00e7\u00f5es e a\u00e7\u00f5es pr\u00e9-criadas. A pessoa que projeta a IA pode organizar a \u00e1rvore como desejar, mas ainda precisa confiar no programador que codificou tudo isso. E se pud\u00e9ssemos dar ao designer ferramentas para criar suas pr\u00f3prias condi\u00e7\u00f5es ou a\u00e7\u00f5es?<\/p>\n<p>Para que o programador n\u00e3o precise escrever c\u00f3digo para as condi\u00e7\u00f5es Is Ball Left Of Paddle e Is Ball Right Of Paddle, ele pode criar um sistema em que o designer registrar\u00e1 as condi\u00e7\u00f5es para verificar esses valores. Assim, os dados da \u00e1rvore de decis\u00f5es ficariam assim:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/8e77f7c3410d097e8b7d8e1209355cc6.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNa ess\u00eancia, isso \u00e9 o mesmo que na primeira tabela, mas as solu\u00e7\u00f5es cont\u00eam seu pr\u00f3prio c\u00f3digo, um pouco semelhante \u00e0 parte condicional de um operador if. No lado do c\u00f3digo, isso seria lido na segunda coluna para os n\u00f3s de decis\u00e3o, mas, em vez de procurar uma condi\u00e7\u00e3o espec\u00edfica a ser executada (Is Ball Left Of Paddle), ele avalia a express\u00e3o condicional e retorna verdadeiro ou falso, respectivamente. Isso \u00e9 feito usando a linguagem de script Lua ou Angelscript. Com elas, o desenvolvedor pode usar objetos em seu jogo (bola e paddle) e criar vari\u00e1veis que estar\u00e3o dispon\u00edveis no script (ball.position). Al\u00e9m disso, a linguagem de script \u00e9 mais simples do que C++. Ela n\u00e3o requer um est\u00e1gio completo de compila\u00e7\u00e3o, o que a torna ideal para ajustes r\u00e1pidos na l\u00f3gica do jogo e permite que \"n\u00e3o-programadores\" criem as fun\u00e7\u00f5es necess\u00e1rias por conta pr\u00f3pria.<\/p>\n<p>No exemplo apresentado, a linguagem de script \u00e9 utilizada apenas para avaliar a express\u00e3o condicional, mas tamb\u00e9m pode ser usada para a\u00e7\u00f5es. Por exemplo, os dados Move Paddle Right podem se tornar um operador de script (ball.position.x += 10). Assim, a a\u00e7\u00e3o tamb\u00e9m pode ser definida no script, sem a necessidade de programar Move Paddle Right.<\/p>\n<p>\u00c9 poss\u00edvel ir mais al\u00e9m e escrever completamente a \u00e1rvore de decis\u00f5es em uma linguagem de script. Isso seria c\u00f3digo na forma de operadores condicionais programados de forma r\u00edgida (hardcoded), mas que ficariam em arquivos externos de script, ou seja, poderiam ser modificados sem recompilar todo o programa. Muitas vezes, \u00e9 poss\u00edvel alterar o arquivo de script enquanto o jogo est\u00e1 em andamento, para testar rapidamente diferentes rea\u00e7\u00f5es da IA.<\/p>\n<h3>Reagindo a eventos<\/h3>\n<p>\nOs exemplos acima se encaixam perfeitamente no Pong. Eles continuamente executam o ciclo Sense\/Think\/Act e agem com base no \u00faltimo estado do mundo. Mas em jogos mais complexos, \u00e9 necess\u00e1rio reagir a eventos espec\u00edficos, e n\u00e3o avaliar tudo de uma vez. Nesse caso, Pong j\u00e1 n\u00e3o \u00e9 um bom exemplo. Vamos escolher outro. <\/p>\n<p>Imagine um jogo de tiro, onde os inimigos ficam parados at\u00e9 detectarem o jogador, ent\u00e3o agem de acordo com sua \"especializa\u00e7\u00e3o\": alguns correr\u00e3o para o ataque, outros atacar\u00e3o \u00e0 dist\u00e2ncia. Isso ainda \u00e9 um sistema reativo b\u00e1sico \u2014 \"se o jogador for visto, fa\u00e7a algo\" \u2014 mas pode ser logicamente dividido em evento Player Seen (jogador visto) e rea\u00e7\u00e3o (escolha uma resposta e execute-a).<\/p>\n<p>Isso nos traz de volta ao ciclo Sense\/Think\/Act. Podemos codificar a parte Sense, que a cada quadro verifica se a IA v\u00ea o jogador. Se n\u00e3o, nada acontece, mas se v\u00ea, um evento Player Seen \u00e9 gerado. O c\u00f3digo ter\u00e1 uma se\u00e7\u00e3o separada que diz: \"quando o evento Player Seen ocorre, fa\u00e7a \", onde  \u00e9 a resposta necess\u00e1ria para se referir \u00e0s partes Think e Act. Assim, voc\u00ea configurar\u00e1 as rea\u00e7\u00f5es para o evento Player Seen: para um personagem \"rushando\" \u2014 ChargeAndAttack, e para um sniper \u2014 HideAndSnipe. Essas conex\u00f5es podem ser criadas em um arquivo de dados para edi\u00e7\u00e3o r\u00e1pida sem necessidade de recompilar. Aqui tamb\u00e9m \u00e9 poss\u00edvel usar uma linguagem de script.<\/p>\n<h2>Tomada de decis\u00f5es complexas<\/h2>\n<p>\nEmbora sistemas de rea\u00e7\u00f5es simples sejam muito eficazes, h\u00e1 muitas situa\u00e7\u00f5es em que eles n\u00e3o s\u00e3o suficientes. \u00c0s vezes, \u00e9 necess\u00e1rio tomar decis\u00f5es variadas, com base no que o agente est\u00e1 fazendo no momento, mas representar isso como uma condi\u00e7\u00e3o \u00e9 dif\u00edcil. \u00c0s vezes, existem muitas condi\u00e7\u00f5es para represent\u00e1-las de forma eficaz em uma \u00e1rvore de decis\u00f5es ou script. \u00c0s vezes, \u00e9 necess\u00e1rio avaliar antecipadamente como a situa\u00e7\u00e3o mudar\u00e1 antes de decidir o pr\u00f3ximo passo. Para resolver esses problemas, s\u00e3o necess\u00e1rias abordagens mais complexas.<\/p>\n<h3>M\u00e1quina de estados finitos<\/h3>\n<p>\nUma m\u00e1quina de estados finitos ou FSM (finite state machine) \u00e9 uma forma de dizer que nosso agente est\u00e1 atualmente em um dos v\u00e1rios estados poss\u00edveis e que ele pode transitar de um estado para outro. Existem um n\u00famero definido de tais estados \u2014 da\u00ed o nome. O melhor exemplo da vida real \u00e9 um sem\u00e1foro. Em diferentes locais h\u00e1 diferentes sequ\u00eancias de luzes, mas o princ\u00edpio \u00e9 o mesmo \u2014 cada estado representa algo (pare, siga, etc.). O sem\u00e1foro est\u00e1 em apenas um estado a qualquer momento e transita de um para outro com base em regras simples.<\/p>\n<p>Com NPCs em jogos, a hist\u00f3ria \u00e9 semelhante. Para exemplo, vamos pegar um guarda com os seguintes estados:<\/p>\n<ul>\n<li>Patrulhando (Patrolling).<\/li>\n<li>Atacando (Attacking).<\/li>\n<li>Fugindo (Fleeing).<\/li>\n<\/ul>\n<p>\nE com essas condi\u00e7\u00f5es para mudar seu estado:<\/p>\n<ul>\n<li>Se o guarda v\u00ea um inimigo, ele ataca.<\/li>\n<li>Se o guarda ataca, mas n\u00e3o v\u00ea mais o inimigo, ele volta a patrulhar.<\/li>\n<li>Se o guarda ataca, mas est\u00e1 gravemente ferido, ele foge.<\/li>\n<\/ul>\n<p>\nTamb\u00e9m \u00e9 poss\u00edvel escrever operadores if com uma vari\u00e1vel de estado do guardi\u00e3o e v\u00e1rias verifica\u00e7\u00f5es: se h\u00e1 um inimigo por perto, qual o n\u00edvel de sa\u00fade do NPC, etc. Adicionaremos mais alguns estados:<\/p>\n<ul>\n<li>Inatividade (Idling) \u2014 entre patrulhas.<\/li>\n<li>Busca (Searching) \u2014 quando um inimigo avistado se escondeu.<\/li>\n<li>Pedir ajuda (Finding Help) \u2014 quando um inimigo \u00e9 avistado, mas \u00e9 muito forte para enfrentar sozinho.<\/li>\n<\/ul>\n<p>\nA escolha de cada um \u00e9 limitada \u2014 por exemplo, o guardi\u00e3o n\u00e3o ir\u00e1 procurar um inimigo escondido se tiver pouca sa\u00fade.<\/p>\n<p>No final, uma enorme lista de &quot;se&quot; &lt;x \u0438 y, \u043d\u043e \u043d\u0435 z&gt;, ent&atilde;o &lt;p&gt;&quot;, pode se tornar excessivamente complexa, portanto, devemos formalizar um m&eacute;todo que nos permita manter em mente os estados e as transi&ccedil;&otilde;es entre os estados. Para fazer isso, levaremos em considera&ccedil;&atilde;o todos os estados e, sob cada estado, listaremos todas as transi&ccedil;&otilde;es para outros estados, juntamente com as condi&ccedil;&otilde;es necess&aacute;rias para elas.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/ba4c401aa20de3d22d2478cba5a4b1ec.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEsta \u00e9 uma tabela de transi\u00e7\u00f5es de estados \u2014 uma forma abrangente de representar uma FSM. Vamos desenhar um diagrama para obter uma vis\u00e3o completa de como o comportamento do NPC muda.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/b4182359983cf573872dacc575af13dc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO diagrama reflete a ess\u00eancia da tomada de decis\u00f5es para este agente com base na situa\u00e7\u00e3o atual. Cada seta mostra a transi\u00e7\u00e3o entre estados, se a condi\u00e7\u00e3o ao lado dela for verdadeira.<\/p>\n<p>A cada atualiza\u00e7\u00e3o, verificamos o estado atual do agente, revisamos a lista de transi\u00e7\u00f5es, e se as condi\u00e7\u00f5es para a transi\u00e7\u00e3o forem atendidas, ele assume um novo estado. Por exemplo, a cada quadro verifica-se se o temporizador de 10 segundos expirou e, se sim, o guardi\u00e3o passa do estado Idling para Patrolling. De maneira semelhante, o estado Attacking verifica a sa\u00fade do agente \u2014 se estiver baixa, ele transita para o estado Fleeing.<\/p>\n<p>Essa \u00e9 a manipula\u00e7\u00e3o das transi\u00e7\u00f5es entre estados, mas e quanto ao comportamento relacionado aos pr\u00f3prios estados? Quanto \u00e0 implementa\u00e7\u00e3o do comportamento real para um estado espec\u00edfico, normalmente existem dois tipos de \"gancho\", onde atribuimos a\u00e7\u00f5es \u00e0 FSM:<\/p>\n<ul>\n<li>A\u00e7\u00f5es que realizamos periodicamente para o estado atual.<\/li>\n<li>A\u00e7\u00f5es que tomamos ao transitar de um estado para outro.<\/li>\n<\/ul>\n<p>\nExemplos para o primeiro tipo. O estado Patrolling mover\u00e1 o agente ao longo da rota de patrulha a cada quadro. O estado Attacking tentar\u00e1 iniciar um ataque a cada quadro ou transitar\u00e1 para um estado quando isso for poss\u00edvel.<\/p>\n<p>Para o segundo tipo, consideremos a transi\u00e7\u00e3o \"se o inimigo est\u00e1 vis\u00edvel e o inimigo \u00e9 muito forte, ent\u00e3o entre no estado Finding Help. O agente deve escolher para onde ir em busca de ajuda e manter essa informa\u00e7\u00e3o, para que o estado Finding Help saiba a quem recorrer. Assim que a ajuda for encontrada, o agente retorna ao estado Attacking. Neste momento, ele querr\u00e1 informar seu aliado sobre a amea\u00e7a, portanto, pode ocorrer a a\u00e7\u00e3o NotifyFriendOfThreat.<\/p>\n<p>Mais uma vez, podemos olhar para este sistema atrav\u00e9s do ciclo Sense \/ Think \/ Act. Sense se manifesta nos dados utilizados pela l\u00f3gica de transi\u00e7\u00e3o. Think se refere \u00e0s transi\u00e7\u00f5es dispon\u00edveis em cada estado. E Act \u00e9 realizado pelas a\u00e7\u00f5es que s\u00e3o executadas periodicamente dentro do estado ou nas transi\u00e7\u00f5es entre estados.<\/p>\n<p>\u00c0s vezes, a sondagem cont\u00ednua das condi\u00e7\u00f5es de transi\u00e7\u00e3o pode ser custosa. Por exemplo, se cada agente executar c\u00e1lculos complexos a cada quadro para determinar se v\u00ea inimigos e entender se pode transitar do estado Patrolling para Attacking \u2014 isso consumir\u00e1 muito tempo de CPU. <\/p>\n<p>Mudan\u00e7as significativas no estado do mundo podem ser vistas como eventos que ser\u00e3o processados \u00e0 medida que surgem. Em vez de o FSM verificar a cada quadro a condi\u00e7\u00e3o de transi\u00e7\u00e3o \"meu agente pode ver o jogador?\", pode-se configurar um sistema separado para realizar verifica\u00e7\u00f5es com menos frequ\u00eancia (por exemplo, 5 vezes por segundo). E o resultado seria Player Seen, quando a verifica\u00e7\u00e3o for bem-sucedida. <\/p>\n<p>Isso \u00e9 passado para o FSM, que agora deve transitar para a condi\u00e7\u00e3o de evento Player Seen recebido e reagir de forma apropriada. O comportamento final \u00e9 o mesmo, exceto por um atraso quase impercept\u00edvel antes da resposta. No entanto, o desempenho melhorou devido \u00e0 separa\u00e7\u00e3o de parte do Sense em uma parte distinta do programa.<\/p>\n<h3>M\u00e1quina de estados finitos hier\u00e1rquica<\/h3>\n<p>\nNo entanto, trabalhar com grandes FSMs nem sempre \u00e9 conveniente. Se quisermos expandir o estado de ataque, substituindo-o por MeleeAttacking (luta corpo a corpo) e RangedAttacking (luta \u00e0 dist\u00e2ncia), teremos que alterar as transi\u00e7\u00f5es de todos os outros estados que levam ao estado Attacking (atuais e futuros).<\/p>\n<p>Voc\u00ea certamente percebeu que, em nosso exemplo, h\u00e1 muitas transi\u00e7\u00f5es duplicadas. A maioria das transi\u00e7\u00f5es no estado de Idling \u00e9 id\u00eantica \u00e0s transi\u00e7\u00f5es no estado de Patrolling. Seria bom n\u00e3o haver repeti\u00e7\u00f5es, especialmente se adicionarmos mais estados semelhantes. Faz sentido agrupar Idling e Patrolling sob a etiqueta comum \"n\u00e3o b\u00e9lico\", onde h\u00e1 apenas um conjunto comum de transi\u00e7\u00f5es para estados de combate. Se apresentarmos essa etiqueta como um estado, ent\u00e3o Idling e Patrolling se tornar\u00e3o substados. Exemplo de uso de uma tabela de transi\u00e7\u00f5es separada para o novo substado n\u00e3o b\u00e9lico:<\/p>\n<p><i>Estados principais:<\/i><br \/>\n<img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/d86dd918acbe81b9bf22c2fb34aecee3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<i>Estado fora de combate:<\/i><br \/>\n<img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/9d5bc2053010a32c5f68d7f0192c04ed.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE na forma de diagrama:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/0ccf95ecafa9ce2a6ea5b5b9833ddc4f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEste \u00e9 o mesmo sistema, mas com um novo estado n\u00e3o b\u00e9lico que inclui Idling e Patrolling. Com cada estado contendo FSM com substados (e esses substados, por sua vez, contendo suas pr\u00f3prias FSM \u2014 e assim por diante, quantas voc\u00ea precisar), obtemos M\u00e1quinas de Estado Finais Hier\u00e1rquicas ou HFSM. Agrupando o estado n\u00e3o b\u00e9lico, eliminamos um monte de transi\u00e7\u00f5es redundantes. O mesmo podemos fazer para qualquer novo estado com transi\u00e7\u00f5es comuns. Por exemplo, se no futuro ampliarmos o estado Attacking para os estados MeleeAttacking e MissileAttacking, eles ser\u00e3o substados que transitam entre si com base na dist\u00e2ncia at\u00e9 o inimigo e na disponibilidade de muni\u00e7\u00f5es. No final, modelos de comportamento complexos e submodelos de comportamento podem ser representados com o m\u00ednimo de transi\u00e7\u00f5es duplicadas.<\/p>\n<h3>\u00c1rvore de comportamentos<\/h3>\n<p>\nCom HFSM, complexas combina\u00e7\u00f5es de comportamentos s\u00e3o criadas de maneira simples. No entanto, h\u00e1 uma pequena dificuldade, pois a tomada de decis\u00f5es na forma de regras de transi\u00e7\u00e3o est\u00e1 intimamente relacionada ao estado atual. E em muitos jogos, isso \u00e9 exatamente o que se precisa. Um uso cuidadoso da hierarquia de estados pode reduzir a quantidade de repeti\u00e7\u00f5es nas transi\u00e7\u00f5es. Mas, \u00e0s vezes, s\u00e3o necess\u00e1rias regras que funcionem independentemente do estado em que voc\u00ea est\u00e1 ou que se aplicam em quase qualquer estado. Por exemplo, se a sa\u00fade do agente cair para 25%, voc\u00ea desejar\u00e1 que ele fuja, independentemente de estar em combate, ocioso ou conversando \u2014 voc\u00ea ter\u00e1 que adicionar essa condi\u00e7\u00e3o a cada estado. E se seu designer quiser mais tarde alterar o limite de baixa sa\u00fade de 25% para 10%, precisar\u00e1 lidar com isso novamente.<\/p>\n<p>Idealmente, para essa situa\u00e7\u00e3o, \u00e9 necess\u00e1rio um sistema em que as decis\u00f5es sobre \"que estado manter\" estejam al\u00e9m dos pr\u00f3prios estados, permitindo fazer altera\u00e7\u00f5es em um \u00fanico local sem alterar as condi\u00e7\u00f5es de transi\u00e7\u00e3o. Aqui surgem as \u00e1rvores de comportamento.<\/p>\n<p>Existem v\u00e1rias maneiras de implement\u00e1-las, mas a ess\u00eancia para todas \u00e9 semelhante a uma \u00e1rvore de decis\u00f5es: o algoritmo come\u00e7a com um n\u00f3 \"raiz\" e a \u00e1rvore cont\u00e9m n\u00f3s que representam decis\u00f5es ou a\u00e7\u00f5es. No entanto, h\u00e1 algumas diferen\u00e7as chave:<\/p>\n<ul>\n<li>Agora, os n\u00f3s retornam um dos tr\u00eas valores: Succeeded (se o trabalho foi conclu\u00eddo), Failed (se n\u00e3o \u00e9 poss\u00edvel iniciar) ou Running (se ainda est\u00e1 em execu\u00e7\u00e3o e n\u00e3o h\u00e1 resultado final).<\/li>\n<li>N\u00e3o existem mais n\u00f3s de decis\u00e3o para escolher entre duas alternativas. Em vez disso, temos n\u00f3s Decorator, que possuem um \u00fanico n\u00f3 filho. Se eles Succeed, ent\u00e3o executam seu \u00fanico n\u00f3 filho.<\/li>\n<li>N\u00f3s que executam a\u00e7\u00f5es retornam o valor Running para representar a\u00e7\u00f5es em andamento.<\/li>\n<\/ul>\n<p>\nEsse pequeno conjunto de n\u00f3s pode ser combinado para criar uma grande variedade de modelos de comportamento complexos. Vamos imaginar um HFSM de guardi\u00e3o do exemplo anterior na forma de uma \u00e1rvore de comportamento:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/5eaa5c725e4ada8285f16f95bb206d53.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCom essa estrutura, n\u00e3o deve haver uma transi\u00e7\u00e3o expl\u00edcita dos estados Idling\/Patrolling para o estado Attacking ou qualquer outro. Se o inimigo estiver vis\u00edvel e a sa\u00fade do personagem estiver baixa, a execu\u00e7\u00e3o ser\u00e1 interrompida no n\u00f3 Fleeing, independentemente de qual n\u00f3 ele estava executando anteriormente \u2014 Patrolling, Idling, Attacking ou qualquer outro.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/e1c1dcc2055174aa7cfa846364b1709a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c1rvores de comportamento s\u00e3o complexas \u2014 existem muitas maneiras de constru\u00ed-las, e encontrar a combina\u00e7\u00e3o certa de decoradores e n\u00f3s compostos pode ser desafiador. Tamb\u00e9m surgem quest\u00f5es sobre com que frequ\u00eancia verificar a \u00e1rvore \u2014 queremos passar por cada parte dela ou apenas quando uma das condi\u00e7\u00f5es mudar? Como armazenar o estado relacionado aos n\u00f3s \u2014 como saber se estivemos no estado Idling por 10 segundos ou como descobrir quais n\u00f3s foram executados da \u00faltima vez para lidar corretamente com a sequ\u00eancia?<\/p>\n<p>\u00c9 por isso que existem muitas implementa\u00e7\u00f5es. Por exemplo, em alguns sistemas, n\u00f3s decoradores foram substitu\u00eddos por decoradores embutidos. Eles reavaliam a \u00e1rvore ao alterar as condi\u00e7\u00f5es do decorador, ajudam a conectar n\u00f3s e fornecem atualiza\u00e7\u00f5es peri\u00f3dicas.<\/p>\n<h3>Sistema baseado em utilidade<\/h3>\n<p>\nAlguns jogos t\u00eam v\u00e1rias mec\u00e2nicas diferentes. \u00c9 desej\u00e1vel que todos elas aproveitem as regras de transi\u00e7\u00e3o simples e comuns, mas n\u00e3o necessariamente na forma de uma \u00e1rvore de comportamento completa. Em vez de ter um conjunto claro de escolhas ou uma \u00e1rvore de a\u00e7\u00f5es poss\u00edveis, \u00e9 mais f\u00e1cil explorar todas as a\u00e7\u00f5es e escolher a mais apropriada no momento.<\/p>\n<p>Um sistema baseado em utilidade ajudar\u00e1 exatamente nisso. \u00c9 um sistema onde o agente tem v\u00e1rias a\u00e7\u00f5es e decide qual realizar, com base na utilidade relativa de cada uma. Onde a utilidade \u00e9 uma medida arbitr\u00e1ria de qu\u00e3o importante ou desej\u00e1vel \u00e9 executar essa a\u00e7\u00e3o para o agente. <\/p>\n<p>A utilidade calculada da a\u00e7\u00e3o, com base no estado atual e no ambiente, permite que o agente verifique e escolha o estado alternativo mais adequado a qualquer momento. Isso \u00e9 semelhante a um FSM, exceto que as transi\u00e7\u00f5es s\u00e3o determinadas pela avalia\u00e7\u00e3o de cada estado potencial, incluindo o atual. Note que escolhemos a a\u00e7\u00e3o mais \u00fatil para a transi\u00e7\u00e3o (ou permanecemos, se j\u00e1 a executamos). Para maior diversidade, isso pode ser uma escolha ponderada, mas aleat\u00f3ria, a partir de uma pequena lista.<\/p>\n<p>O sistema atribui um intervalo arbitr\u00e1rio de valores de utilidade \u2014 por exemplo, de 0 (completamente indesejado) a 100 (totalmente desejado). Cada a\u00e7\u00e3o tem uma s\u00e9rie de par\u00e2metros que influenciam o c\u00e1lculo desse valor. Retornando ao nosso exemplo com o guardi\u00e3o:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/085fb2c197bde93d78455d18e63c9c25.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nAs transi\u00e7\u00f5es entre a\u00e7\u00f5es n\u00e3o s\u00e3o amb\u00edguas \u2014 qualquer estado pode seguir qualquer outro. As prioridades das a\u00e7\u00f5es est\u00e3o nos valores de utilidade retornados. Se o inimigo for vis\u00edvel, e esse inimigo for forte, enquanto a sa\u00fade do personagem estiver baixa, tanto Fleeing quanto FindingHelp retornar\u00e3o altos valores n\u00e3o nulos. Neste caso, FindingHelp sempre ter\u00e1 prioridade. Da mesma forma, a\u00e7\u00f5es n\u00e3o combativas nunca retornam mais de 50, ent\u00e3o elas sempre estar\u00e3o abaixo das a\u00e7\u00f5es de combate. Isso deve ser considerado ao criar a\u00e7\u00f5es e calcular sua utilidade.<\/p>\n<p>No nosso exemplo, as a\u00e7\u00f5es retornam ou um valor fixo constante ou um dos dois valores fixos. Um sistema mais realista pressup\u00f5e o retorno de avalia\u00e7\u00f5es de um intervalo cont\u00ednuo de valores. Por exemplo, a a\u00e7\u00e3o Fleeing retorna valores de utilidade mais altos se a sa\u00fade do agente est\u00e1 baixa, enquanto a a\u00e7\u00e3o Attacking retorna valores mais baixos se o inimigo \u00e9 muito forte. Por causa disso, a a\u00e7\u00e3o Fleeing tem prioridade sobre Attacking em qualquer situa\u00e7\u00e3o na qual o agente sente que n\u00e3o tem sa\u00fade suficiente para vencer o oponente. Isso permite ajustar as prioridades das a\u00e7\u00f5es com base em qualquer n\u00famero de crit\u00e9rios, tornando essa abordagem mais flex\u00edvel e vari\u00e1vel do que uma \u00e1rvore de comportamento ou FSM.<\/p>\n<p>Cada a\u00e7\u00e3o tem muitas condi\u00e7\u00f5es para calcular o programa. Elas podem ser escritas em uma linguagem de script ou na forma de uma s\u00e9rie de f\u00f3rmulas matem\u00e1ticas. Em The Sims, que modela a rotina di\u00e1ria do personagem, \u00e9 adicionado um n\u00edvel adicional de c\u00e1lculos \u2014 o agente recebe uma s\u00e9rie de \"motiva\u00e7\u00f5es\" que influenciam as avalia\u00e7\u00f5es de utilidade. Se um personagem est\u00e1 com fome, ao longo do tempo ele ficar\u00e1 ainda mais faminto, e o resultado da a\u00e7\u00e3o EatFood aumentar\u00e1 at\u00e9 que o personagem a execute, reduzindo seu n\u00edvel de fome e retornando o valor de EatFood a zero. <\/p>\n<p>A ideia de escolher a\u00e7\u00f5es com base em um sistema de avalia\u00e7\u00f5es \u00e9 bastante simples, portanto, um sistema baseado em utilidade pode ser usado como parte dos processos de tomada de decis\u00e3o da IA, e n\u00e3o como uma substitui\u00e7\u00e3o completa. Uma \u00e1rvore de decis\u00f5es pode solicitar uma avalia\u00e7\u00e3o da utilidade de dois n\u00f3s filhos e escolher o mais alto. Da mesma forma, uma \u00e1rvore de comportamento pode ter um n\u00f3 composto Utility para avaliar a utilidade das a\u00e7\u00f5es, a fim de decidir qual elemento filho executar.<\/p>\n<h2>Movimenta\u00e7\u00e3o e navega\u00e7\u00e3o<\/h2>\n<p>\nNos exemplos anteriores, temos uma plataforma que movemos para a esquerda ou direita, e um guardi\u00e3o que patrulha ou ataca. Mas como exatamente tratamos o movimento do agente ao longo de um per\u00edodo de tempo? Como estabelecemos a velocidade, como evitamos obst\u00e1culos, e como planejamos a rota se chegar ao destino for mais complicado do que simplesmente mover-se em linha reta? Vamos analisar isso.<\/p>\n<h3>Gerenciamento<\/h3>\n<p>\nNa fase inicial, vamos considerar que cada agente tem um valor de velocidade, que inclui qu\u00e3o r\u00e1pido ele se move e em que dire\u00e7\u00e3o. Isso pode ser medido em metros por segundo, quil\u00f4metros por hora, pixels por segundo, etc. Lembrando do ciclo Sense\/Think\/Act, podemos imaginar que a parte Think escolhe a velocidade, enquanto a parte Act aplica essa velocidade ao agente. Normalmente, em jogos h\u00e1 um sistema f\u00edsico que realiza essa tarefa por voc\u00ea, analisando o valor de velocidade de cada objeto e regulando-o. Portanto, podemos deixar a IA com uma \u00fanica tarefa \u2014 decidir qual deve ser a velocidade do agente. Se sabemos onde o agente deve estar, ent\u00e3o precisamos mov\u00ea-lo na dire\u00e7\u00e3o certa com uma velocidade definida. Uma equa\u00e7\u00e3o muito trivial:<\/p>\n<p><i>desired_travel = destination_position \u2013 agent_position<\/i><\/p>\n<p>Imagine um mundo 2D. O agente est\u00e1 no ponto (-2,-2), o destino em algum lugar ao nordeste no ponto (30, 20), e o caminho necess\u00e1rio para o agente chegar l\u00e1 \u00e9 (32, 22). Suponha que essas posi\u00e7\u00f5es sejam medidas em metros \u2014 se aceitarmos a velocidade do agente como 5 metros por segundo, ent\u00e3o escalaremos nosso vetor de movimenta\u00e7\u00e3o e obteremos uma velocidade de aproximadamente (4.12, 2.83). Com esses par\u00e2metros, o agente chegaria ao destino em quase 8 segundos.<\/p>\n<p>Os valores podem ser recalculados a qualquer momento. Se o agente estava a meio caminho do objetivo, o deslocamento teria sido metade do comprimento, mas como a velocidade m\u00e1xima do agente \u00e9 de 5 m\/s (decidimos isso anteriormente), a velocidade ser\u00e1 a mesma. Isso tamb\u00e9m funciona para alvos em movimento, permitindo que o agente fa\u00e7a pequenos ajustes enquanto eles se deslocam.<\/p>\n<p>Mas queremos mais variabilidade \u2014 por exemplo, aumentar lentamente a velocidade para simular um personagem que se move de um estado parado para a corrida. O mesmo pode ser feito no final antes de parar. Essas caracter\u00edsticas s\u00e3o conhecidas como comportamentos de dire\u00e7\u00e3o, cada uma com nomes espec\u00edficos: Seek (procurar), Flee (fugir), Arrival (chegada), etc. A ideia \u00e9 que for\u00e7as de acelera\u00e7\u00e3o podem ser aplicadas \u00e0 velocidade do agente, com base na compara\u00e7\u00e3o da posi\u00e7\u00e3o do agente e da velocidade atual com o destino, para utilizar diferentes maneiras de se mover em dire\u00e7\u00e3o ao objetivo.<\/p>\n<p>Cada comportamento tem um objetivo um pouco diferente. Seek e Arrival s\u00e3o formas de mover o agente em dire\u00e7\u00e3o ao seu destino. Obstacle Avoidance (evitamento de obst\u00e1culos) e Separation (separa\u00e7\u00e3o) ajustam o movimento do agente para contornar obst\u00e1culos no caminho para o objetivo. Alignment (alinhamento) e Cohesion (coes\u00e3o) mant\u00eam os agentes juntos enquanto se movem. Um n\u00famero qualquer de comportamentos de navega\u00e7\u00e3o pode ser somado para obter um \u00fanico vetor de caminho, levando em conta todos os fatores. Um agente utiliza os comportamentos Arrival, Separation e Obstacle Avoidance para se manter afastado de paredes e outros agentes. Essa abordagem funciona bem em locais abertos, sem muitos detalhes. <\/p>\n<p>Em condi\u00e7\u00f5es mais dif\u00edceis, a combina\u00e7\u00e3o de diferentes comportamentos funciona pior \u2014 por exemplo, o agente pode ficar preso na parede devido ao conflito entre Arrival e Obstacle Avoidance. Portanto, precisamos considerar op\u00e7\u00f5es que sejam mais complexas do que simplesmente somar todos os valores. Uma maneira de fazer isso \u00e9, em vez de somar os resultados de cada comportamento, considerar movimentos em diferentes dire\u00e7\u00f5es e escolher a melhor op\u00e7\u00e3o. <\/p>\n<p>No entanto, em um ambiente complexo com becos sem sa\u00edda e escolha de dire\u00e7\u00e3o, precisaremos de algo ainda mais avan\u00e7ado.<\/p>\n<h3>Busca de caminho<\/h3>\n<p>\nComportamentos de navega\u00e7\u00e3o s\u00e3o excelentes para movimento simples em \u00e1reas abertas (como um campo de futebol ou uma arena), onde ir de A a B \u00e9 um caminho direto com pequenas desvios ao contornar obst\u00e1culos. Para rotas complexas, precisamos de pathfinding (busca de caminho), que \u00e9 uma maneira de explorar o mundo e decidir a rota atrav\u00e9s dele.<\/p>\n<p>A maneira mais simples \u00e9 sobrepor uma grade a cada quadrado ao lado do agente e avaliar em quais deles \u00e9 permitido se mover. Se algum desses quadrados for o destino, ent\u00e3o siga a partir dele pela rota de cada quadrado at\u00e9 o anterior, at\u00e9 chegar ao in\u00edcio. Esse \u00e9 o caminho. Caso contr\u00e1rio, repita o processo com os quadrados mais pr\u00f3ximos at\u00e9 encontrar o destino ou ficar sem quadrados (o que significa que n\u00e3o h\u00e1 rota poss\u00edvel). Isso \u00e9 formalmente conhecido como Breadth-First Search ou BFS (algoritmo de busca em largura). Em cada etapa, ele verifica em todas as dire\u00e7\u00f5es (por isso, breadth, \"largura\"). O espa\u00e7o de busca se assemelha a uma frente de onda que se move at\u00e9 alcan\u00e7ar o local desejado \u2014 a \u00e1rea de busca se expande a cada passo at\u00e9 que o ponto final seja atingido, depois do qual o caminho pode ser rastreado at\u00e9 o in\u00edcio.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/d367e62bc53033b05388538649853a41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nComo resultado, voc\u00ea obter\u00e1 uma lista de quadrados que comp\u00f5em a rota necess\u00e1ria. Este \u00e9 o caminho (da\u00ed, pathfinding) \u2014 uma lista de locais que o agente ir\u00e1 visitar ao seguir para o destino.<\/p>\n<p>Dado que sabemos a posi\u00e7\u00e3o de cada quadrado no mundo, podemos usar comportamentos de dire\u00e7\u00e3o para mover ao longo do caminho \u2014 do n\u00f3 1 para o n\u00f3 2, depois do n\u00f3 2 para o n\u00f3 3 e assim por diante. A maneira mais simples \u00e9 direcionar-se ao centro do pr\u00f3ximo quadrado, mas \u00e9 ainda melhor parar no meio da borda entre o quadrado atual e o pr\u00f3ximo. Isso permite que o agente corte os cantos em curvas acentuadas.<\/p>\n<p>O algoritmo BFS tem desvantagens \u2014 ele explora tantos quadrados na dire\u00e7\u00e3o \"errada\" quanto na dire\u00e7\u00e3o \"certa\". Aqui entra um algoritmo mais complexo chamado A* (A estrela). Ele funciona de forma semelhante, mas em vez de explorar cegamente os quadrados vizinhos (depois os vizinhos dos vizinhos, e assim por diante), ele coleta n\u00f3s em uma lista e os classifica de modo que o pr\u00f3ximo n\u00f3 a ser explorado seja sempre aquele que levar\u00e1 ao caminho mais curto. Os n\u00f3s s\u00e3o classificados com base em uma heur\u00edstica que leva em conta duas coisas \u2014 o \"custo\" hipot\u00e9tico do caminho para o quadrado desejado (incluindo quaisquer custos de movimento) e uma estimativa de qu\u00e3o longe esse quadrado est\u00e1 do destino (direcionando a busca na dire\u00e7\u00e3o certa).<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/1cab4f53fa5af6b31d352c7bcf453d7e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNeste exemplo, o agente explora uma quadr\u00edcula de cada vez, escolhendo sempre o vizinho com maior potencial. O caminho obtido \u00e9 semelhante ao da BFS, mas durante o processo, foram considerados menos quadrados \u2014 o que tem um grande impacto no desempenho do jogo.<\/p>\n<h3>Movimento sem grade<\/h3>\n<p>\nMas a maioria dos jogos n\u00e3o \u00e9 constru\u00edda em uma grade, e muitas vezes n\u00e3o \u00e9 poss\u00edvel faz\u00ea-la sem comprometer o realismo. Compromissos s\u00e3o necess\u00e1rios. Qual deve ser o tamanho dos quadrados? Se forem muito grandes \u2014 n\u00e3o poder\u00e3o representar corretamente corredores ou curvas pequenas; se forem muito pequenos \u2014 haver\u00e1 uma quantidade excessiva de quadrados a serem pesquisados, o que acabar\u00e1 levando muito tempo.<\/p>\n<p>A primeira coisa a entender \u00e9 que a grade nos fornece um grafo de n\u00f3s conectados. Os algoritmos A* e BFS, de fato, operam em gr\u00e1ficos e n\u00e3o se preocupam com a nossa grade. Poder\u00edamos colocar n\u00f3s em qualquer lugar do mundo do jogo: com uma conex\u00e3o entre quaisquer dois n\u00f3s conectados, assim como entre o ponto inicial e o final, e pelo menos um dos n\u00f3s \u2014 o algoritmo funcionar\u00e1 t\u00e3o bem quanto antes. Isso \u00e9 frequentemente chamado de sistema de pontos de passagem, pois cada n\u00f3 representa uma posi\u00e7\u00e3o significativa no mundo que pode ser parte de qualquer n\u00famero de caminhos hipot\u00e9ticos.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/d87e9d4bb2a2fc713d32abc158506eaa.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Exemplo 1: um n\u00f3 em cada quadrado. A busca come\u00e7a no n\u00f3 onde o agente est\u00e1 localizado e termina no n\u00f3 do quadrado desejado.<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/b535a5db805efdc427d7c5724b866982.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Exemplo 2: um conjunto menor de n\u00f3s (pontos de passagem). A busca come\u00e7a no quadrado com o agente, passa pelo n\u00famero necess\u00e1rio de n\u00f3s e, em seguida, continua at\u00e9 o destino.<\/i><\/p>\n<p>Este \u00e9 um sistema bastante flex\u00edvel e poderoso. Mas \u00e9 necess\u00e1rio ter cuidado nas decis\u00f5es sobre onde e como colocar os pontos de passagem, caso contr\u00e1rio, os agentes podem simplesmente n\u00e3o ver o ponto mais pr\u00f3ximo e n\u00e3o conseguir iniciar o caminho. Seria mais f\u00e1cil se pud\u00e9ssemos colocar os pontos de passagem automaticamente com base na geometria do mundo.<\/p>\n<p>Aqui entra a malha de navega\u00e7\u00e3o ou navmesh. Essa \u00e9 tipicamente uma malha 2D de tri\u00e2ngulos que se sobrep\u00f5e \u00e0 geometria do mundo \u2014 em todos os lugares onde o agente \u00e9 permitido andar. Cada um dos tri\u00e2ngulos na malha se torna um n\u00f3 no grafo e tem at\u00e9 tr\u00eas tri\u00e2ngulos adjacentes, que se tornam n\u00f3s vizinhos no grafo. <\/p>\n<p>Esta imagem \u00e9 um exemplo do motor Unity \u2014 ele analisou a geometria do mundo e criou um navmesh (na captura de tela, em azul claro). Cada pol\u00edgono no navmesh \u00e9 uma \u00e1rea onde o agente pode permanecer ou se mover de um pol\u00edgono para outro. No exemplo dado, os pol\u00edgonos s\u00e3o menores que os andares em que est\u00e3o localizados \u2014 isso foi feito para levar em conta as dimens\u00f5es do agente, que podem ultrapassar sua posi\u00e7\u00e3o nominal.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/845705ba7b9a9d469203aedf7942da41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPodemos buscar um caminho atrav\u00e9s dessa grade, utilizando novamente o algoritmo A*. Isso nos dar\u00e1 um caminho praticamente perfeito no mundo, que leva em conta toda a geometria e n\u00e3o requer n\u00f3s extras ou cria\u00e7\u00e3o de pontos de refer\u00eancia.<\/p>\n<p>Pathfinding \u2014 \u00e9 um tema muito abrangente, que n\u00e3o pode ser coberto em apenas uma se\u00e7\u00e3o de um artigo. Se voc\u00ea deseja estud\u00e1-lo mais a fundo, isso pode ser feito atrav\u00e9s do <noindex><a rel=\"nofollow\" href=\"https:\/\/www.redblobgames.com\/pathfinding\/a-star\/introduction.html\">site de Amit Patel.<\/a><\/noindex>.<\/p>\n<h2>Planejamento<\/h2>\n<p>\nN\u00f3s nos certificamos de que, no pathfinding, \u00e0s vezes n\u00e3o basta simplesmente escolher uma dire\u00e7\u00e3o e seguir \u2014 devemos escolher uma rota e fazer algumas curvas para chegar ao local desejado. Podemos generalizar essa ideia: alcan\u00e7ar um objetivo n\u00e3o \u00e9 apenas o pr\u00f3ximo passo, mas uma sequ\u00eancia inteira, onde \u00e0s vezes \u00e9 necess\u00e1rio olhar para frente alguns passos para entender como deve ser o primeiro. Isso se chama planejamento. O pathfinding pode ser visto como um dos v\u00e1rios complementos ao planejamento. Do ponto de vista do nosso ciclo Sense\/Tthink\/Act, \u00e9 aqui que a parte Think planeja v\u00e1rias partes do Act para o futuro.<\/p>\n<p>Vamos analisar com o exemplo do jogo de cartas Magic: The Gathering. N\u00f3s come\u00e7amos com as seguintes cartas na m\u00e3o:<\/p>\n<ul>\n<li>Swamp \u2014 fornece 1 mana preta (carta de terreno).<\/li>\n<li>Forest \u2014 fornece 1 mana verde (carta de terreno).<\/li>\n<li>Fugitive Wizard \u2014 requer 1 mana azul para invocar.<\/li>\n<li>Elvish Mystic \u2014 requer 1 mana verde para invocar.<\/li>\n<\/ul>\n<p>\nIgnoramos as tr\u00eas cartas restantes para simplificar. De acordo com as regras, o jogador pode jogar 1 carta de terreno por turno, ele pode \"tapear\" essa carta para extrair mana e, em seguida, usar feiti\u00e7os (incluindo invocar criaturas) de acordo com a quantidade de mana dispon\u00edvel. Nessa situa\u00e7\u00e3o, o jogador humano sabe que precisa jogar Forest, \"tapear\" 1 mana verde e, em seguida, invocar Elvish Mystic. Mas como o IA do jogo pode adivinhar isso?<\/p>\n<h3>Planejamento simples<\/h3>\n<p>\nUma abordagem trivial \u00e9 testar cada a\u00e7\u00e3o sequencialmente at\u00e9 que nenhuma a\u00e7\u00e3o apropriada permane\u00e7a. Observando as cartas, a IA v\u00ea que pode jogar Swamp. E joga. Existem outras a\u00e7\u00f5es dispon\u00edveis neste turno? Ela n\u00e3o pode convocar nem Elvish Mystic nem Fugitive Wizard, pois ambas requerem, respectivamente, mana verde e azul, enquanto Swamp fornece apenas mana preta. E ela n\u00e3o poder\u00e1 jogar Forest, pois j\u00e1 jogou Swamp. Assim, a IA do jogo seguiu as regras, mas o fez de forma inadequada. Isso pode ser melhorado.<\/p>\n<p>O planejamento pode encontrar uma lista de a\u00e7\u00f5es que levam o jogo ao estado desejado. Assim como cada quadrado no caminho tinha vizinhos (em busca de caminho), cada a\u00e7\u00e3o no plano tamb\u00e9m tem vizinhos ou sucessores. Podemos buscar essas a\u00e7\u00f5es e a\u00e7\u00f5es subsequentes at\u00e9 alcan\u00e7armos o estado desejado.<\/p>\n<p>No nosso exemplo, o resultado desejado \u00e9 'convocar uma criatura, se poss\u00edvel'. No in\u00edcio do turno, vemos apenas duas poss\u00edveis a\u00e7\u00f5es permitidas pelas regras do jogo:<\/p>\n<p><i>1. Jogar Swamp (resultado: Swamp em jogo)<br \/>\n2. Jogar Forest (resultado: Forest em jogo)<\/i><\/p>\n<p>Cada a\u00e7\u00e3o tomada pode levar a outras a\u00e7\u00f5es e bloquear outras, novamente dependendo das regras do jogo. Imagine que jogamos Swamp \u2014 isso remover\u00e1 Swamp como a pr\u00f3xima jogada (j\u00e1 o jogamos), tamb\u00e9m remover\u00e1 Forest (porque segundo as regras, s\u00f3 \u00e9 permitido jogar um card de terreno por turno). Depois disso, a IA adiciona como pr\u00f3ximo passo \u2014 ganhar 1 mana preta, pois n\u00e3o h\u00e1 outras op\u00e7\u00f5es dispon\u00edveis. Se avan\u00e7ar e escolher Tap the Swamp, ganhar\u00e1 1 unidade de mana preta e nada poder\u00e1 fazer com ela.<\/p>\n<p><i>1. Jogar Swamp (resultado: Swamp em jogo)<br \/>\n 1.1 'Tap' Swamp (resultado: Swamp 'tapado', +1 unidade de mana preta)<br \/>\n Nenhuma a\u00e7\u00e3o dispon\u00edvel \u2013 FIM<br \/>\n2. Jogar Forest (resultado: Forest em jogo)<\/i><\/p>\n<p>A lista de a\u00e7\u00f5es acabou sendo curta, chegamos a um impasse. Vamos repetir o processo para a pr\u00f3xima a\u00e7\u00e3o. Jogamos Forest, abrindo a a\u00e7\u00e3o 'ganhar 1 mana verde', que, por sua vez, abrir\u00e1 a terceira a\u00e7\u00e3o \u2014 convocar Elvish Mystic.<\/p>\n<p><i>1. Jogar Swamp (resultado: Swamp em jogo)<br \/>\n 1.1 'Tap' Swamp (resultado: Swamp 'tapado', +1 unidade de mana preta)<br \/>\n Nenhuma a\u00e7\u00e3o dispon\u00edvel \u2013 FIM<br \/>\n2. Jogar Forest (resultado: Forest em jogo)<br \/>\n 2.1 'Tap' Forest (resultado: Forest 'tapada', +1 unidade de mana verde)<br \/>\n 2.1.1 Convocar Elvish Mystic (resultado: Elvish Mystic em jogo, -1 unidade de mana verde)<br \/>\n Nenhuma a\u00e7\u00e3o dispon\u00edvel \u2013 FIM<\/i><\/p>\n<p>Finalmente, examinamos todas as a\u00e7\u00f5es poss\u00edveis e encontramos um plano para convocar uma criatura.<\/p>\n<p>Este \u00e9 um exemplo muito simplificado. \u00c9 prefer\u00edvel escolher o melhor plano poss\u00edvel em vez de apenas qualquer um que atenda a certos crit\u00e9rios. Em geral, os planos potenciais podem ser avaliados com base no resultado final ou no benef\u00edcio total que eles proporcionam. Voc\u00ea pode ganhar 1 ponto por jogar um terreno e 3 pontos por invocar uma criatura. Jogar um Swamp seria um plano que d\u00e1 1 ponto. E jogar um Forest \u2192 Tap the Forest \u2192 invocar um Elvish Mystic \u2014 daria imediatamente 4 pontos. <\/p>\n<p>Assim funciona o planejamento em Magic: The Gathering, mas a mesma l\u00f3gica se aplica a outras situa\u00e7\u00f5es. Por exemplo, mover um pe\u00e3o para liberar espa\u00e7o para o movimento de um bispo no xadrez. Ou se esconder atr\u00e1s de uma parede para atirar com seguran\u00e7a em XCOM. Em geral, voc\u00ea entendeu o ponto.<\/p>\n<h3>Planejamento Avan\u00e7ado<\/h3>\n<p>\n\u00c0s vezes, h\u00e1 muitas a\u00e7\u00f5es potenciais para considerar cada poss\u00edvel op\u00e7\u00e3o. Voltando ao exemplo de Magic: The Gathering: suponha que no jogo voc\u00ea tenha v\u00e1rias cartas de terrenos e criaturas em m\u00e3os \u2014 o n\u00famero de combina\u00e7\u00f5es poss\u00edveis de jogadas pode chegar a dezenas. Existem algumas solu\u00e7\u00f5es para esse problema.<\/p>\n<p>O primeiro m\u00e9todo \u00e9 o backward chaining (forma\u00e7\u00e3o de cadeia reversa). Em vez de percorrer todas as combina\u00e7\u00f5es, \u00e9 melhor come\u00e7ar a partir do resultado final e tentar encontrar um caminho direto. Em vez de ir da raiz da \u00e1rvore a uma folha espec\u00edfica, seguimos na dire\u00e7\u00e3o oposta \u2014 da folha para a raiz. Este m\u00e9todo \u00e9 mais simples e r\u00e1pido.<\/p>\n<p>Se o oponente tem 1 ponto de vida, voc\u00ea pode encontrar um plano \"causar 1 ou mais pontos de dano\". Para conseguir isso, \u00e9 preciso cumprir uma s\u00e9rie de condi\u00e7\u00f5es: <\/p>\n<p>1. O dano pode ser causado por um feiti\u00e7o \u2014 ele deve estar na m\u00e3o.<br \/>\n2. Para jogar o feiti\u00e7o \u2014 \u00e9 necess\u00e1rio mana.<br \/>\n3. Para obter mana \u2014 \u00e9 necess\u00e1rio jogar uma carta de terreno.<br \/>\n4. Para jogar uma carta de terreno \u2014 voc\u00ea precisa t\u00ea-la na m\u00e3o.<\/p>\n<p>Outro m\u00e9todo \u00e9 o best-first search (busca do melhor primeiro). Em vez de percorrer todos os caminhos, escolhemos o mais adequado. Na maioria das vezes, este m\u00e9todo fornece um plano otimizado sem desperd\u00edcio de tempo na busca. A* \u00e9 uma forma de busca do melhor primeiro \u2014 ao explorar as rotas mais promissoras desde o in\u00edcio, ele pode encontrar o melhor caminho sem necessidade de verificar as outras op\u00e7\u00f5es.<\/p>\n<p>Uma op\u00e7\u00e3o interessante e cada vez mais popular de busca best-first \u00e9 a Monte Carlo Tree Search. Em vez de adivinhar quais planos s\u00e3o melhores ao escolher cada a\u00e7\u00e3o subsequente, o algoritmo escolhe sucessores aleat\u00f3rios em cada passo, at\u00e9 atingir o fim (quando o plano leva \u00e0 vit\u00f3ria ou derrota). Ent\u00e3o, o resultado final \u00e9 usado para aumentar ou diminuir a avalia\u00e7\u00e3o do \"peso\" das op\u00e7\u00f5es anteriores. Repetindo esse processo v\u00e1rias vezes, o algoritmo fornece uma boa avalia\u00e7\u00e3o de qual \u00e9 o pr\u00f3ximo passo melhor, mesmo que a situa\u00e7\u00e3o mude (se o oponente tomar medidas para impedir o jogador). <\/p>\n<p>Na narrativa sobre planejamento em jogos, n\u00e3o podemos deixar de mencionar o Goal-Oriented Action Planning ou GOAP (Planejamento de A\u00e7\u00e3o Orientado a Objetivos). Este \u00e9 um m\u00e9todo amplamente utilizado e discutido, mas al\u00e9m de alguns detalhes distintos, \u00e9, essencialmente, um m\u00e9todo de retroceder na cadeia, que j\u00e1 discutimos anteriormente. Se a tarefa \u00e9 \"eliminar o jogador\", e o jogador est\u00e1 atr\u00e1s de uma cobertura, o plano pode ser: elimine com granada \u2192 pegue-a \u2192 lance-a.<\/p>\n<p>Normalmente, existem v\u00e1rios objetivos, cada um com sua prioridade. Se o objetivo de maior prioridade n\u00e3o pode ser alcan\u00e7ado (nenhuma combina\u00e7\u00e3o de a\u00e7\u00f5es cria um plano para \"eliminar o jogador\", pois o jogador n\u00e3o est\u00e1 vis\u00edvel), a IA retornar\u00e1 aos objetivos de menor prioridade.<\/p>\n<h2>Treinamento e adapta\u00e7\u00e3o<\/h2>\n<p>\nJ\u00e1 mencionamos que a IA de jogos geralmente n\u00e3o utiliza aprendizado de m\u00e1quina, porque n\u00e3o \u00e9 adequada para gerenciar agentes em tempo real. Mas isso n\u00e3o significa que n\u00e3o podemos pegar algo dessa \u00e1rea. Queremos um oponente em um atirador que possa nos ensinar algo. Por exemplo, aprender sobre as melhores posi\u00e7\u00f5es no mapa. Ou um oponente em um jogo de luta que bloqueie combos frequentemente usados pelo jogador, incentivando o uso de outros. Assim, o aprendizado de m\u00e1quina pode ser bastante \u00fatil nessas situa\u00e7\u00f5es.<\/p>\n<h3>Estat\u00edsticas e probabilidades<\/h3>\n<p>\nAntes de passarmos para exemplos mais complexos, vamos estimar at\u00e9 onde podemos ir, fazendo algumas medi\u00e7\u00f5es simples e usando-as para tomar decis\u00f5es. Por exemplo, em uma estrat\u00e9gia em tempo real \u2014 como podemos determinar se um jogador consegue iniciar um ataque nos primeiros minutos do jogo e qual defesa devemos preparar contra isso? Podemos estudar a experi\u00eancia passada do jogador para entender qual pode ser sua rea\u00e7\u00e3o futura. Come\u00e7amos com o fato de que n\u00e3o temos esses dados iniciais, mas podemos colet\u00e1-los \u2014 toda vez que a IA joga contra um humano, ela pode registrar o tempo do primeiro ataque. Ap\u00f3s algumas sess\u00f5es, teremos a m\u00e9dia do tempo em que o jogador atacar\u00e1 no futuro.<\/p>\n<p>Os valores m\u00e9dios tamb\u00e9m t\u00eam um problema: se o jogador \u2018rushou\u2019 20 vezes e jogou lentamente outras 20, os valores necess\u00e1rios estar\u00e3o em algum lugar no meio, o que n\u00e3o nos dar\u00e1 informa\u00e7\u00f5es \u00fateis. Uma das solu\u00e7\u00f5es \u00e9 limitar os dados de entrada \u2014 podemos considerar os \u00faltimos 20 casos.<\/p>\n<p>Uma abordagem semelhante \u00e9 usada para avaliar a probabilidade de certas a\u00e7\u00f5es, assumindo que as prefer\u00eancias passadas do jogador ser\u00e3o as mesmas no futuro. Se o jogador nos ataca cinco vezes com uma bola de fogo, duas vezes com um raio e uma vez corpo a corpo, \u00e9 evidente que ele prefere a bola de fogo. Extrapolamos e vemos a probabilidade de uso de diferentes armas: bola de fogo = 62,5%, raio = 25% e corpo a corpo = 12,5%. Nossa IA de jogo precisa se preparar para se defender do fogo.<\/p>\n<p>Outro m\u00e9todo interessante \u00e9 usar o Classificador Naive Bayes para explorar grandes volumes de dados de entrada e classificar a situa\u00e7\u00e3o para que a IA reaja da maneira certa. Os classificadores bayesianos s\u00e3o mais conhecidos por seu uso em filtros de spam de e-mail. Eles analisam palavras, comparam-nas com onde essas palavras apareceram anteriormente (em spam ou n\u00e3o) e tiram conclus\u00f5es sobre os e-mails recebidos. Podemos fazer o mesmo mesmo com uma quantidade menor de dados de entrada. Com base em todas as informa\u00e7\u00f5es \u00fateis que a IA v\u00ea (por exemplo, quais unidades inimigas foram criadas, quais feiti\u00e7os est\u00e3o sendo usados ou quais tecnologias foram pesquisadas) e no resultado final (guerra ou paz, \u2018rushar\u2019 ou se defender etc.) \u2014 escolheremos o comportamento apropriado para a IA.<\/p>\n<p>Todos esses m\u00e9todos de aprendizado s\u00e3o suficientes, mas \u00e9 prefer\u00edvel us\u00e1-los com base em dados de testes. A IA aprender\u00e1 a se adaptar \u00e0s diferentes estrat\u00e9gias utilizadas pelos seus playtesters. Uma IA que se adapta ao jogador ap\u00f3s o lan\u00e7amento pode se tornar previs\u00edvel demais ou, ao contr\u00e1rio, muito dif\u00edcil de vencer.<\/p>\n<h3>Adapta\u00e7\u00e3o com base em valores<\/h3>\n<p>\nConsiderando o conte\u00fado do nosso mundo de jogo e suas regras, podemos alterar o conjunto de valores que influenciam a tomada de decis\u00f5es, em vez de apenas usar os dados de entrada. Fazemos isso:<\/p>\n<ul>\n<li>Deixe a IA coletar dados sobre o estado do mundo e eventos-chave durante o jogo (como mencionado acima).<\/li>\n<li>Vamos alterar alguns valores importantes com base nesses dados.<\/li>\n<li>Implementaremos nossas decis\u00f5es, baseadas no processamento ou avalia\u00e7\u00e3o desses valores.<\/li>\n<\/ul>\n<p>\nPor exemplo, o agente tem v\u00e1rias salas para escolher no mapa de um shooter em primeira pessoa. Cada sala tem seu valor, que determina qu\u00e3o desej\u00e1vel \u00e9 a visita. A IA escolhe aleatoriamente para qual sala ir, com base no valor. Em seguida, o agente se lembra de em qual sala foi morto e diminui seu valor (a probabilidade de voltar l\u00e1). Da mesma forma, na situa\u00e7\u00e3o inversa \u2014 se o agente elimina muitos oponentes, o valor da sala aumenta.<\/p>\n<h3>Modelo de Markov<\/h3>\n<p>\nE se us\u00e1ssemos os dados coletados para fazer previs\u00f5es? Se lembrarmos de cada sala onde vemos o jogador durante um determinado per\u00edodo, podemos prever para qual sala o jogador pode se mover. Monitorando e registrando os movimentos do jogador entre as salas (valores), podemos fazer previs\u00f5es sobre eles.<\/p>\n<p>Vamos considerar tr\u00eas salas: vermelha, verde e azul. E tamb\u00e9m as observa\u00e7\u00f5es que registramos ao assistir \u00e0 sess\u00e3o de jogo:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/6e90a365b72a176c36c9a14213baaafc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nO n\u00famero de observa\u00e7\u00f5es em cada sala \u00e9 quase igual \u2014 ainda n\u00e3o sabemos onde fazer um bom ponto de emboscada. A coleta de estat\u00edsticas tamb\u00e9m \u00e9 dificultada pelo respawn dos jogadores, que aparecem uniformemente pelo mapa. Mas os dados sobre a pr\u00f3xima sala que eles entram ap\u00f3s aparecer no mapa j\u00e1 s\u00e3o \u00fateis.<\/p>\n<p>\u00c9 evidente que a sala verde agrada aos jogadores \u2014 a maioria das pessoas da sala vermelha a escolhe, com 50% delas permanecendo l\u00e1. A sala azul, por outro lado, n\u00e3o \u00e9 popular, quase ningu\u00e9m a frequenta, e quando o faz, n\u00e3o fica muito tempo. <\/p>\n<p>Mas os dados nos dizem algo mais importante \u2014 quando um jogador est\u00e1 na sala azul, a pr\u00f3xima sala na qual provavelmente o veremos ser\u00e1 a vermelha, e n\u00e3o a verde. Apesar de a sala verde ser mais popular que a vermelha, a situa\u00e7\u00e3o muda se o jogador est\u00e1 na azul. O pr\u00f3ximo estado (ou seja, a sala para a qual o jogador ir\u00e1) depende do estado anterior (ou seja, da sala em que o jogador est\u00e1 agora). Devido \u00e0 pesquisa das depend\u00eancias, faremos previs\u00f5es mais precisas do que se simplesmente cont\u00e1ssemos as observa\u00e7\u00f5es de forma independente.<\/p>\n<p>Prever o futuro estado com base nos dados do estado passado \u00e9 chamado de modelo de Markov, e esses exemplos (com salas) s\u00e3o chamados de cadeias de Markov. Como os modelos representam a probabilidade de mudan\u00e7as entre estados consecutivos, eles s\u00e3o visualmente representados como FSM com a probabilidade em cada transi\u00e7\u00e3o. Anteriormente, usamos FSM para representar o estado comportamental em que o agente se encontrava, mas esse conceito se aplica a qualquer estado, independentemente de estar relacionado ao agente ou n\u00e3o. Nesse caso, os estados representam a sala que o agente ocupa:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/edb32dff7a3298b19c3fa4d66f48e9f4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEsta \u00e9 uma maneira simples de representar a probabilidade relativa de mudan\u00e7as de estado, dando ao IA uma certa capacidade de prever o pr\u00f3ximo estado. \u00c9 poss\u00edvel prever alguns passos \u00e0 frente.<\/p>\n<p>Se o jogador est\u00e1 na sala verde, h\u00e1 50% de chance de que ele permane\u00e7a l\u00e1 na pr\u00f3xima observa\u00e7\u00e3o. Mas qual \u00e9 a probabilidade de ele ainda estar l\u00e1 mesmo depois? N\u00e3o h\u00e1 apenas a chance de que o jogador permaneceu na sala verde ap\u00f3s duas observa\u00e7\u00f5es, mas tamb\u00e9m a chance de que ele saiu e voltou. Aqui est\u00e1 uma nova tabela considerando os novos dados:<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/f87afff68b066a879661e37f68654ae2.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nA partir dela, vemos que a chance de ver o jogador na sala verde ap\u00f3s duas observa\u00e7\u00f5es ser\u00e1 de 51% \u2014 21% de que ele venha da sala vermelha, 5% de que o jogador visitar\u00e1 a sala azul entre elas, e 25% de que o jogador n\u00e3o sair\u00e1 da sala verde.<\/p>\n<p>A tabela \u00e9 uma ferramenta visual simples \u2014 o procedimento requer apenas multiplica\u00e7\u00e3o de probabilidades em cada passo. Isso significa que voc\u00ea pode olhar longe para o futuro com uma ressalva: assumimos que a chance de entrar em uma sala depende totalmente da sala atual. Isso \u00e9 chamado de propriedade de Markov \u2014 o estado futuro depende apenas do presente. Mas isso n\u00e3o \u00e9 100% preciso. Os jogadores podem mudar suas decis\u00f5es com base em outros fatores: n\u00edveis de sa\u00fade ou quantidade de muni\u00e7\u00e3o. Como n\u00e3o fixamos esses valores, nossas previs\u00f5es ser\u00e3o menos precisas.<\/p>\n<h3>N-Gramas<\/h3>\n<p>\nE quanto ao exemplo com uma luta e a previs\u00e3o de combos do jogador? A mesma coisa! Mas em vez de um \u00fanico estado ou evento, vamos explorar sequ\u00eancias inteiras que comp\u00f5em o golpe do combo.<\/p>\n<p>Uma forma de fazer isso \u00e9 armazenar cada entrada (como Chute, Soco ou Bloqueio) em um buffer e registrar todo o buffer como um evento. Assim, o jogador aperta repetidamente Chute, Chute, Soco para usar o ataque SuperDeathFist, e o sistema de IA armazena todas as entradas no buffer e lembra as \u00faltimas tr\u00eas, utilizadas em cada passo.<\/p>\n<p><img decoding=\"async\" alt=\"Como criar uma IA para jogos: guia para iniciantes\" src=\"\/wp-content\/uploads\/2019\/11\/9a95226ae155dca5e45a66d4440f3cd4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n(Os trechos em negrito s\u00e3o as linhas quando o jogador inicia o ataque SuperDeathFist.)<\/p>\n<p>A IA ver\u00e1 todas as op\u00e7\u00f5es quando o jogador escolher Chute, seguido de outro Chute, e depois notar\u00e1 que a pr\u00f3xima entrada \u00e9 sempre um Soco. Isso permitir\u00e1 que o agente preveja o combo SuperDeathFist e o bloqueie, se poss\u00edvel.<\/p>\n<p>Essas sequ\u00eancias de eventos s\u00e3o chamadas de N-gramas, onde N \u00e9 o n\u00famero de elementos armazenados. No exemplo anterior, era um 3-grama (trigrama), o que significa: as duas primeiras entradas s\u00e3o usadas para prever a terceira. Assim, em um 5-grama, as quatro primeiras entradas preveem a quinta e assim por diante.<\/p>\n<p>O desenvolvedor precisa escolher cuidadosamente o tamanho do N-grama. Um n\u00famero menor de N requer menos mem\u00f3ria, mas armazena uma hist\u00f3ria menor. Por exemplo, um 2-grama (bigram) registrar\u00e1 Chute, Chute ou Chute, Soco, mas n\u00e3o conseguir\u00e1 armazenar Chute, Chute, Soco, portanto a IA n\u00e3o reagir\u00e1 ao combo SuperDeathFist.<\/p>\n<p>Por outro lado, n\u00fameros maiores exigem mais mem\u00f3ria e a IA ter\u00e1 mais dificuldade em aprender, uma vez que haver\u00e1 muito mais op\u00e7\u00f5es poss\u00edveis. Se voc\u00ea tinha tr\u00eas entradas poss\u00edveis: Chute, Soco ou Bloqueio, e us\u00e1ssemos um 10-grama, ter\u00edamos cerca de 60 mil variantes diferentes.<\/p>\n<p>O modelo de bigramas \u00e9 uma cadeia de Markov simples \u2014 cada par \"estado anterior\/estado atual\" \u00e9 um bigrama, e voc\u00ea pode prever o segundo estado com base no primeiro. Trigramas e n-gramas maiores tamb\u00e9m podem ser vistos como cadeias de Markov, onde todos os elementos (exceto o \u00faltimo no n-grama) formam juntos o primeiro estado, e o \u00faltimo elemento \u00e9 o segundo. Um exemplo com luta mostra a chance de transi\u00e7\u00e3o do estado Kick e Kick para o estado Kick e Punch. Ao considerar v\u00e1rias entradas do hist\u00f3rico como uma unidade, estamos essencialmente transformando a sequ\u00eancia de entrada em parte de um estado inteiro. Isso nos d\u00e1 a propriedade de Markov, permitindo o uso de cadeias de Markov para prever a pr\u00f3xima entrada e adivinhar qual golpe de combo ser\u00e1 o pr\u00f3ximo.<\/p>\n<h2>Conclus\u00e3o<\/h2>\n<p>\nDiscutimos as ferramentas e abordagens mais comuns no desenvolvimento de intelig\u00eancia artificial. Tamb\u00e9m analisamos as situa\u00e7\u00f5es em que elas devem ser aplicadas e onde s\u00e3o particularmente \u00fateis. <\/p>\n<p>Isso deve ser suficiente para entender os conceitos b\u00e1sicos da IA em jogos. Mas, claro, est\u00e1 longe de ser todos os m\u00e9todos. Menos populares, mas igualmente eficazes, incluem:<\/p>\n<ul>\n<li>algoritmos de otimiza\u00e7\u00e3o, incluindo subida de colinas, descida de gradiente e algoritmos gen\u00e9ticos<\/li>\n<li>algoritmos de busca\/planejamento competitivos (minimax e poda alpha-beta)<\/li>\n<li>m\u00e9todos de classifica\u00e7\u00e3o (perceptrons, redes neurais e m\u00e1quinas de vetores de suporte)<\/li>\n<li>sistemas para processamento de percep\u00e7\u00e3o e mem\u00f3ria de agentes<\/li>\n<li>abordagens arquitet\u00f4nicas para IA (sistemas h\u00edbridos, subconjuntos de arquiteturas e outras maneiras de sobrepor sistemas de IA)<\/li>\n<li>ferramentas de anima\u00e7\u00e3o (planejamento e coordena\u00e7\u00e3o de movimento)<\/li>\n<li>fatores de desempenho (n\u00edvel de detalhe, algoritmos anytime e timeslicing)<\/li>\n<\/ul>\n<p>\nRecursos online sobre o assunto:<\/p>\n<p>1. No GameDev.net, existe <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/articles\/programming\/artificial-intelligence\/\">uma se\u00e7\u00e3o com artigos e tutoriais sobre IA<\/a><\/noindex>, al\u00e9m de <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/forums\/forum\/6-artificial-intelligence\/\">f\u00f3rum<\/a><\/noindex>.<br \/>\n2. <noindex><a rel=\"nofollow\" href=\"http:\/\/aigamedev.com\/\">AiGameDev.com<\/a><\/noindex> cont\u00e9m uma variedade de apresenta\u00e7\u00f5es e artigos sobre uma ampla gama de temas relacionados ao desenvolvimento de IA em jogos.<br \/>\n3. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gdcvault.com\/\">O GDC Vault<\/a><\/noindex> inclui t\u00f3picos da c\u00fapula GDC AI, muitos dos quais est\u00e3o dispon\u00edveis gratuitamente.<br \/>\n4. Materiais \u00fateis tamb\u00e9m podem ser encontrados no site <noindex><a rel=\"nofollow\" href=\"http:\/\/gameai.com\/\">AI Game Programmers Guild<\/a><\/noindex>.<br \/>\n5. Tommy Thompson, pesquisador de IA e desenvolvedor de jogos, cria v\u00eddeos no canal do YouTube <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/tthompso\">AI and Games<\/a><\/noindex> com explica\u00e7\u00f5es e estudos sobre IA em jogos comerciais.<\/p>\n<p>Livros sobre o tema:<\/p>\n<p>1. A s\u00e9rie de livros Game AI Pro consiste em colet\u00e2neas de artigos curtos que explicam como implementar fun\u00e7\u00f5es espec\u00edficas ou como resolver problemas concretos.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/go.gamedev.net\/?id=13722X707581&amp;xs=1&amp;isjs=1&amp;url=https%3A%2F%2Famzn.to%2F2KGoB8n&amp;xguid=f8ad586e5984991508efff4754027dbd&amp;xuuid=305451ecead59d76ca830fded0aab276&amp;xsessid=6ccb8b9fa3f10b478b65f7ed703a447b&amp;xcreo=0&amp;xed=0&amp;sref=https%3A%2F%2Fwww.gamedev.net%2Farticles%2Fprogramming%2Fartificial-intelligence%2Fthe-total-beginners-guide-to-game-ai-r4942%2F%3Fdo%3Dedit%26d%3D1%26id%3D4942%26csrfKey%3D7015c6d2c5c643e87baa74f8e5d2c094&amp;pref=https%3A%2F%2Fwww.gamedev.net%2Farticles%2Fprogramming%2Fartificial-intelligence%2Fthe-total-beginners-guide-to-game-ai-r4942%2F&amp;xtz=420&amp;jv=13.7.1&amp;bv=2.5.1\">Game AI Pro: Sabedoria Coletada de Profissionais de IA de Jogos<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"http:\/\/go.gamedev.net\/?id=13722X707581&amp;xs=1&amp;isjs=1&amp;url=https%3A%2F%2Famzn.to%2F2KFKyoe&amp;xguid=f8ad586e5984991508efff4754027dbd&amp;xuuid=305451ecead59d76ca830fded0aab276&amp;xsessid=6ccb8b9fa3f10b478b65f7ed703a447b&amp;xcreo=0&amp;xed=0&amp;sref=https%3A%2F%2Fwww.gamedev.net%2Farticles%2Fprogramming%2Fartificial-intelligence%2Fthe-total-beginners-guide-to-game-ai-r4942%2F%3Fdo%3Dedit%26d%3D1%26id%3D4942%26csrfKey%3D7015c6d2c5c643e87baa74f8e5d2c094&amp;pref=https%3A%2F%2Fwww.gamedev.net%2Farticles%2Fprogramming%2Fartificial-intelligence%2Fthe-total-beginners-guide-to-game-ai-r4942%2F&amp;xtz=420&amp;jv=13.7.1&amp;bv=2.5.1\">Game AI Pro 2: Sabedoria Coletada de Profissionais de IA de Jogos<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2KF4irS\">Game AI Pro 3: Sabedoria Coletada de Profissionais de IA de Jogos<\/a><\/noindex><\/p>\n<p>2. A s\u00e9rie AI Game Programming Wisdom \u00e9 a predecessora da s\u00e9rie Game AI Pro. Ela cont\u00e9m m\u00e9todos mais antigos, mas quase todos ainda s\u00e3o relevantes hoje.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2ARFhKx\">AI Game Programming Wisdom 1<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2Mkv4eh\">AI Game Programming Wisdom 2<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2nnuYEh\">AI Game Programming Wisdom 3<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2ARFEEV\">AI Game Programming Wisdom 4<\/a><\/noindex><\/p>\n<p>3. <noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2AWKuRh\">Intelig\u00eancia Artificial: Uma Abordagem Moderna<\/a><\/noindex> \u2014 \u00e9 um dos textos fundamentais para todos que desejam entender a \u00e1rea geral de intelig\u00eancia artificial. Este livro n\u00e3o \u00e9 sobre desenvolvimento de jogos \u2014 ele ensina os fundamentos b\u00e1sicos de IA.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/pixonic\/blog\/428892\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043e\u0431 \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0435 \u0432 \u0438\u0433\u0440\u0430\u0445. \u0421 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0432\u0435\u0449\u0435\u0439 \u043f\u0440\u043e \u0418\u0418 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445, \u0430 \u0435\u0449\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0435\u0433\u043e \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041a\u0430\u043a, \u0433\u0434\u0435 \u0438 \u043a\u043e\u0433\u0434\u0430 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u2014 \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u043f\u0441\u0435\u0432\u0434\u043e\u043a\u043e\u0434\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c 35 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-52118","post","type-post","status-publish","format-standard","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043e\u0431.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0418\u0418: \u0433\u0430\u0439\u0434 \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043e\u0431.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T10:59:47+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Como criar uma IA para jogos: guia para iniciantes | ProHoster","description":"Encontrei um material interessante sobre.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0418\u0418: \u0433\u0430\u0439\u0434 \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 | ProHoster","og:description":"\u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043e\u0431.","og:url":"https:\/\/prohoster.info\/pt\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T21:00:00+00:00","article:modified_time":"2020-02-18T10:59:47+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52118","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 02:32:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:49:49","updated":"2026-01-24 02:32:21","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/52118","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=52118"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/52118\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=52118"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=52118"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=52118"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}