{"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\/it\/blog\/novosti-interneta\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","title":{"rendered":"Come creare un'IA di gioco: guida per principianti","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/9e57175b233a104e0df98383b374eded.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nHo trovato un materiale interessante sull'intelligenza artificiale nei giochi. Spiega le basi dell'IA con esempi semplici e include molti strumenti e metodi utili per la sua comodit\u00e0 nello sviluppo e nella progettazione. Anche informazioni su dove, come e quando usarli sono disponibili.<\/p>\n<p>La maggior parte degli esempi \u00e8 scritta in pseudocodice, quindi non servono conoscenze approfondite di programmazione. Sotto ci sono 35 pagine di testo con immagini e gif, quindi preparati.<\/p>\n<p>UPD. Mi scuso, ma ho gi\u00e0 fatto una mia traduzione di questo articolo su Habr <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/PatientZero\/\">PatientZero<\/a><\/noindex>. Puoi leggere la sua versione <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/420219\/\">qui<\/a><\/noindex>, ma per qualche motivo l'articolo \u00e8 passato inosservato (ho usato la ricerca, ma qualcosa \u00e8 andato storto). E poich\u00e9 scrivo in un blog dedicato allo sviluppo di giochi, ho deciso di lasciare la mia variante di traduzione per gli iscritti (alcuni punti sono formulati diversamente, altri sono intenzionalmente omessi su consiglio degli sviluppatori).<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Che cos'\u00e8 l'IA?<\/h2>\n<p>\nL'IA di gioco si concentra su quali azioni un oggetto deve compiere in base alle condizioni in cui si trova. Di solito, questo viene chiamato gestione di \"agenti intelligenti\", dove l'agente pu\u00f2 essere un personaggio di gioco, un veicolo, un bot, e a volte anche qualcosa di pi\u00f9 astratto: un'intera squadra di entit\u00e0 o addirittura una civilt\u00e0. In ogni caso, si tratta di qualcosa che deve percepire l'ambiente circostante, prendere decisioni sulla base di esso e agire di conseguenza. Questo \u00e8 chiamato ciclo Sense\/Think\/Act (Percepire\/Pensare\/Agire):<\/p>\n<ul>\n<li>Sense: l'agente trova o riceve informazioni sulle cose nel suo ambiente che possono influenzare il suo comportamento (minacce vicine, oggetti da raccogliere, luoghi interessanti da esplorare).<\/li>\n<li>Think: l'agente decide come reagire (valuta se sia sicuro raccogliere oggetti o se debba combattere\/nascostarsi prima).<\/li>\n<li>Act: l'agente compie azioni per attuare la decisione precedente (inizia a muoversi verso il nemico o l'oggetto).<\/li>\n<li>\u2026ora la situazione \u00e8 cambiata a causa delle azioni dei personaggi, quindi il ciclo si ripete con nuovi dati.<\/li>\n<\/ul>\n<p>\nL'IA si concentra generalmente sulla fase Sense del ciclo. Ad esempio, le auto autonome scattano foto della strada, le combinano con i dati del radar e del lidar, e le interpretano. Di solito, questo viene fatto tramite l'apprendimento automatico, che elabora i dati in entrata e assegna loro un significato, estraendo informazioni semantiche come \u00abc'\u00e8 un'altra auto a 20 iarde davanti a te\u00bb. Questi sono noti come problemi di classificazione.<\/p>\n<p>I giochi non hanno bisogno di un sistema complesso per estrarre informazioni, poich\u00e9 gran parte dei dati fa gi\u00e0 parte integrante del gioco. Non \u00e8 necessario eseguire algoritmi di riconoscimento delle immagini per stabilire se c'\u00e8 un nemico davanti: il gioco lo sa gi\u00e0 e comunica queste informazioni direttamente nel processo decisionale. Pertanto, la fase Sense del ciclo \u00e8 spesso molto pi\u00f9 semplice rispetto a Think e Act.<\/p>\n<h2>Limitazioni dell'IA di gioco<\/h2>\n<p>\nL'IA presenta una serie di limitazioni che devono essere rispettate:<\/p>\n<ul>\n<li>L'IA non deve essere addestrata in anticipo, come un algoritmo di apprendimento automatico. \u00c8 inutile scrivere una rete neurale durante lo sviluppo per osservare decine di migliaia di giocatori e studiare il miglior modo di giocare contro di loro. Perch\u00e9? Perch\u00e9 il gioco non \u00e8 stato rilasciato e non ci sono giocatori.<\/li>\n<li>Il gioco deve intrattenere e sfidare, quindi gli agenti non dovrebbero trovare l'approccio migliore contro gli esseri umani.<\/li>\n<li>Gli agenti devono apparire realistici affinch\u00e9 i giocatori si sentano come se stessero giocando contro persone reali. Il programma AlphaGo ha superato l'umano, ma le mosse selezionate erano molto lontane dalla tradizionale comprensione del gioco. Se il gioco simula un avversario umano, non dovrebbe esserci questa sensazione. L'algoritmo deve essere modificato affinch\u00e9 prenda decisioni plausibili, anzich\u00e9 perfette.<\/li>\n<li>L'IA deve funzionare in tempo reale. Questo significa che l'algoritmo non pu\u00f2 monopolizzare l'uso del processore per un lungo periodo durante la presa di decisioni. Anche 10 millisecondi per questo sono troppo lunghi, perch\u00e9 la maggior parte dei giochi richiede da 16 a 33 millisecondi per completare tutta l'elaborazione e procedere al fotogramma successivo.<\/li>\n<li>\u00c8 ideale se almeno una parte del sistema \u00e8 controllata dai dati, affinch\u00e9 i \"non programmatori\" possano apportare modifiche e affinch\u00e9 le correzioni avvengano pi\u00f9 rapidamente.<\/li>\n<\/ul>\n<p>\nConsideriamo gli approcci dell'IA che coprono l'intero ciclo Sense\/Think\/Act.<\/p>\n<h3>Prendere decisioni di base<\/h3>\n<p>\nIniziamo con un gioco semplice: Pong. L'obiettivo \u00e8 spostare la piattaforma (paddle) in modo che la pallina rimbalzi su di essa e non passi oltre. \u00c8 come il tennis, dove perdi se non colpisci la pallina. Qui l'IA ha compiti relativamente facili: deve decidere in quale direzione spostare la piattaforma.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/e1935d657b9f090bf60c365c21e8f92b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Operatori condizionali<\/h3>\n<p>\nPer l'IA in Pong, c'\u00e8 una soluzione ovvia: cercare sempre di posizionare la piattaforma sotto la pallina.<\/p>\n<p>Un algoritmo semplice per fare questo, scritto in pseudocodice:<\/p>\n<p><i>ogni frame\/aggiornamento mentre il gioco \u00e8 in esecuzione:<br \/>\nse la pallina \u00e8 a sinistra della piattaforma:<br \/>\n muovi la piattaforma a sinistra<br \/>\naltrimenti se la pallina \u00e8 a destra della piattaforma:<br \/>\n muovi la piattaforma a destra<\/i><\/p>\n<p>Se la piattaforma si muove alla stessa velocit\u00e0 della pallina, questo \u00e8 l'algoritmo ideale per l'IA in Pong. Non c'\u00e8 bisogno di complicare le cose se i dati e le possibili azioni per l'agente non sono molti.<\/p>\n<p>Questo approccio \u00e8 cos\u00ec semplice che l'intero ciclo Sense\/Think\/Act \u00e8 appena percepibile. Ma \u00e8 presente:<\/p>\n<ul>\n<li>La parte Sense si trova in due operatori if. Il gioco conosce la posizione della pallina e della piattaforma, quindi l'IA fa riferimento a queste informazioni. <\/li>\n<li>La parte Think comprende anche due operatori if. Questi rappresentano due soluzioni che, in questo caso, sono mutuamente esclusive. Di conseguenza, viene scelta una tra tre azioni: spostare la piattaforma a sinistra, spostarla a destra o non fare nulla se \u00e8 gi\u00e0 posizionata correttamente.<\/li>\n<li>La parte Act si trova negli operatori Move Paddle Left e Move Paddle Right. A seconda del design del gioco, questi possono spostare la piattaforma istantaneamente o a una certa velocit\u00e0. <\/li>\n<\/ul>\n<p>\nQuesti approcci vengono chiamati reattivi: ci sono un insieme semplice di regole (in questo caso gli operatori if nel codice) che reagiscono allo stato attuale del mondo e agiscono.<\/p>\n<h3>Albero delle decisioni<\/h3>\n<p>\nL'esempio del gioco Pong corrisponde effettivamente al concetto formale di AI chiamato albero delle decisioni. L'algoritmo lo percorre per raggiungere una \"foglia\" \u2014 una decisione su quale azione intraprendere.<\/p>\n<p>Creiamo un diagramma di flusso dell'albero delle decisioni per l'algoritmo della nostra piattaforma:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/d3b7290ba93144967cd849416cd5eef3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOgni parte dell'albero \u00e8 chiamata nodo \u2014 l'AI utilizza la teoria dei grafi per descrivere strutture simili. Ci sono due tipi di nodi:<\/p>\n<ul>\n<li>Nodi decisionali: scelta tra due alternative basata sul controllo di una certa condizione, dove ogni alternativa \u00e8 rappresentata come un nodo separato.<\/li>\n<li>Nodi terminali: azione da eseguire, che rappresenta una decisione finale.<\/li>\n<\/ul>\n<p>\nL'algoritmo inizia con il primo nodo (il \"radice\" dell'albero). Esso decide se passare a un nodo figlio o eseguire l'azione memorizzata nel nodo e termina.<\/p>\n<p>Qual \u00e8 quindi il vantaggio, se l'albero delle decisioni esegue lo stesso lavoro degli operatori if nella sezione precedente? Qui c'\u00e8 un sistema generale, dove ogni decisione ha solo una condizione e due possibili risultati. Questo consente allo sviluppatore di creare IA dai dati che rappresentano decisioni nell'albero, evitando il loro hardcoding. Immaginiamolo in forma di tabella:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/6875293a60ff9d0efa26fb5e1aa4b21c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDal lato del codice, avrai un sistema per la lettura delle stringhe. Crea un nodo per ognuna di esse, collega la logica decisionale basata sulla seconda colonna e i nodi figli basati sulla terza e quarta colonna. Dovrai ancora programmare le condizioni e le azioni, ma ora la struttura del gioco sar\u00e0 pi\u00f9 complessa. Aggiungi ulteriori decisioni e azioni, e poi configura l'intera IA semplicemente modificando il file di testo che definisce l'albero. Poi, trasferisci il file al game designer, che potr\u00e0 modificare il comportamento senza ricompilare il gioco e modificare il codice.<\/p>\n<p>Gli alberi decisionali sono molto utili quando vengono costruiti automaticamente sulla base di un ampio insieme di esempi (ad esempio, utilizzando l'algoritmo ID3). Questo li rende uno strumento efficace e ad alte prestazioni per la classificazione delle situazioni in base ai dati ricevuti. Tuttavia, andiamo oltre un semplice sistema per decidere le azioni degli agenti.<\/p>\n<h3>Scenari<\/h3>\n<p>\nAbbiamo esaminato un sistema ad albero decisionale che utilizzava condizioni e azioni predefinite. La persona che progetta l'intelligenza artificiale pu\u00f2 organizzare l'albero come desidera, ma deve comunque dipendere da un programmatore che lo ha codificato. E se potessimo dare al designer strumenti per creare le proprie condizioni o azioni?<\/p>\n<p>Per evitare che il programmatore debba scrivere codice per le condizioni Is Ball Left Of Paddle e Is Ball Right Of Paddle, potrebbe realizzare un sistema in cui il designer registra le condizioni per controllare questi valori. Allora i dati dell'albero decisionale appariranno in questo modo:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/8e77f7c3410d097e8b7d8e1209355cc6.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn sostanza, \u00e8 la stessa cosa della prima tabella, ma le soluzioni al suo interno hanno un proprio codice, simile alla parte condizionale di un'istruzione if. Dal lato del codice, questo verrebbe letto nella seconda colonna per i nodi decisionali, ma invece di cercare una condizione specifica da eseguire (Is Ball Left Of Paddle), valuta l'espressione condizionale e restituisce true o false di conseguenza. Questo avviene utilizzando il linguaggio di scripting Lua o Angelscript. Con questi, lo sviluppatore pu\u00f2 gestire oggetti nel suo gioco (ball e paddle) e creare variabili che saranno disponibili nello script (ball.position). Inoltre, il linguaggio di scripting \u00e8 pi\u00f9 semplice del C++. Non richiede una fase di compilazione completa, rendendolo ideale per modifiche rapide alla logica di gioco e permettendo ai 'non programmatori' di creare le funzioni necessarie.<\/p>\n<p>Nell'esempio fornito, il linguaggio di scripting viene utilizzato solo per valutare l'espressione condizionale, ma pu\u00f2 essere usato anche per le azioni. Ad esempio, i dati Move Paddle Right possono diventare un'istruzione di script (ball.position.x += 10). In questo modo, l'azione \u00e8 definita anche nello script, senza la necessit\u00e0 di programmare Move Paddle Right.<\/p>\n<p>\u00c8 possibile andare oltre e scrivere completamente un albero delle decisioni in un linguaggio di scripting. Si tratter\u00e0 di codice sotto forma di operatori condizionali hardcoded, ma saranno contenuti in file esterni di script, quindi possono essere modificati senza ricompilare l'intero programma. Spesso \u00e8 possibile modificare il file dello script direttamente durante il gioco per testare rapidamente diverse reazioni dell'IA.<\/p>\n<h3>Reazione agli eventi<\/h3>\n<p>\nGli esempi sopra si applicano perfettamente a Pong. Eseguono continuamente il ciclo Sense\/Think\/Act e agiscono in base all'ultimo stato del mondo. Ma nei giochi pi\u00f9 complessi \u00e8 necessario reagire a eventi singoli, piuttosto che valutare tutto e subito. In questo caso, Pong non \u00e8 un buon esempio. Scegliamo un altro. <\/p>\n<p>Immagina uno sparatutto dove i nemici rimangono fermi finch\u00e9 non vedono il giocatore, dopodich\u00e9 agiscono in base alla loro \"specializzazione\": qualcuno correr\u00e0 per attaccare, qualcun altro attaccher\u00e0 da lontano. Questo \u00e8 ancora un sistema reattivo di base \u2014 \"se il giocatore \u00e8 visto, fai qualcosa\" \u2014 ma pu\u00f2 essere logicamente diviso in evento Player Seen (giocatore visto) e reazione (scegli una risposta e eseguila).<\/p>\n<p>Questo ci riporta al ciclo Sense\/Think\/Act. Possiamo codificare la parte Sense, che ogni fotogramma verificher\u00e0 se l'IA vede il giocatore. Se non lo vede, non succede nulla, ma se lo vede, viene generato un evento Player Seen. Il codice avr\u00e0 una sezione separata che dir\u00e0: \"quando si verifica l'evento Player Seen, fa \", dove  \u00e8 la risposta necessaria per accedere alle parti Think e Act. In questo modo, puoi impostare le reazioni all'evento Player Seen: per un personaggio che avanza - ChargeAndAttack, e per un cecchino - HideAndSnipe. Questi legami possono essere creati in un file di dati per una rapida modifica senza la necessit\u00e0 di ricompilare. E qui puoi utilizzare anche un linguaggio di scripting.<\/p>\n<h2>Prendere decisioni complesse<\/h2>\n<p>\nSebbene i semplici sistemi di reazione siano molto efficaci, ci sono molte situazioni in cui non sono sufficienti. A volte \u00e8 necessario prendere decisioni diverse in base a ci\u00f2 che l'agente sta facendo in quel momento, ma rappresentare questo come una condizione \u00e8 difficile. A volte ci sono troppe condizioni da rappresentare in modo efficace in un albero decisionale o in uno script. Occasionalmente, \u00e8 necessario valutare in anticipo come cambier\u00e0 la situazione prima di decidere quale sar\u00e0 il passo successivo. Per affrontare questi problemi sono necessarie soluzioni pi\u00f9 complesse.<\/p>\n<h3>Macchina a stati finiti<\/h3>\n<p>\nLa macchina a stati finiti, o FSM (Finite State Machine) \u00e8 un modo per indicare che il nostro agente si trova attualmente in uno di diversi stati possibili e che pu\u00f2 passare da uno stato all'altro. Gli stati sono un numero definito\u2014da qui il nome. Il miglior esempio nella vita reale \u00e8 il semaforo. In luoghi diversi ci sono sequenze di luci differenti, ma il principio \u00e8 lo stesso: ogni stato rappresenta qualcosa (fermo, vai, ecc.). Il semaforo \u00e8 in uno stato solo in qualsiasi momento e passa da uno all'altro basandosi su semplici regole.<\/p>\n<p>Con NPC nei giochi c'\u00e8 una storia simile. Prendiamo come esempio una guardia con i seguenti stati:<\/p>\n<ul>\n<li>In pattugliamento (Patrolling).<\/li>\n<li>In attacco (Attacking).<\/li>\n<li>In fuga (Fleeing).<\/li>\n<\/ul>\n<p>\nE con queste condizioni per cambiare il suo stato:<\/p>\n<ul>\n<li>Se la guardia vede un nemico, attacca.<\/li>\n<li>Se la guardia attacca, ma non vede pi\u00f9 il nemico, torna a pattugliare.<\/li>\n<li>Se la guardia attacca, ma \u00e8 gravemente ferita, fugge.<\/li>\n<\/ul>\n<p>\n\u00c8 possibile anche scrivere operatori if con una variabile di stato della guardia e vari controlli: c'\u00e8 un nemico vicino, qual \u00e8 il livello di salute dell\u2019NPC, e cos\u00ec via. Aggiungiamo qualche altro stato:<\/p>\n<ul>\n<li>Inattivit\u00e0 (Idling) \u2014 tra le pattuglie.<\/li>\n<li>Ricerca (Searching) \u2014 quando un nemico avvistato si \u00e8 nascosto.<\/li>\n<li>Chiedere aiuto (Finding Help) \u2014 quando un nemico \u00e8 stato avvistato, ma \u00e8 troppo forte per combatterlo da solo.<\/li>\n<\/ul>\n<p>\nLa scelta per ognuno di essi \u00e8 limitata \u2014 per esempio, la guardia non andr\u00e0 a cercare un nemico nascosto se ha poca salute.<\/p>\n<p>Alla fine, un lungo elenco di &quot;se&quot; pu&ograve; diventare troppo ingombrante, pertanto &egrave; necessario formalizzare un metodo che ci permetta di tenere a mente gli stati e le transizioni tra gli stati. &lt;x \u0438 y, \u043d\u043e \u043d\u0435 z&gt;, allora &lt;p&gt;Per fare ci&ograve;, considereremo tutti gli stati e, sotto ciascuno stato, annoteremo un elenco di tutte le transizioni verso altri stati, insieme alle condizioni necessarie per esse.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/ba4c401aa20de3d22d2478cba5a4b1ec.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQuesta \u00e8 una tabella di transizioni di stato \u2014 un modo complesso per rappresentare una FSM. Disegniamo un diagramma e otteniamo una panoramica completa di come cambia il comportamento dell\u2019NPC.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/b4182359983cf573872dacc575af13dc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl diagramma riflette la natura della presa di decisioni per questo agente in base alla situazione attuale. Ogni freccia indica una transizione tra stati, se la condizione accanto ad essa \u00e8 vera.<\/p>\n<p>Ad ogni aggiornamento verifichiamo lo stato attuale dell'agente, consultiamo l'elenco delle transizioni e, se le condizioni per la transizione sono soddisfatte, accetta un nuovo stato. Ad esempio, ogni fotogramma verifica se il timer di 10 secondi \u00e8 scaduto e, in tal caso, l'agente passa dallo stato Idling a Patrolling. Allo stesso modo, lo stato Attacking controlla la salute dell'agente: se \u00e8 bassa, passa allo stato Fleeing.<\/p>\n<p>Questa \u00e8 la gestione delle transizioni tra stati, ma che dire del comportamento associato agli stati stessi? Per quanto riguarda l'implementazione del comportamento effettivo per uno stato specifico, di solito ci sono due tipi di \"hook\" dove assegnamo azioni alla FSM:<\/p>\n<ul>\n<li>Azioni che eseguiamo periodicamente per lo stato attuale.<\/li>\n<li>Azioni che intraprendiamo durante la transizione da uno stato all'altro.<\/li>\n<\/ul>\n<p>\nEsempi per il primo tipo. Lo stato Patrolling sposter\u00e0 l'agente lungo il percorso di pattugliamento ad ogni fotogramma. Lo stato Attacking tenter\u00e0 ogni fotogramma di iniziare un attacco o passare a uno stato in cui ci\u00f2 \u00e8 possibile.<\/p>\n<p>Per il secondo tipo, consideriamo la transizione \"se il nemico \u00e8 visibile e il nemico \u00e8 troppo forte, allora passare allo stato Finding Help.\" L'agente deve scegliere dove andare a cercare aiuto e memorizzare queste informazioni affinch\u00e9 lo stato Finding Help sappia a chi rivolgersi. Una volta trovato aiuto, l'agente torna allo stato Attacking. A questo punto, vorr\u00e0 informare l'alleato della minaccia, quindi pu\u00f2 sorgere l'azione NotifyFriendOfThreat.<\/p>\n<p>Ancora una volta, possiamo guardare questo sistema attraverso il ciclo Sense\/Think\/Act. Sense si materializza nei dati utilizzati dalla logica di transizione. Think \u2014 nelle transizioni disponibili in ogni stato. E Act si concretizza nelle azioni eseguite periodicamente all'interno dello stato o durante le transizioni tra gli stati.<\/p>\n<p>A volte, il monitoraggio continuo delle condizioni di transizione pu\u00f2 risultare costoso. Ad esempio, se ogni agente deve eseguire calcoli complessi a ogni frame per determinare se vede nemici e se pu\u00f2 passare dallo stato di Pattugliamento a quello di Attacco, ci\u00f2 richieder\u00e0 molte risorse del processore. <\/p>\n<p>I cambiamenti significativi nello stato del mondo possono essere considerati eventi da elaborare man mano che si presentano. Invece di far s\u00ec che la FSM controlli ogni frame la condizione di transizione 'pu\u00f2 il mio agente vedere il giocatore?', si pu\u00f2 impostare un sistema separato per effettuare i controlli meno frequentemente (ad esempio, 5 volte al secondo). Il risultato sarebbe emettere Player Seen quando il controllo ha successo. <\/p>\n<p>Questo viene passato alla FSM, che ora deve passare alla condizione event received per Player Seen e rispondere di conseguenza. Il comportamento finale \u00e8 lo stesso, tranne per un ritardo quasi impercettibile prima della risposta. Tuttavia, le prestazioni sono migliorate grazie alla separazione della parte Sense in un'area distinta del programma.<\/p>\n<h3>Macchina a stati finiti gerarchica<\/h3>\n<p>\nTuttavia, lavorare con grandi FSM non \u00e8 sempre comodo. Se volessimo espandere lo stato di attacco, sostituendolo con MeleeAttacking (combattimento corpo a corpo) e RangedAttacking (combattimento a distanza) separati, dovremmo modificare le transizioni da tutti gli altri stati che portano allo stato Attacking (attuale e futuro).<\/p>\n<p>Sicuramente avrete notato che nel nostro esempio ci sono molte transizioni duplicate. La maggior parte delle transizioni nello stato Idling \u00e8 identica a quelle nello stato Patrolling. \u00c8 meglio evitare ripetizioni, specialmente se aggiungeremo altri stati simili. Ha senso raggruppare Idling e Patrolling sotto un'etichetta comune \"non combattenti\", dove c'\u00e8 solo un unico insieme di transizioni verso stati combattivi. Se consideriamo questa etichetta come uno stato, allora Idling e Patrolling diventeranno sottostati. Un esempio di utilizzo di una tabella di transizione separata per il nuovo sottostato non combattente:<\/p>\n<p><i>Stati principali:<\/i><br \/>\n<img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/d86dd918acbe81b9bf22c2fb34aecee3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<i>Stato fuori combattimento:<\/i><br \/>\n<img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/9d5bc2053010a32c5f68d7f0192c04ed.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE in forma di diagramma:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/0ccf95ecafa9ce2a6ea5b5b9833ddc4f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSi tratta dello stesso sistema, ma con un nuovo stato non bellico, che include Idling e Patrolling. Ogni stato contiene una FSM con sottostati (e questi sottostati, a loro volta, contengono la propria FSM \u2014 e cos\u00ec via quante ne servono), ottenendo cos\u00ec una Hierarchical Finite State Machine o HFSM (macchina a stati finiti gerarchica). Raggruppando lo stato non bellico, abbiamo eliminato molte transizioni ridondanti. Lo stesso possiamo fare per nuovi stati con transizioni comuni. Ad esempio, se in futuro espandiamo lo stato Attacking fino a includere gli stati MeleeAttacking e MissileAttacking, questi saranno sottostati che si scambiano tra di loro in base alla distanza dal nemico e alla disponibilit\u00e0 di munizioni. Di conseguenza, modelli di comportamento complessi e sotto-modelli di comportamento possono essere rappresentati con il minimo di transizioni duplicate.<\/p>\n<h3>Albero dei comportamenti<\/h3>\n<p>\nCon HFSM si possono creare combinazioni complesse di comportamenti in modo semplice. Tuttavia, c'\u00e8 una piccola difficolt\u00e0: le decisioni sotto forma di regole di transizione sono strettamente legate allo stato attuale. E in molti giochi, questo \u00e8 esattamente ci\u00f2 di cui si ha bisogno. Un uso attento della gerarchia degli stati pu\u00f2 ridurre il numero di ripetizioni durante le transizioni. Ma a volte sono necessarie regole che funzionano indipendentemente dallo stato in cui ci si trova o che si applicano quasi a tutti gli stati. Ad esempio, se la salute dell'agente scende al 25%, si vorr\u00e0 che scappi indipendentemente dal fatto che sia stato in combattimento, si fosse riposato o stesse parlando: sar\u00e0 necessario aggiungere questa condizione in ogni stato. E se successivamente il designer decide di cambiare la soglia di bassa salute dal 25% al 10%, si dovr\u00e0 occuparne di nuovo.<\/p>\n<p>Ideale per questa situazione sarebbe un sistema in cui le decisioni su \"in quale stato trovarsi\" siano al di fuori degli stati stessi, in modo da apportare modifiche in un solo luogo senza toccare le condizioni di transizione. Qui entrano in gioco gli alberi di comportamento.<\/p>\n<p>Ci sono diversi modi per implementarli, ma il concetto \u00e8 sostanzialmente lo stesso e somiglia a un albero delle decisioni: l'algoritmo inizia da un nodo 'radice', e nell'albero ci sono nodi che rappresentano sia decisioni che azioni. Tuttavia, ci sono alcune differenze chiave:<\/p>\n<ul>\n<li>Ora i nodi restituiscono uno dei tre valori: Succeeded (se il lavoro \u00e8 completato), Failed (se non pu\u00f2 essere avviato) o Running (se \u00e8 ancora in esecuzione e non ci sono risultati finali).<\/li>\n<li>Non ci sono pi\u00f9 nodi decisionali per scegliere tra due alternative. Al loro posto, ci sono i nodi Decorator, che hanno un solo nodo figlio. Se restituiscono Succeed, eseguono il loro unico nodo figlio.<\/li>\n<li>I nodi che eseguono azioni restituiscono il valore Running per rappresentare le azioni in corso.<\/li>\n<\/ul>\n<p>\nQuesto piccolo insieme di nodi pu\u00f2 essere combinato per creare un gran numero di complessi modelli comportamentali. Immaginiamo l'HFSM della guardia dal precedente esempio sotto forma di un albero comportamentale:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/5eaa5c725e4ada8285f16f95bb206d53.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCon questa struttura non dovrebbe esserci un passaggio diretto dagli stati Idling\/Patrolling allo stato Attacking o ad altri stati. Se il nemico \u00e8 visibile e la salute del personaggio \u00e8 bassa, l'esecuzione si fermer\u00e0 al nodo Fleeing, indipendentemente da quale nodo stesse eseguendo in precedenza \u2014 Patrolling, Idling, Attacking o qualsiasi altro.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/e1c1dcc2055174aa7cfa846364b1709a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nGli alberi comportamentali sono complessi: ci sono molti modi per comporli e trovare la giusta combinazione di decoratori e nodi compositi pu\u00f2 risultare problematico. Ci sono anche domande su quanto spesso controllare l'albero: vogliamo passare attraverso ogni parte o solo quando una delle condizioni \u00e8 cambiata? Come mantenere lo stato relativo ai nodi \u2014 come sapere quando siamo stati in uno stato Idling per 10 secondi o come sapere quali nodi sono stati eseguiti l'ultima volta per gestire correttamente la sequenza?<\/p>\n<p>Proprio per questo esistono molteplici implementazioni. Ad esempio, in alcuni sistemi, i nodi decoratori sono stati sostituiti da decoratori integrati. Questi rivalutano l'albero al variare delle condizioni del decoratore, aiutano a collegare i nodi e forniscono aggiornamenti periodici.<\/p>\n<h3>Sistema basato sull'utilit\u00e0<\/h3>\n<p>\nAlcuni giochi presentano molte meccaniche diverse. \u00c8 consigliabile che traggano tutti i vantaggi di regole semplici e generali di transizione, ma non necessariamente in forma di un albero completo di comportamenti. Invece di avere un insieme chiaro di scelte o un albero di azioni possibili, \u00e8 pi\u00f9 semplice esplorare tutte le azioni e scegliere quella pi\u00f9 appropriata al momento.<\/p>\n<p>Il sistema basato sulla utilit\u00e0 aiuta proprio in questo. \u00c8 un sistema in cui l'agente ha molte azioni, e sceglie quale eseguire, basandosi sulla relativa utilit\u00e0 di ciascuna. Dove l'utilit\u00e0 \u00e8 una misura arbitraria di quanto sia importante o desiderabile l'esecuzione di quell'azione per l'agente. <\/p>\n<p>L'agente pu\u00f2 calcolare l'utilit\u00e0 delle azioni in base allo stato e all'ambiente attuali, verificando e selezionando in qualsiasi momento il pi\u00f9 appropriato stato alternativo. Questo \u00e8 simile a un FSM, tranne per il fatto che le transizioni sono definite dalla valutazione di ciascuno stato potenziale, incluso quello attuale. Si noti che scegliamo l'azione pi\u00f9 utile per il passaggio (o restiamo fermi se l'abbiamo gi\u00e0 eseguita). Per maggiore variet\u00e0, pu\u00f2 essere una scelta ponderata ma casuale da un breve elenco.<\/p>\n<p>Il sistema assegna un intervallo casuale di valori di utilit\u00e0, ad esempio, da 0 (completamente indesiderabile) a 100 (completamente desiderabile). Ogni azione ha una serie di parametri che influenzano il calcolo di questo valore. Tornando al nostro esempio con la guardia:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/085fb2c197bde93d78455d18e63c9c25.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nLe transizioni tra le azioni sono ambigue: qualsiasi stato pu\u00f2 seguire un altro. Le priorit\u00e0 delle azioni sono determinate dai valori di utilit\u00e0 restituiti. Se il nemico \u00e8 visibile, e questo nemico \u00e8 forte, mentre la salute del personaggio \u00e8 bassa, sia Fuggire che TrovareAiuto restituiranno valori alti e diversi da zero. Tuttavia, TrovareAiuto avr\u00e0 sempre una priorit\u00e0 maggiore. Allo stesso modo, le azioni non combative non restituiscono mai pi\u00f9 di 50, quindi saranno sempre inferiori alle azioni di combattimento. \u00c8 necessario tenerne conto nella creazione delle azioni e nel calcolo della loro utilit\u00e0.<\/p>\n<p>Nel nostro esempio, le azioni restituiscono un valore costante fisso oppure uno dei due valori fissi. Un sistema pi\u00f9 realistico prevede la restituzione di una valutazione da un intervallo continuo di valori. Ad esempio, l'azione Fleeing restituisce valori di utilit\u00e0 pi\u00f9 elevati se la salute dell'agente \u00e8 bassa, mentre l'azione Attacking restituisce valori pi\u00f9 bassi se il nemico \u00e8 troppo forte. Per questo motivo, l'azione Fleeing ha la priorit\u00e0 su Attacking ogni volta che l'agente percepisce di avere una salute insufficiente per vincere contro il suo avversario. Questo permette di modificare le priorit\u00e0 delle azioni in base a un numero qualsiasi di criteri, rendendo questo approccio pi\u00f9 flessibile e variabile rispetto a un albero comportamentale o a un FSM.<\/p>\n<p>Ogni azione ha molte condizioni per calcolare il programma. Queste possono essere scritte in un linguaggio di scripting o come una serie di formule matematiche. In The Sims, che simula la routine quotidiana del personaggio, viene aggiunto un ulteriore livello di calcolo: l'agente riceve una serie di \"motivazioni\" che influenzano le valutazioni di utilit\u00e0. Se il personaggio ha fame, col tempo avr\u00e0 ancora pi\u00f9 fame, e il risultato dell'azione EatFood aumenter\u00e0 finch\u00e9 il personaggio non la eseguir\u00e0, riducendo il livello di fame e riportando il valore di EatFood a zero. <\/p>\n<p>L'idea di scegliere azioni basate su un sistema di valutazione \u00e8 piuttosto semplice, quindi il sistema basato sull'utilit\u00e0 pu\u00f2 essere utilizzato come parte dei processi decisionali dell'IA, non come un loro completo sostituto. Un albero delle decisioni pu\u00f2 richiedere la valutazione dell'utilit\u00e0 di due nodi figli e scegliere quello con il valore pi\u00f9 elevato. Allo stesso modo, un albero del comportamento pu\u00f2 avere un nodo composto di Utilit\u00e0 per valutare l'utilit\u00e0 delle azioni, decidendo quale elemento figlio eseguire.<\/p>\n<h2>Movimento e navigazione<\/h2>\n<p>\nNei precedenti esempi avevamo una piattaforma che spostavamo a sinistra o a destra e una sentinella che pattugliava o attaccava. Ma come gestiamo esattamente il movimento dell'agente nel corso del tempo? Come impostiamo la velocit\u00e0, come evitiamo gli ostacoli e come pianifichiamo il percorso se raggiungere la destinazione \u00e8 pi\u00f9 complesso che muoversi in linea retta? Analizziamo questo.<\/p>\n<h3>Gestione<\/h3>\n<p>\nInizialmente, supponiamo che ogni agente abbia un valore di velocit\u00e0 che include quanto velocemente si muove e in quale direzione. Pu\u00f2 essere misurata in metri al secondo, chilometri all'ora, pixel al secondo, ecc. Ricordando il ciclo Sense\/Think\/Act, possiamo immaginare che la parte Think scelga la velocit\u00e0, mentre la parte Act applichi quella velocit\u00e0 all'agente. Di solito, nei giochi esiste un sistema fisico che esegue questo compito per te, monitorando il valore di velocit\u00e0 di ogni oggetto e regolando di conseguenza. Pertanto, possiamo lasciare all'IA un compito: decidere quale velocit\u00e0 deve avere l'agente. Se si sa dove l'agente deve trovarsi, allora deve essere spostato nella giusta direzione a una velocit\u00e0 stabilita. \u00c8 un'equazione molto triviale:<\/p>\n<p><i>desired_travel = destination_position \u2013 agent_position<\/i><\/p>\n<p>Immagina un mondo 2D. L'agente si trova nel punto (-2,-2), mentre la destinazione \u00e8 da qualche parte a nord-est, nel punto (30, 20), e il percorso necessario per l'agente per arrivarci \u00e8 (32, 22). Supponiamo che queste posizioni siano misurate in metri: se consideriamo la velocit\u00e0 dell'agente di 5 metri al secondo, scaleremo il nostro vettore di movimento e otterremo una velocit\u00e0 di circa (4.12, 2.83). Con questi parametri, l'agente arriverebbe a destinazione in quasi 8 secondi.<\/p>\n<p>I valori possono essere ricalcolati in qualsiasi momento. Se l'agente era a met\u00e0 strada verso l'obiettivo, il movimento sarebbe stato la met\u00e0 della lunghezza, ma poich\u00e9 la velocit\u00e0 massima dell'agente \u00e8 di 5 m\/s (come deciso sopra), la velocit\u00e0 sar\u00e0 uguale. Questo funziona anche per obiettivi in movimento, consentendo all'agente di apportare piccole modifiche mentre si muovono.<\/p>\n<p>Tuttavia, desideriamo maggiore variet\u00e0: ad esempio, aumentare lentamente la velocit\u00e0 per simulare un personaggio che passa da una posizione ferma alla corsa. Lo stesso vale per l'arresto finale. Queste funzionalit\u00e0 sono conosciute come comportamenti di guida, ciascuno con un nome specifico: Seek (ricerca), Flee (fuga), Arrival (arrivo) e cos\u00ec via. L'idea \u00e8 che le forze di accelerazione possono essere applicate alla velocit\u00e0 dell'agente, confrontando la posizione dell'agente e la velocit\u00e0 attuale con il punto di destinazione, in modo da utilizzare diversi metodi di movimento verso l'obiettivo.<\/p>\n<p>Ogni comportamento ha un obiettivo leggermente diverso. Seek e Arrival sono modi per muovere l'agente verso una destinazione. Obstacle Avoidance (evitamento ostacoli) e Separation (separazione) correggono il movimento dell'agente per aggirare gli ostacoli lungo il percorso verso l'obiettivo. Alignment (allineamento) e Cohesion (coesione) mantengono gli agenti uniti durante il movimento. Un numero qualsiasi di diversi comportamenti di guida pu\u00f2 essere sommato per ottenere un unico vettore di percorso che tiene conto di tutti i fattori. Un agente utilizza i comportamenti Arrival, Separation e Obstacle Avoidance per mantenere la distanza da pareti e altri agenti. Questo approccio funziona bene in spazi aperti senza troppi dettagli. <\/p>\n<p>In condizioni pi\u00f9 difficili, la somma di diversi comportamenti funziona peggio \u2014 per esempio, un agente potrebbe rimanere bloccato in un muro a causa di un conflitto tra Arrival e Obstacle Avoidance. Pertanto, \u00e8 necessario considerare opzioni pi\u00f9 complesse rispetto a una semplice somma di tutti i valori. Un modo per farlo \u00e8: invece di sommare i risultati di ciascun comportamento, si possono considerare i movimenti in diverse direzioni e scegliere la migliore opzione. <\/p>\n<p>Tuttavia, in un ambiente complesso con vicoli ciechi e scelte su quale direzione andare, avremo bisogno di qualcosa di ancora pi\u00f9 avanzato.<\/p>\n<h3>Ricerca del percorso<\/h3>\n<p>\nI comportamenti di guida sono ideali per la semplice navigazione in spazi aperti (un campo da calcio o un'arena), dove raggiungere A da B \u00e8 un percorso diretto con lievi deviazioni attorno agli ostacoli. Per percorsi pi\u00f9 complessi, abbiamo bisogno del pathfinding, che \u00e8 un modo per esplorare il mondo e decidere il miglior tragitto attraverso di esso.<\/p>\n<p>Il modo pi\u00f9 semplice \u00e8 sovrapporre una griglia su ogni quadrato accanto all'agente e valutare in quali di essi \u00e8 permesso muoversi. Se uno di essi \u00e8 una destinazione, segui da esso il percorso da ogni quadrato al precedente, fino a tornare all'inizio. Questo \u00e8 il percorso. In caso contrario, ripeti il processo con i quadrati vicini finch\u00e9 non trovi la destinazione o non ci sono pi\u00f9 quadrati (il che significa che non esiste alcun percorso possibile). Questo \u00e8 formalmente noto come Breadth-First Search o BFS (algoritmo di ricerca in ampiezza). Ad ogni passo, guarda in tutte le direzioni (da qui 'breadth', 'ampiezza'). Lo spazio di ricerca assomiglia a un fronte d'onda che si muove fino a raggiungere il punto desiderato \u2014 l'area di ricerca si espande ad ogni passo fino a quando non raggiunge il punto finale, dopo di che \u00e8 possibile tracciare il percorso verso l'inizio.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/d367e62bc53033b05388538649853a41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDi conseguenza, avrai un elenco di quadrati da cui si compone il percorso desiderato. Questo \u00e8 il percorso (da qui 'pathfinding') \u2014 l'elenco dei luoghi che l'agente visiter\u00e0 mentre si dirige verso la destinazione.<\/p>\n<p>Considerando che conosciamo la posizione di ciascun quadrato nel mondo, possiamo utilizzare i comportamenti di steering per muoverci lungo il percorso \u2014 dal nodo 1 al nodo 2, poi dal nodo 2 al nodo 3 e cos\u00ec via. La soluzione pi\u00f9 semplice \u00e8 dirigersi verso il centro del prossimo quadrato, ma \u00e8 ancora meglio fermarsi a met\u00e0 del lato tra il quadrato attuale e quello successivo. Questo permette all'agente di tagliare gli angoli nelle curve strette.<\/p>\n<p>L'algoritmo BFS ha anche degli svantaggi \u2014 esplora quanti pi\u00f9 quadrati nella direzione \u00absbagliata\u00bb quanti quelli nella direzione \u00abgiusta\u00bb. Qui entra in gioco un algoritmo pi\u00f9 complesso chiamato A* (A star). Funziona in modo simile, ma invece di esplorare ciecamente i quadrati vicini (poi i vicini dei vicini, poi i vicini dei vicini dei vicini e cos\u00ec via), raccoglie i nodi in una lista e li ordina in modo tale che il prossimo nodo esplorato sia sempre quello che porter\u00e0 al percorso pi\u00f9 breve. I nodi vengono ordinati sulla base di un'euristica che considera due aspetti \u2014 il \u00abcosto\u00bb del percorso ipotetico verso il quadrato desiderato (inclusi eventuali costi di spostamento) e una stima di quanto questo quadrato sia lontano dalla destinazione (spostando la ricerca nella direzione giusta).<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/1cab4f53fa5af6b31d352c7bcf453d7e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn questo esempio, l'agente esplora un quadrato alla volta, scegliendo ogni volta quello vicino che offre le migliori possibilit\u00e0. Il percorso ottenuto \u00e8 lo stesso del BFS, ma nel processo sono stati considerati meno quadrati, il che \u00e8 significativo per le prestazioni del gioco.<\/p>\n<h3>Movimento senza griglia<\/h3>\n<p>\nMa la maggior parte dei giochi non \u00e8 organizzata su una griglia, e spesso non \u00e8 possibile crearla senza compromettere il realismo. Sono necessari dei compromessi. Quali dovrebbero essere le dimensioni dei quadrati? Troppo grandi \u2014 e non potranno rappresentare correttamente corridoi o curve strette, troppo piccoli \u2014 ci sarebbero troppi quadrati da cercare, il che richiederebbe molto tempo.<\/p>\n<p>La prima cosa da comprendere \u00e8 che la griglia ci fornisce un grafo di nodi collegati. Gli algoritmi A* e BFS funzionano fondamentalmente su grafi e non si preoccupano affatto della nostra griglia. Potremmo posizionare i nodi in qualsiasi punto del mondo di gioco: con una connessione tra due nodi, cos\u00ec come tra il punto di partenza e di arrivo e almeno uno dei nodi, l'algoritmo funzioner\u00e0 altrettanto bene come prima. Questo \u00e8 spesso chiamato sistema di waypoint, poich\u00e9 ogni nodo rappresenta una posizione significativa nel mondo, che pu\u00f2 far parte di un numero qualsiasi di percorsi ipotetici.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/d87e9d4bb2a2fc713d32abc158506eaa.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Esempio 1: un nodo in ogni quadrato. La ricerca inizia dal nodo in cui si trova l'agente e termina nel nodo del quadrato desiderato.<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/b535a5db805efdc427d7c5724b866982.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Esempio 2: un insieme ridotto di nodi (waypoint). La ricerca inizia nel quadrato con l'agente, passa attraverso il numero necessario di nodi e poi continua fino alla destinazione.<\/i><\/p>\n<p>Si tratta di un sistema piuttosto flessibile e potente. Tuttavia, \u00e8 necessaria una certa prudenza nelle decisioni riguardo a dove e come posizionare i waypoint; altrimenti, gli agenti potrebbero semplicemente non vedere il punto pi\u00f9 vicino e non riuscire a partire. Sarebbe pi\u00f9 semplice se potessimo disporre automaticamente i waypoint sulla base della geometria del mondo.<\/p>\n<p>Qui entra in gioco la navigation mesh o navmesh (rete di navigazione). Si tratta solitamente di una rete 2D di triangoli che si sovrappone alla geometria del mondo, in tutte le aree in cui all'agente \u00e8 consentito muoversi. Ciascuno dei triangoli nella rete diventa un nodo nel grafo e ha fino a tre triangoli adiacenti che diventano nodi vicini nel grafo. <\/p>\n<p>Questa immagine \u00e8 un esempio dal motore Unity: ha analizzato la geometria del mondo e creato il navmesh (nella schermata di colore blu chiaro). Ogni poligono nel navmesh \u00e8 un'area su cui l'agente pu\u00f2 stare o spostarsi da un poligono a un altro. In questo esempio, i poligoni sono pi\u00f9 piccoli dei piani su cui si trovano, per tenere conto delle dimensioni dell'agente, che potrebbero estendersi oltre la sua posizione nominale.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/845705ba7b9a9d469203aedf7942da41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPossiamo cercare un percorso attraverso questa rete, utilizzando nuovamente l'algoritmo A*. Questo ci dar\u00e0 un percorso praticamente perfetto in un mondo che tiene conto di tutta la geometria e non richiede nodi inutili e creazione di punti di passaggio.<\/p>\n<p>La ricerca di percorsi \u00e8 un argomento troppo vasto per essere trattato in un solo articolo. Se vuoi approfondire, puoi trovare aiuto sul <noindex><a rel=\"nofollow\" href=\"https:\/\/www.redblobgames.com\/pathfinding\/a-star\/introduction.html\">sito di Amit Patel.<\/a><\/noindex>.<\/p>\n<h2>Pianificazione<\/h2>\n<p>\nAbbiamo appreso con la ricerca di percorsi che a volte non basta semplicemente scegliere una direzione e muoversi: dobbiamo scegliere un percorso e effettuare alcune svolte per raggiungere la destinazione desiderata. Possiamo riassumere questa idea: raggiungere un obiettivo non \u00e8 solo il prossimo passo, ma una vera e propria sequenza, in cui a volte \u00e8 necessario guardare avanti di alcuni passi per sapere quale dovrebbe essere il primo. Questo \u00e8 chiamato pianificazione. La ricerca di percorsi pu\u00f2 essere vista come una delle varie integrazioni della pianificazione. Dal punto di vista del nostro ciclo Sensore\/Pensiero\/Azione, \u00e8 qui che la parte Pensiero pianifica diverse parti dell'Azione per il futuro.<\/p>\n<p>Analizziamo con l'esempio del gioco da tavolo Magic: The Gathering. Iniziamo per primi con questa mano di carte:<\/p>\n<ul>\n<li>Palude \u2014 fornisce 1 mana nero (carta terreno).<\/li>\n<li>Foresta \u2014 fornisce 1 mana verde (carta terra).<\/li>\n<li>Mago Fuggitivo \u2014 richiede 1 mana blu per l'invocazione.<\/li>\n<li>Mistico Elfico \u2014 richiede 1 mana verde per l'invocazione.<\/li>\n<\/ul>\n<p>\nIgnoriamo le tre carte rimanenti per semplificare. Secondo le regole, un giocatore pu\u00f2 giocare 1 carta terra per turno; pu\u00f2 'tappare' questa carta per ottenere mana e poi usare incantesimi (incluso l'invocazione di creature) in base alla quantit\u00e0 di mana. In questa situazione, un giocatore umano sa che deve giocare Foresta, 'tappare' 1 mana verde e poi invocare il Mistico Elfico. Ma come pu\u00f2 capirlo l'IA del gioco?<\/p>\n<h3>Pianificazione semplice<\/h3>\n<p>\nL'approccio triviale \u00e8 provare ogni azione a turno, finch\u00e9 non rimangono opzioni valide. Guardando le carte, l'IA vede che pu\u00f2 giocare Pantano. E lo gioca. Ci sono altre azioni disponibili in questo turno? Non pu\u00f2 invocare n\u00e9 il Mistico Elfico n\u00e9 il Mago Fuggitivo, poich\u00e9 richiedono rispettivamente mana verde e blu, e il Pantano fornisce solo mana nera. E non potr\u00e0 giocare Foresta, perch\u00e9 ha gi\u00e0 giocato il Pantano. In questo modo, l'IA di gioco ha agito secondo le regole, ma lo ha fatto male. Si pu\u00f2 migliorare.<\/p>\n<p>La pianificazione pu\u00f2 trovare un elenco di azioni che conducono il gioco allo stato desiderato. Proprio come ogni quadrato nel percorso ha avuto dei vicini (nel pathfinding), ogni azione nel piano ha anche dei vicini o successori. Possiamo esplorare queste azioni e le azioni successive finch\u00e9 non raggiungiamo lo stato desiderato.<\/p>\n<p>Nel nostro esempio, il risultato desiderato \u00e8 \u00abevocare una creatura, se possibile\u00bb. All'inizio del turno vediamo solo due possibili azioni consentite dalle regole del gioco:<\/p>\n<p><i>1. Giocare Swamp (risultato: Swamp in gioco)<br \/>\n2. Giocare Forest (risultato: Forest in gioco)<\/i><\/p>\n<p>Ogni azione intrapresa pu\u00f2 portare a ulteriori azioni e chiudere altre, ancora una volta a seconda delle regole del gioco. Immaginate di aver giocato Swamp \u2014 questo rimuover\u00e0 Swamp come prossimo passo (lo abbiamo gi\u00e0 giocato), e rimuover\u00e0 anche Forest (perch\u00e9 secondo le regole si pu\u00f2 giocare solo una carta terra per turno). Successivamente, l'IA aggiunge come prossimo passo \u2014 ottenere 1 mana nero, perch\u00e9 non ci sono altre opzioni. Se proceder\u00e0 ulteriormente e sceglier\u00e0 di tappare lo Swamp, otterr\u00e0 1 mana nero e non potr\u00e0 fare nulla con esso.<\/p>\n<p><i>1. Giocare Swamp (risultato: Swamp in gioco)<br \/>\n 1.1 \u00abTappare\u00bb Swamp (risultato: Swamp \u00abtappato\u00bb, +1 unit\u00e0 di mana nera)<br \/>\n Nessuna azione disponibile \u2013 FINE<br \/>\n2. Giocare Forest (risultato: Forest in gioco)<\/i><\/p>\n<p>L'elenco delle azioni \u00e8 corto, siamo bloccati. Ripetiamo il processo per la prossima azione. Giochiamo Forest, attiviamo l'azione \u00abottenere 1 mana verde\u00bb, che a sua volta attiver\u00e0 la terza azione \u2014 evocare Elvish Mystic.<\/p>\n<p><i>1. Giocare Swamp (risultato: Swamp in gioco)<br \/>\n 1.1 \u00abTappare\u00bb Swamp (risultato: Swamp \u00abtappato\u00bb, +1 unit\u00e0 di mana nera)<br \/>\n Nessuna azione disponibile \u2013 FINE<br \/>\n2. Giocare Forest (risultato: Forest in gioco)<br \/>\n 2.1 \u00abTappare\u00bb Forest (risultato: Forest \u00abtappata\u00bb, +1 unit\u00e0 di mana verde)<br \/>\n 2.1.1 Evocare Elvish Mystic (risultato: Elvish Mystic in gioco, -1 unit\u00e0 di mana verde)<br \/>\n Nessuna azione disponibile \u2013 FINE<\/i><\/p>\n<p>Infine, abbiamo esaminato tutte le possibili azioni e trovato un piano per evocare una creatura.<\/p>\n<p>Questo \u00e8 un esempio molto semplificato. \u00c8 preferibile scegliere il miglior piano possibile, piuttosto che qualsiasi piano che soddisfi determinati criteri. In generale, \u00e8 possibile valutare i piani potenziali in base al risultato finale o ai benefici complessivi derivanti dalla loro attuazione. Si possono guadagnare 1 punto per ogni carta terra giocata e 3 punti per l'evocazione di una creatura. Giocare Swamp sarebbe un piano che fornisce 1 punto. Giocare Forest \u2192 Tappare la Forest \u2192 evocare Elvish Mystic darebbe immediatamente 4 punti. <\/p>\n<p>Ecco come funziona la pianificazione in Magic: The Gathering, ma la stessa logica si applica anche in altre situazioni. Ad esempio, spostare un pedone per liberare spazio per muovere un alfiere negli scacchi. O ripararsi dietro un muro per poter sparare in sicurezza in XCOM. Insomma, hai capito il concetto.<\/p>\n<h3>Pianificazione avanzata<\/h3>\n<p>\nA volte ci sono troppe possibili azioni da considerare per esaminare ogni opzione. Tornando all'esempio di Magic: The Gathering: supponiamo che ci siano diverse carte di terra e creature in gioco e nella tua mano: il numero di possibili combinazioni di mosse pu\u00f2 essere enorme. Ci sono alcune soluzioni a questo problema.<\/p>\n<p>Il primo metodo \u00e8 il backwards chaining (formazione della catena al contrario). Invece di esaminare tutte le combinazioni, \u00e8 meglio iniziare dal risultato finale e cercare un percorso diretto. Invece di muoversi dalla radice dell'albero verso una foglia specifica, ci muoviamo in direzione opposta \u2014 dalla foglia alla radice. Questo metodo \u00e8 pi\u00f9 semplice e veloce.<\/p>\n<p>Se il nemico ha 1 punto vita, possiamo trovare un piano per 'infliggere 1 o pi\u00f9 danni'. Per farlo \u00e8 necessario soddisfare una serie di condizioni: <\/p>\n<p>1. Un incantesimo pu\u00f2 causare danni \u2014 deve essere nella mano.<br \/>\n2. Per lanciare un incantesimo \u2014 \u00e8 necessaria la mana.<br \/>\n3. Per ottenere mana \u2014 \u00e8 necessario giocare una carta terreno.<br \/>\n4. Per giocare una carta terreno \u2014 \u00e8 necessario averla in mano.<\/p>\n<p>Un altro modo \u00e8 la ricerca best-first (cerca il migliore per primo). Invece di esaminare tutti i percorsi, scegliamo il pi\u00f9 idoneo. Questo metodo frequentemente fornisce un piano ottimale senza costi aggiuntivi per la ricerca. A* \u00e8 una forma di ricerca best-first \u2014 esplorando i percorsi pi\u00f9 promettenti sin dall'inizio, pu\u00f2 gi\u00e0 trovare il percorso migliore senza dover controllare le altre opzioni.<\/p>\n<p>Una delle varianti pi\u00f9 interessanti e sempre pi\u00f9 popolari della ricerca best-first \u00e8 il Monte Carlo Tree Search. Invece di indovinare quali piani siano migliori ad ogni azione successiva, l'algoritmo sceglie successori casuali ad ogni passo, fino a raggiungere la fine (quando il piano porta alla vittoria o alla sconfitta). Il risultato finale viene poi utilizzato per aumentare o diminuire la valutazione del 'peso' delle opzioni precedenti. Ripetendo questo processo pi\u00f9 volte, l'algoritmo fornisce una buona stima di quale possa essere il passo successivo migliore, anche se la situazione cambia (se l'avversario prende misure per ostacolare il giocatore). <\/p>\n<p>Nel racconto del pianificare nei giochi non si pu\u00f2 prescindere dal Goal-Oriented Action Planning o GOAP (pianificazione delle azioni orientata agli obiettivi). Questo \u00e8 un metodo ampiamente utilizzato e discusso, ma al di l\u00e0 di alcuni dettagli distintivi, \u00e8 essenzialmente un metodo di backwards chaining, di cui abbiamo parlato in precedenza. Se l'obiettivo \u00e8 'eliminare il giocatore', e il giocatore \u00e8 dietro a una copertura, il piano potrebbe essere: distruggi con una granata \u2192 prendila \u2192 lanciala.<\/p>\n<p>Di solito ci sono pi\u00f9 obiettivi, ognuno con la propria priorit\u00e0. Se l'obiettivo con la massima priorit\u00e0 non pu\u00f2 essere raggiunto (nessuna combinazione di azioni crea un piano per 'eliminare il giocatore', poich\u00e9 il giocatore non \u00e8 visibile), l'IA torner\u00e0 agli obiettivi con priorit\u00e0 inferiore.<\/p>\n<h2>Apprendimento e adattamento<\/h2>\n<p>\nAbbiamo gi\u00e0 detto che l'IA di gioco di solito non utilizza il machine learning, poich\u00e9 non \u00e8 adatta per gestire agenti in tempo reale. Ma questo non significa che non si possa imparare qualcosa da quest'area. Vogliamo un avversario in uno sparatutto da cui si possa apprendere qualcosa. Per esempio, scoprire le migliori posizioni sulla mappa. Oppure un avversario in un picchiaduro che bloccasse frequentemente le combo usate dai giocatori, motivando a utilizzare altre mosse. Quindi, il machine learning in tali situazioni pu\u00f2 essere molto utile.<\/p>\n<h3>Statistiche e probabilit\u00e0<\/h3>\n<p>\nPrima di immergerci in esempi complessi, vediamo quanto possiamo scorprire prendendo alcune semplici misure e utilizzandole per prendere decisioni. Ad esempio, nella strategia in tempo reale, come possiamo determinare se un giocatore possa iniziare un attacco nei primi minuti del gioco e quale difesa preparare contro di esso? Possiamo analizzare le esperienze passate del giocatore per capire quale potrebbe essere la futura reazione. Partiamo dal presupposto che non abbiamo dati di partenza, ma possiamo raccoglierli \u2014 ogni volta che l'IA gioca contro un umano, pu\u00f2 registrare il tempo della prima attacco. Dopo alcune sessioni, avremo una media del tempo che ci vorr\u00e0 per il giocatore per attaccare in futuro.<\/p>\n<p>Le medie hanno anche un problema: se un giocatore ha \"rushato\" 20 volte e ha giocato lentamente 20 volte, i valori necessari saranno da qualche parte nel mezzo, e ci\u00f2 non ci fornir\u00e0 nulla di utile. Una soluzione \u00e8 limitare i dati in ingresso \u2014 possiamo considerare solo gli ultimi 20 eventi.<\/p>\n<p>Un approccio simile viene utilizzato per valutare la probabilit\u00e0 di determinate azioni, assumendo che le preferenze passate del giocatore rimarranno le stesse in futuro. Se un giocatore ci attacca cinque volte con palle di fuoco, due volte con fulmini e una volta corpo a corpo, \u00e8 chiaro che preferisce le palle di fuoco. Espandiamo e vediamo la probabilit\u00e0 di utilizzo delle diverse armi: palladi fuoco = 62,5%, fulmine = 25% e corpo a corpo = 12,5%. La nostra IA di gioco deve prepararsi a difendersi dal fuoco.<\/p>\n<p>Un altro metodo interessante \u00e8 utilizzare il Naive Bayes Classifier (classificatore bayesiano naive) per analizzare grandi volumi di dati in ingresso e classificare la situazione affinch\u00e9 l'IA reagisca in modo appropriato. I classificatori bayesiani sono pi\u00f9 noti per il loro utilizzo nei filtri antispam delle email. In questo caso, esaminano le parole, le confrontano con le precedenti apparizioni di quelle parole (in spam o meno) e traggono conclusioni sulle email in arrivo. Possiamo fare lo stesso anche con un minor numero di dati in ingresso. Sulla base di tutte le informazioni utili che l'IA osserva (ad esempio, quali unit\u00e0 nemiche sono state create, quali incantesimi vengono utilizzati o quali tecnologie sono state esplorate) e il risultato finale (guerra o pace, attaccare o difendersi, ecc.) \u2014 selezioneremo il comportamento pi\u00f9 adeguato per l'IA.<\/p>\n<p>Tutti questi metodi di apprendimento sono sufficienti, ma \u00e8 preferibile utilizzarli basandosi sui dati dei test. L'IA apprender\u00e0 ad adattarsi a diverse strategie utilizzate dai tuoi playtester. Un'IA che si adatta ai giocatori dopo il rilascio potrebbe diventare troppo prevedibile o, al contrario, troppo difficile da battere.<\/p>\n<h3>Adattamento basato sui valori<\/h3>\n<p>\nTenendo conto della struttura del nostro mondo di gioco e delle regole, possiamo modificare il set di valori che influenzano le decisioni, anzich\u00e9 semplicemente utilizzare i dati in ingresso. Procediamo in questo modo:<\/p>\n<ul>\n<li>Lasciamo che l'IA raccolga dati sullo stato del mondo e sugli eventi chiave durante il gioco (come indicato sopra).<\/li>\n<li>Modifichiamo alcuni valori importanti in base a questi dati.<\/li>\n<li>Implementiamo le nostre decisioni basate sull'elaborazione o sulla valutazione di questi valori.<\/li>\n<\/ul>\n<p>\nAd esempio, l'agente ha diverse stanze tra cui scegliere sulla mappa di uno sparatutto in prima persona. Ogni stanza ha il proprio valore, che determina quanto sia desiderabile per la visita. L'IA sceglie casualmente in quale stanza andare, basandosi sul valore. Poi l'agente ricorda in quale stanza \u00e8 stato ucciso e diminuisce il suo valore (la probabilit\u00e0 che torni l\u00ec). Analogamente, se l'agente elimina molti avversari, il valore della stanza aumenta.<\/p>\n<h3>Modello di Markov<\/h3>\n<p>\nCosa succede se utilizziamo i dati raccolti per le previsioni? Se ricordiamo ogni stanza in cui vediamo un giocatore per un certo periodo, possiamo anticipare in quale stanza il giocatore potrebbe andare. Monitorando e registrando i movimenti del giocatore tra le stanze (valori), possiamo fare delle previsioni.<\/p>\n<p>Prendiamo tre stanze: rossa, verde e blu. E anche le osservazioni che abbiamo registrato durante la visione della sessione di gioco:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/6e90a365b72a176c36c9a14213baaafc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nIl numero di osservazioni per ogni stanza \u00e8 quasi uguale \u2014 non sappiamo ancora dove creare un buon punto di appostamento. La raccolta di statistiche \u00e8 inoltre complicata dal respawn dei giocatori, che appaiono uniformemente in tutta la mappa. Tuttavia, i dati sulla successiva stanza in cui entrano dopo essere apparsi sulla mappa sono gi\u00e0 utili.<\/p>\n<p>\u00c8 chiaro che la stanza verde soddisfa i giocatori \u2014 la maggior parte delle persone dalla stanza rossa vi si trasferisce, e il 50% di esse rimane l\u00ec. Al contrario, la stanza blu non gode di popolarit\u00e0; vi entrano molto pochi e, se ci vanno, non si fermano. <\/p>\n<p>Ma i dati ci dicono qualcosa di pi\u00f9 importante: quando il giocatore si trova nella stanza blu, la stanza successiva in cui \u00e8 pi\u00f9 probabile che lo vediamo sar\u00e0 rossa e non verde. Sebbene la stanza verde sia pi\u00f9 popolare di quella rossa, la situazione cambia se il giocatore \u00e8 nella stanza blu. Il prossimo stato (cio\u00e8 la stanza in cui il giocatore passer\u00e0) dipende dallo stato precedente (cio\u00e8 dalla stanza in cui il giocatore si trova attualmente). Grazie all'analisi delle dipendenze, saremo in grado di fare previsioni pi\u00f9 accurate rispetto a se semplicemente conteggiassimo le osservazioni in modo indipendente l'una dall'altra.<\/p>\n<p>La previsione dello stato futuro sulla base dei dati dello stato passato \u00e8 chiamata modello di Markov, e tali esempi (con stanze) vengono definiti catene di Markov. Poich\u00e9 i modelli rappresentano la probabilit\u00e0 di cambiamenti tra stati successivi, vengono visualizzati come FSM con probabilit\u00e0 associate a ciascun passaggio. In precedenza, abbiamo utilizzato le FSM per rappresentare lo stato comportamentale in cui si trovava l'agente, ma questo concetto si estende a qualsiasi stato, indipendentemente dal fatto che sia associato all'agente o meno. In questo caso, gli stati rappresentano la stanza occupata dall'agente:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/edb32dff7a3298b19c3fa4d66f48e9f4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQuesta \u00e8 una semplice rappresentazione della probabilit\u00e0 relativa dei cambiamenti di stato, che offre all'IA una certa possibilit\u00e0 di prevedere il prossimo stato. \u00c8 possibile prevedere diversi passaggi avanti.<\/p>\n<p>Se un giocatore si trova nella stanza verde, c'\u00e8 il 50% di probabilit\u00e0 che rimanga l\u00ec al prossimo osservazione. Ma qual \u00e8 la probabilit\u00e0 che ci sia ancora anche dopo? Non c'\u00e8 solo la possibilit\u00e0 che il giocatore rimanga nella stanza verde dopo due osservazioni, ma anche la possibilit\u00e0 che sia uscito e poi tornato. Ecco una nuova tabella basata sui nuovi dati:<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/f87afff68b066a879661e37f68654ae2.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nDa essa si evince che la probabilit\u00e0 di vedere il giocatore nella stanza verde dopo due osservazioni sar\u00e0 del 51% \u2014 21% che provenga dalla stanza rossa, 5% di probabilit\u00e0 che il giocatore visiti la stanza blu nel mezzo, e 25% che il giocatore non esca affatto dalla stanza verde.<\/p>\n<p>La tabella \u00e8 uno strumento visivo semplice: la procedura richiede solo di moltiplicare le probabilit\u00e0 a ogni passo. Questo significa che puoi guardare lontano nel futuro con un'unica riserva: presumiamo che la probabilit\u00e0 di entrare in una stanza dipenda completamente dalla stanza attuale. Questo \u00e8 conosciuto come propriet\u00e0 di Markov (Markov Property) \u2014 il futuro stato dipende solo dallo stato presente. Tuttavia, non \u00e8 totalmente preciso. I giocatori possono modificare le decisioni in base ad altri fattori: livello di salute o quantit\u00e0 di munizioni. Poich\u00e9 non registriamo questi valori, le nostre previsioni saranno meno accurate.<\/p>\n<h3>N-Grams<\/h3>\n<p>\nE per quanto riguarda l'esempio del combattimento e la previsione delle combo dei giocatori? \u00c8 lo stesso! Ma invece di uno stato o evento, esploreremo intere sequenze che compongono il colpo in combo.<\/p>\n<p>Uno dei modi per farlo \u00e8 memorizzare ogni input (ad esempio, Kick, Punch o Block) in un buffer e registrare l'intero buffer come evento. Quindi, se un giocatore preme ripetutamente Kick, Kick, Punch per eseguire l'attacco SuperDeathFist, il sistema AI memorizza tutti gli input nel buffer e ricorda gli ultimi tre utilizzati a ogni passaggio.<\/p>\n<p><img decoding=\"async\" alt=\"Come creare un&#039;IA di gioco: guida per principianti\" src=\"\/wp-content\/uploads\/2019\/11\/9a95226ae155dca5e45a66d4440f3cd4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n(Le righe sono evidenziate in grassetto quando il giocatore avvia l'attacco SuperDeathFist.)<\/p>\n<p>L'IA vedr\u00e0 tutte le opzioni quando il giocatore seleziona Kick, seguito da un altro Kick, e poi noter\u00e0 che il prossimo input \u00e8 sempre Punch. Questo permetter\u00e0 all'agente di prevedere la combo SuperDeathFist e di bloccarla se possibile.<\/p>\n<p>Queste sequenze di eventi sono chiamate N-grammi, dove N \u00e8 il numero di elementi memorizzati. Nell'esempio precedente, si trattava di un 3-gramma, il che significa: i primi due elementi vengono utilizzati per prevedere il terzo. Di conseguenza, in un 5-gramma, i primi quattro elementi prevedono il quinto e cos\u00ec via.<\/p>\n<p>Lo sviluppatore deve scegliere con attenzione la dimensione degli N-grammi. Un numero minore di N richiede meno memoria, ma memorizza anche una storia minore. Ad esempio, un 2-gramma registrer\u00e0 Kick, Kick o Kick, Punch, ma non sar\u00e0 in grado di memorizzare Kick, Kick, Punch, pertanto l'IA non risponder\u00e0 alla combo SuperDeathFist.<\/p>\n<p>D'altra parte, numeri pi\u00f9 grandi richiedono pi\u00f9 memoria e sar\u00e0 pi\u00f9 difficile per l'IA addestrarsi, poich\u00e9 ci saranno molte pi\u00f9 varianti possibili. Se avevate tre possibili input: Kick, Punch o Block, e utilizzavamo un modello di 10-grammi, ci sarebbero circa 60.000 varianti diverse.<\/p>\n<p>Il modello dei bigrammi \u00e8 una semplice catena di Markov: ogni coppia \u00abstato passato\/stato attuale\u00bb \u00e8 un bigramma, e si pu\u00f2 prevedere il secondo stato basandosi sul primo. I 3-grammi e le N-grammi pi\u00f9 grandi possono anche essere considerati catene di Markov, dove tutti gli elementi (eccetto l'ultimo nell'N-gramma) insieme formano il primo stato, e l'ultimo elemento \u00e8 il secondo. L'esempio con il combattimento mostra la probabilit\u00e0 di passare dallo stato Kick e Kick allo stato Kick e Punch. Considerando pi\u00f9 registrazioni della storia di input come un'unit\u00e0, stiamo fondamentalmente trasformando la sequenza di input in una parte di uno stato intero. Questo ci d\u00e0 la propriet\u00e0 di Markov, permettendoci di utilizzare le catene di Markov per prevedere il prossimo input e indovinare quale mossa combo sar\u00e0 successiva.<\/p>\n<h2>Conclusione<\/h2>\n<p>\nAbbiamo parlato dei pi\u00f9 comuni strumenti e approcci nello sviluppo dell'intelligenza artificiale, analizzando anche le situazioni in cui devono essere applicati e dove sono particolarmente utili. <\/p>\n<p>Questo dovrebbe essere sufficiente per comprendere le nozioni di base sull'IA nei giochi. Tuttavia, sicuramente non \u00e8 tutto. Tra i metodi meno comuni, ma altrettanto efficaci, ci sono:<\/p>\n<ul>\n<li>algoritmi di ottimizzazione, compresi l'ascensione nei colli, il gradiente discendente e gli algoritmi genetici<\/li>\n<li>algoritmi competitivi di ricerca\/pianificazione (minimax e potatura alpha-beta)<\/li>\n<li>metodi di classificazione (perceptron, reti neurali e macchine a vettori di supporto)<\/li>\n<li>sistemi per la gestione della percezione e della memoria degli agenti<\/li>\n<li>approcci architettonici all'IA (sistemi ibridi, sottoinsiemi di architetture e altri metodi di sovrapposizione dei sistemi di IA)<\/li>\n<li>strumenti di animazione (pianificazione e coordinamento del movimento)<\/li>\n<li>fattori di prestazione (livello di dettaglio, algoritmi anytime e timeslicing)<\/li>\n<\/ul>\n<p>\nRisorse online sull'argomento:<\/p>\n<p>1. Su GameDev.net c'\u00e8 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/articles\/programming\/artificial-intelligence\/\">una sezione con articoli e tutorial sull'IA<\/a><\/noindex>, cos\u00ec come <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/forums\/forum\/6-artificial-intelligence\/\">un forum<\/a><\/noindex>.<br \/>\n2. <noindex><a rel=\"nofollow\" href=\"http:\/\/aigamedev.com\/\">AiGameDev.com<\/a><\/noindex> offre molte presentazioni e articoli su un ampio spettro di argomenti legati allo sviluppo dell'IA nei giochi.<br \/>\n3. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gdcvault.com\/\">Il GDC Vault<\/a><\/noindex> include argomenti dal summit GDC AI, molti dei quali sono disponibili gratuitamente.<br \/>\n4. Materiali utili possono essere trovati anche sul sito <noindex><a rel=\"nofollow\" href=\"http:\/\/gameai.com\/\">AI Game Programmers Guild<\/a><\/noindex>.<br \/>\n5. Tommy Thompson, ricercatore di IA e sviluppatore di giochi, realizza video sul canale YouTube <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/tthompso\">AI and Games<\/a><\/noindex> con spiegazioni e analisi dell'IA nei giochi commerciali.<\/p>\n<p>Libri sul tema:<\/p>\n<p>1. La serie di libri Game AI Pro \u00e8 una raccolta di articoli brevi che spiegano come implementare funzioni specifiche o risolvere problemi concreti.<\/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: Collected Wisdom of Game AI Professionals<\/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: Collected Wisdom of Game AI Professionals<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2KF4irS\">Game AI Pro 3: Collected Wisdom of Game AI Professionals<\/a><\/noindex><\/p>\n<p>2. La serie AI Game Programming Wisdom \u00e8 il precursore della serie Game AI Pro. Presenta metodi pi\u00f9 vecchi, ma quasi tutti sono ancora pertinenti oggi.<\/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\">Artificial Intelligence: A Modern Approach<\/a><\/noindex> \u00e8 uno dei testi fondamentali per chiunque voglia comprendere l'ampia area dell'intelligenza artificiale. Questo libro non \u00e8 sulla sviluppo di giochi - insegna le basi dell'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-novosti-interneta"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - 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 \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\" \/>\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\/it\/blog\/novosti-interneta\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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 \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\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/novosti-interneta\/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\udd47 Come creare un'IA per giochi: guida per principianti | ProHoster","description":"Ho trovato materiale interessante sull'intelligenza artificiale nei giochi. Il testo spiega i concetti base dell'IA con esempi semplici e contiene molti strumenti e metodi utili per un suo sviluppo e progettazione agevoli. Sono disponibili anche indicazioni su come, dove e quando utilizzarli. La maggior parte degli esempi \u00e8 scritta in pseudocodice, quindi non \u00e8 necessario avere conoscenze approfondite di programmazione.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/novosti-interneta\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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 \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","og:url":"https:\/\/prohoster.info\/it\/blog\/novosti-interneta\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/52118","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=52118"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/52118\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=52118"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=52118"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=52118"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}