{"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\/da\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","title":{"rendered":"S\u00e5dan skaber du spil-AI: en guide for begyndere","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/9e57175b233a104e0df98383b374eded.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJeg st\u00f8dte p\u00e5 et interessant materiale om kunstig intelligens i spil. Det forklarer de grundl\u00e6ggende begreber om AI med simple eksempler, og det indeholder mange nyttige v\u00e6rkt\u00f8jer og metoder til nem udvikling og design. Der er ogs\u00e5 information om, hvordan, hvor og hvorn\u00e5r man skal bruge dem.<\/p>\n<p>De fleste eksempler er skrevet i pseudokode, s\u00e5 dybe programmeringskundskaber vil ikke v\u00e6re n\u00f8dvendige. Under brudteksten er der 35 sider med billeder og GIF'er, s\u00e5 v\u00e6r forberedt.<\/p>\n<p>UPD. Jeg beklager, men jeg har allerede lavet min egen overs\u00e6ttelse af denne artikel p\u00e5 Habr. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/PatientZero\/\">PatientZero<\/a><\/noindex>. Du kan l\u00e6se hans version <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/420219\/\">her<\/a><\/noindex>, men af en eller anden grund er artiklen g\u00e5et mig forbi (jeg brugte en s\u00f8gning, men noget gik galt). Og eftersom jeg skriver i en blog, der er dedikeret til game development, besluttede jeg at efterlade min egen version af overs\u00e6ttelsen til abonnenterne (nogle punkter er pr\u00e6senteret anderledes af mig, og nogle er bevidst udeladt efter udviklernes r\u00e5d).<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Hvad er AI?<\/h2>\n<p>\nSpil AI fokuserer p\u00e5, hvilke handlinger en enhed skal udf\u00f8re, baseret p\u00e5 de forhold, den befinder sig i. Dette kaldes normalt styring af \"intelligente agenter\", hvor en agent kan v\u00e6re en spilfigur, et k\u00f8ret\u00f8j, en bot eller nogle gange noget mere abstrakt: en hel gruppe enheder eller endda en civilisation. I hvert tilf\u00e6lde er det noget, der skal se sit milj\u00f8, tr\u00e6ffe beslutninger baseret p\u00e5 dette og handle i overensstemmelse hermed. Dette kaldes Sense\/Think\/Act-cyklussen:<\/p>\n<ul>\n<li>Sense: agenten finder eller modtager information om ting i sit milj\u00f8, der kan p\u00e5virke dens adf\u00e6rd (trusler i n\u00e6rheden, genstande til at samle, interessante steder at udforske).<\/li>\n<li>Think: agenten beslutter, hvordan den skal reagere (overvejer, om det er sikkert nok at samle ting eller om den f\u00f8rst skal k\u00e6mpe\/gemme sig).<\/li>\n<li>Act: agenten udf\u00f8rer handlinger for at gennemf\u00f8re den tidligere beslutning (begynder at bev\u00e6ge sig mod modstanderen eller genstanden).<\/li>\n<li>...situationen er nu \u00e6ndret p\u00e5 grund af karakterernes handlinger, s\u00e5 cyklussen gentages med nye data.<\/li>\n<\/ul>\n<p>\nAI fokuserer normalt p\u00e5 Sense-delen af cyklussen. For eksempel tager selvk\u00f8rende biler billeder af vejen, kombinerer dem med radardata og lidar-data og fortolker dem. Dette udf\u00f8res typisk af maskinl\u00e6ring, som behandler de indkommende data og giver dem mening ved at udtr\u00e6kke semantisk information som \"der er en anden bil 20 yards foran dig\". Dette kaldes classification problems.<\/p>\n<p>Spil har ikke brug for et komplekst system til at udtr\u00e6kke information, da st\u00f8rstedelen af dataene allerede er en integreret del af dem. Der er ingen grund til at k\u00f8re billedgenkendelsesalgoritmer for at afg\u00f8re, om der er en fjende foran \u2014 spillet ved det allerede og videregiver oplysningerne direkte i beslutningsprocessen. Derfor er Sense-delen af cyklussen ofte meget simpler end Think og Act.<\/p>\n<h2>Begr\u00e6nsninger for spil-AI<\/h2>\n<p>\nAI har en r\u00e6kke begr\u00e6nsninger, som skal overholdes:<\/p>\n<ul>\n<li>AI skal ikke tr\u00e6nes forud, som det er tilf\u00e6ldet med maskinl\u00e6ringsalgoritmer. Det giver ikke mening at skrive et neuralt netv\u00e6rk under udviklingen for at observere titusindvis af spillere og l\u00e6re den bedste m\u00e5de at spille imod dem. Hvorfor? Fordi spillet ikke er udgivet, og der ikke er nogen spillere.<\/li>\n<li>Spillet skal underholde og udfordre, s\u00e5 agenterne m\u00e5 ikke finde den bedste tilgang mod mennesker.<\/li>\n<li>Agenterne skal se realistiske ud, s\u00e5 spillerne f\u00f8ler, at de spiller imod rigtige mennesker. Programmets AlphaGo overgik mennesker, men de valgte trin var langt fra den traditionelle forst\u00e5else af spillet. Hvis et spil imiterer en menneskelig modstander, b\u00f8r den f\u00f8lelse ikke v\u00e6re der. Algoritmen skal \u00e6ndres, s\u00e5 den tr\u00e6ffer plausible beslutninger og ikke perfekte.<\/li>\n<li>AI skal fungere i realtid. Det betyder, at algoritmen ikke kan monopolere processorens brug i l\u00e6ngere tid til at tr\u00e6ffe beslutninger. Selv 10 millisekunder til dette er for l\u00e6nge, da de fleste spil har brug for 16 til 33 millisekunder for at udf\u00f8re hele behandlingen og g\u00e5 videre til det n\u00e6ste grafiske frame.<\/li>\n<li>Det er ideelt, hvis i det mindste en del af systemet styres af data, s\u00e5 \"non-coders\" kan foretage \u00e6ndringer, og s\u00e5 justeringer kan ske hurtigere.<\/li>\n<\/ul>\n<p>\nLad os se p\u00e5 AI-tilgange, der d\u00e6kker hele cyklussen Sense\/Think\/Act.<\/p>\n<h3>Tr\u00e6ffe grundl\u00e6ggende beslutninger<\/h3>\n<p>\nLad os starte med det enkleste spil - Pong. M\u00e5let er at flytte platformen (paddle), s\u00e5 bolden hopper af den i stedet for at flyve forbi. Det er ligesom tennis, hvor du taber, hvis du ikke sl\u00e5r bolden. Her har AI en relativt let opgave - at beslutte, hvilken retning platformen skal bev\u00e6ges i.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/e1935d657b9f090bf60c365c21e8f92b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Betingede operatorer<\/h3>\n<p>\nFor AI i Pong er den mest \u00e5benlyse l\u00f8sning at fors\u00f8ge at placere platformen under bolden hele tiden.<\/p>\n<p>En simpel algoritme til dette, skrevet i pseudokode:<\/p>\n<p><i>hver ramme\/opdatering mens spillet k\u00f8rer:<br \/>\nhvis bolden er til venstre for paddle:<br \/>\n flyt paddle til venstre<br \/>\nellers hvis bolden er til h\u00f8jre for paddle:<br \/>\n flyt paddle til h\u00f8jre<\/i><\/p>\n<p>Hvis platformen bev\u00e6ger sig med boldens hastighed, s\u00e5 er dette den ideelle algoritme for AI i Pong. Der er ikke behov for at komplicere det, hvis dataene og de mulige handlinger for agenten ikke er s\u00e5 mange.<\/p>\n<p>Denne tilgang er s\u00e5 enkel, at hele cyklen Sense\/Think\/Act knap er m\u00e6rkbar. Men den eksisterer:<\/p>\n<ul>\n<li>Delen Sense findes i de to if-operatorer. Spillet ved, hvor bolden er, og hvor platformen er, s\u00e5 AI henvender sig til det for denne information. <\/li>\n<li>Delen Think inkluderer ogs\u00e5 to if-operatorer. De udtrykker to l\u00f8sninger, som i dette tilf\u00e6lde er gensidigt udelukkende. Som et resultat v\u00e6lges en af tre handlinger - flyt platformen til venstre, flyt platformen til h\u00f8jre, eller g\u00f8r ingenting, hvis den allerede er korrekt placeret.<\/li>\n<li>Delen Act findes i operationerne Flyt Paddle Til Venstre og Flyt Paddle Til H\u00f8jre. Afh\u00e6ngigt af spillets design kan de flytte platformen \u00f8jeblikkeligt eller med en bestemt hastighed. <\/li>\n<\/ul>\n<p>\nS\u00e5danne tilgange kaldes reaktive - der findes et simpelt s\u00e6t regler (i dette tilf\u00e6lde if-operatorer i koden), der reagerer p\u00e5 den aktuelle tilstand af verden og handler.<\/p>\n<h3>Beslutningstr\u00e6<\/h3>\n<p>\nEksemplet med spillet Pong er faktisk lig med den formelle AI-koncept kaldet beslutningstr\u00e6. Algoritmen gennemg\u00e5r det for at n\u00e5 'bladet' - beslutningen om, hvilken handling der skal tages.<\/p>\n<p>Lad os lave et flowchart til beslutningstr\u00e6et for vores platforms algoritme:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/d3b7290ba93144967cd849416cd5eef3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nHver del af tr\u00e6et kaldes en node - AI bruger grafteori til at beskrive s\u00e5danne strukturer. Der er to typer noder:<\/p>\n<ul>\n<li>Beslutningsnoder: valg mellem to alternativer baseret p\u00e5 kontrol af en betingelse, hvor hvert alternativ pr\u00e6senteres som en separat node.<\/li>\n<li>Terminalnoder: en handling, der skal udf\u00f8res, som repr\u00e6senterer den endelige beslutning.<\/li>\n<\/ul>\n<p>\nAlgoritmen begynder med den f\u00f8rste node ('roden' af tr\u00e6et). Den tr\u00e6ffer enten en beslutning om, hvilken datternode der skal g\u00e5 til, eller udf\u00f8rer den handling, der er gemt i noden, og afsluttes.<\/p>\n<p>Hvad er fordelene, hvis beslutningstr\u00e6et udf\u00f8rer det samme arbejde som if-operatorer i det forg\u00e5ende afsnit? Her er der et generelt system, hvor hver beslutning kun har \u00e9n betingelse og to mulige resultater. Dette g\u00f8r det muligt for udvikleren at skabe AI baseret p\u00e5 data, der repr\u00e6senterer beslutninger i tr\u00e6et, og undg\u00e5 hardcoding. Lad os forestille os det i form af en tabel:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/6875293a60ff9d0efa26fb5e1aa4b21c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00e5 kodens side f\u00e5r du et system til at l\u00e6se r\u00e6kker. Opret en node for hver af dem, tilslut beslutningstagning logikken baseret p\u00e5 den anden kolonne og datterknuderne baseret p\u00e5 den tredje og fjerde kolonne. Du skal stadig programmere betingelser og handlinger, men nu vil spilstrukturen v\u00e6re mere kompleks. I den tilf\u00f8jer du flere beslutninger og handlinger, og derefter justerer du hele AI'en blot ved at redigere en tekstfil med definitionen af tr\u00e6et. Derefter overleveres filen til spildesigneren, som vil kunne \u00e6ndre adf\u00e6rden uden at recompilere spillet og \u00e6ndre koden.<\/p>\n<p>Beslutningstr\u00e6er er meget nyttige, n\u00e5r de automatisk genereres baseret p\u00e5 et stort antal eksempler (f.eks. ved hj\u00e6lp af ID3-algoritmen). Dette g\u00f8r dem til et effektivt og h\u00f8jtydende v\u00e6rkt\u00f8j til klassificering af situationer baseret p\u00e5 indsamlede data. Men vi g\u00e5r ud over et simpelt system til at v\u00e6lge handlinger for agenter.<\/p>\n<h3>Scenarier<\/h3>\n<p>\nVi har gennemg\u00e5et systemet for beslutningstr\u00e6et, som brugte foruddefinerede betingelser og handlinger. Mennesket, der designer AI, kan organisere tr\u00e6et, som de \u00f8nsker, men de skal stadig stole p\u00e5 koderen, der programmerede det hele. Hvad hvis vi kunne give designeren v\u00e6rkt\u00f8jerne til at skabe deres egne betingelser eller handlinger?<\/p>\n<p>For at programm\u00f8ren ikke skal skrive kode for betingelserne Is Ball Left Of Paddle og Is Ball Right Of Paddle, kan han lave et system, hvor designeren vil indtaste betingelser for at kontrollere disse v\u00e6rdier. S\u00e5 ville dataene i beslutningstr\u00e6et se s\u00e5dan ud:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/8e77f7c3410d097e8b7d8e1209355cc6.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI bundet er det dybest set det samme som i den f\u00f8rste tabel, men l\u00f8sningerne har deres egen kode, der ligner den betingede del af en if-s\u00e6tning. I koden ville dette blive l\u00e6st i den anden kolonne for beslutningstagningsnoder, men i stedet for at lede efter en specifik betingelse for at udf\u00f8re (Is Ball Left Of Paddle) vurderer det det betingede udtryk og returnerer true eller false. Dette g\u00f8res med scripting-sproget Lua eller Angelscript. Ved hj\u00e6lp af disse kan udvikleren tage objekter i sit spil (bold og paddle) og oprette variable, der vil v\u00e6re tilg\u00e6ngelige i scriptet (ball.position). Desuden er scriptsproget enklere end C++. Det kr\u00e6ver ikke en fuld kompilering, hvilket g\u00f8r det ideelt til hurtige justeringer af spilogikken og giver \"ikke-programm\u00f8rer\" mulighed for at oprette de \u00f8nskede funktioner selv.<\/p>\n<p>I det givne eksempel bruges scripting-sproget kun til at vurdere det betingede udtryk, men det kan ogs\u00e5 bruges til handlinger. For eksempel kan dataene Move Paddle Right blive til en scripting-operator (ball.position.x += 10). P\u00e5 den m\u00e5de bestemmes handlingen ogs\u00e5 i scriptet, uden at det er n\u00f8dvendigt at kode Move Paddle Right.<\/p>\n<p>Man kan g\u00e5 endnu l\u00e6ngere og skrive hele beslutningstr\u00e6et i et scriptsprog. Dette vil v\u00e6re kode i form af hardcoded betingede operatorer, men de vil befinde sig i eksterne scriptfiler, dvs. de kan \u00e6ndres uden at genkompilere hele programmet. Ofte kan man \u00e6ndre scriptfilen midt i spillet for hurtigt at teste forskellige AI-reaktioner.<\/p>\n<h3>Reagering p\u00e5 begivenheder<\/h3>\n<p>\nEksemplerne ovenfor passer perfekt til Pong. De k\u00f8rer konstant en cyklus af Sense\/Think\/Act og handler baseret p\u00e5 den seneste tilstand af verden. Men i mere komplekse spil skal man reagere p\u00e5 enkeltbegivenheder i stedet for at evaluere alt p\u00e5 \u00e9n gang. Pong er i s\u00e5 fald ikke et ideelt eksempel. Lad os v\u00e6lge et andet. <\/p>\n<p>Forestil dig en shooter, hvor fjenderne er stille, indtil de opdager spilleren, hvorefter de handler afh\u00e6ngigt af deres \u201especialisering\u201d: nogle vil \u201erush\u201d, mens andre vil angribe p\u00e5 afstand. Dette er stadig et grundl\u00e6ggende reaktionssystem \u2014 \u201ehvis spilleren ses, s\u00e5 g\u00f8r noget\u201d \u2014 men det kan logisk opdeles i begivenheden Player Seen (spilleren set) og reaktionen (v\u00e6lg en respons og udf\u00f8r den).<\/p>\n<p>Dette bringer os tilbage til cyklussen Sense\/Think\/Act. Vi kan kode Sense-delen, som vil tjekke i hver ramme \u2014 om AI'en kan se spilleren. Hvis ikke, sker der ikke noget, men hvis den kan se spilleren, oprettes der en begivenhed kaldet Player Seen. Koden vil have en sektion, der siger: \"n\u00e5r begivenheden Player Seen indtr\u00e6ffer, s\u00e5 g\u00f8r \", hvor  er det svar, du har brug for for at kommunikere med delene Think og Act. P\u00e5 den m\u00e5de konfigurerer du reaktionerne p\u00e5 begivenheden Player Seen: for en 'rushende' karakter \u2014 ChargeAndAttack, og for en snigskytte \u2014 HideAndSnipe. Disse forbindelser kan oprettes i en datafil til hurtig redigering uden behov for at kompilere p\u00e5 ny. Og her kan man ogs\u00e5 bruge scriptsprog.<\/p>\n<h2>At tr\u00e6ffe komplekse beslutninger<\/h2>\n<p>\nSelvom enkle reaktionssystemer er meget effektive, er der mange situationer, hvor de ikke er tilstr\u00e6kkelige. Nogle gange skal man tr\u00e6ffe forskellige beslutninger baseret p\u00e5, hvad agenten g\u00f8r lige nu, men det er sv\u00e6rt at repr\u00e6sentere dette som en betingelse. Nogle gange er der for mange betingelser til effektivt at repr\u00e6sentere dem i et beslutningstr\u00e6 eller script. Nogle gange skal man p\u00e5 forh\u00e5nd vurdere, hvordan situationen vil \u00e6ndre sig, f\u00f8r man tr\u00e6ffer en beslutning om n\u00e6ste skridt. For at l\u00f8se disse problemer kr\u00e6ves mere komplekse tilgangsformer.<\/p>\n<h3>Endelig tilstandsmaskine<\/h3>\n<p>\nEndelig tilstandsmaskine eller FSM (finite state machine) \u2014 det er en metode til at angive, at vores agent i \u00f8jeblikket er i en af flere mulige tilstande, og at den kan skifte fra en tilstand til en anden. Antallet af s\u00e5danne tilstande er begr\u00e6nset \u2014 deraf navnet. Det bedste virkelige eksempel er et trafiklys. I forskellige steder er der forskellige lyssekvenser, men princippet er det samme \u2014 hver tilstand repr\u00e6senterer noget (stop, g\u00e5 osv.). Trafiklyset er kun i \u00e9n tilstand ad gangen og skifter fra \u00e9n tilstand til en anden baseret p\u00e5 enkle regler.<\/p>\n<p>Med NPC'er i spil er historien ens. Lad os tage en vagt med f\u00f8lgende tilstande:<\/p>\n<ul>\n<li>Patruljerende (Patrolling).<\/li>\n<li>Angrebende (Attacking).<\/li>\n<li>Flygter (Fleeing).<\/li>\n<\/ul>\n<p>\nOg med f\u00f8lgende betingelser for at \u00e6ndre dens tilstand:<\/p>\n<ul>\n<li>Hvis vagten ser en fjende, angriber den.<\/li>\n<li>Hvis vagten angriber, men ikke l\u00e6ngere ser fjenden, vender den tilbage til patruljering.<\/li>\n<li>Hvis vagten angriber, men er alvorligt s\u00e5ret, flygter den.<\/li>\n<\/ul>\n<p>\nDu kan ogs\u00e5 skrive if-s\u00e6tninger med en vagtstate-variabel og forskellige kontroller: er der en fjende i n\u00e6rheden, hvad er NPC'ens sundhedsniveau osv. Lad os tilf\u00f8je et par flere tilstande:<\/p>\n<ul>\n<li>Inaktivitet (Idling) \u2014 mellem patruljeringer.<\/li>\n<li>S\u00f8gning (Searching) \u2014 n\u00e5r en observeret fjende er forsvundet.<\/li>\n<li>Be om hj\u00e6lp (Finding Help) \u2014 n\u00e5r fjenden er bem\u00e6rket, men for st\u00e6rk til at k\u00e6mpe imod alene.<\/li>\n<\/ul>\n<p>\nValget for hver af dem er begr\u00e6nset \u2014 for eksempel vil vagten ikke s\u00f8ge efter den skjulte fjende, hvis hans helbred er lavt.<\/p>\n<p>I sidste ende kan en massiv liste over &quot;hvis&quot; &lt;x \u0438 y, \u043d\u043e \u043d\u0435 z&gt;, s&aring; &lt;p&gt;&quot;, blive alt for uoverskuelig, s&aring; vi b&oslash;r formaliserer en metode, der g&oslash;r det muligt for os at huske tilstandene og overgange mellem tilstande. For at g&oslash;re dette, lad os tage h&oslash;jde for alle tilstande, og under hver tilstand notere en liste over alle overgange til andre tilstande, sammen med de n&oslash;dvendige betingelser for dem.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/ba4c401aa20de3d22d2478cba5a4b1ec.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDette er en overgangstabel for tilstande \u2014 en kompleks m\u00e5de at repr\u00e6sentere FSM p\u00e5. Lad os tegne et diagram og f\u00e5 et klart overblik over, hvordan NPC'ens adf\u00e6rd \u00e6ndrer sig.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/b4182359983cf573872dacc575af13dc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDiagrammet afspejler essensen af beslutningstagning for denne agent baseret p\u00e5 den aktuelle situation. Hver pil viser en overgang mellem tilstande, hvis betingelsen ved siden af er sand.<\/p>\n<p>Ved hver opdatering tjekker vi agentens nuv\u00e6rende tilstand, gennemg\u00e5r overgange, og hvis betingelserne for en overgang opfyldes, tager den en ny tilstand. For eksempel, hver frame tjekkes det, om 10-sekunders timeren er udl\u00f8bet, og hvis ja, g\u00e5r vagten fra Idling til Patrolling. P\u00e5 samme m\u00e5de tjekker tilstanden Attacking agentens helbred \u2014 hvis det er lavt, skifter den til tilstanden Fleeing.<\/p>\n<p>Dette er behandling af overgange mellem tilstande, men hvad med adf\u00e6rden knyttet til selve tilstandene? N\u00e5r det kommer til implementationen af den faktiske adf\u00e6rd for en specifik tilstand, eksisterer der typisk to typer 'hooks', hvor vi tildeler handlinger til FSM:<\/p>\n<ul>\n<li>Handlinger, som vi periodisk udf\u00f8rer for den nuv\u00e6rende tilstand.<\/li>\n<li>Handlinger, som vi foretager, n\u00e5r vi skifter fra en tilstand til en anden.<\/li>\n<\/ul>\n<p>\nEksempler p\u00e5 den f\u00f8rste type. Tilstanden Patrolling vil hver frame bev\u00e6ge agenten langs patruljeruten. Tilstanden Attacking vil hver frame fors\u00f8ge at starte et angreb eller skifte til en tilstand, n\u00e5r det er muligt.<\/p>\n<p>For the second type, let's consider the transition 'if the enemy is visible and the enemy is too strong, then switch to the Finding Help state. The agent must choose where to go for help and retain this information so that the Finding Help state knows where to turn. Once help is found, the agent transitions back to the Attacking state. At this point, he will want to inform an ally about the threat, so an action NotifyFriendOfThreat may occur.<\/p>\n<p>Once again, we can look at this system through the lens of the Sense\/Think\/Act cycle. Sense is embodied in the data used by the transition logic. Think consists of the transitions available in each state. Act is executed through actions performed periodically within the state or during transitions between states.<\/p>\n<p>Sometimes continuous polling of transition conditions can be costly. For example, if each agent performs complex calculations every frame to determine if they see enemies and whether they can transition from Patrolling to Attacking state \u2014 it will consume a lot of processor time. <\/p>\n<p>Important changes in the state of the world can be viewed as events that will be processed as they arise. Instead of the FSM checking the transition condition 'can my agent see the player?' every frame, a separate system can be set up to perform checks less frequently (for example, 5 times a second). The result can then yield a Player Seen when the check passes. <\/p>\n<p>This is passed to the FSM, which now needs to transition to the condition Player Seen event received and react accordingly. The final behavior remains the same except for an almost imperceptible delay before the response. However, performance has improved as a result of separating part of the Sense into a separate part of the program.<\/p>\n<h3>Hierarkisk finite state machine<\/h3>\n<p>\nHowever, working with large FSMs is not always convenient. If we want to expand the attack state by separating it into MeleeAttacking (close combat) and RangedAttacking (ranged combat), we will have to change the transitions from all other states that lead to the Attacking state (both current and future).<\/p>\n<p>Du har sikkert bem\u00e6rket, at der i vores eksempel er mange duplikerede overgange. De fleste overgange i tilstanden Idling er identiske med overgange i tilstanden Patrolling. Det ville v\u00e6re godt ikke at gentage os selv, is\u00e6r hvis vi tilf\u00f8jer flere lignende tilstande. Det giver mening at gruppere Idling og Patrolling under et f\u00e6lles m\u00e6rkat \"ikke-kamp\", hvor der kun er et f\u00e6lles s\u00e6t overgange til kamptilstande. Hvis vi betragter dette m\u00e6rkat som en tilstand, vil Idling og Patrolling blive undertilstande. Et eksempel p\u00e5 brug af en separat overgangstabel for den nye ikke-kamp undertilstand:<\/p>\n<p><i>Prim\u00e6re tilstande:<\/i><br \/>\n<img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/d86dd918acbe81b9bf22c2fb34aecee3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<i>Tilstand uden kamp:<\/i><br \/>\n<img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/9d5bc2053010a32c5f68d7f0192c04ed.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOg i form af et diagram:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/0ccf95ecafa9ce2a6ea5b5b9833ddc4f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDet er det samme system, men med en ny ikke-kamp tilstand, der inkluderer Idling og Patrolling. Hver tilstand indeholder en FSM med undertilstande (og disse undertilstande kan i sig selv indeholde deres egne FSM'er \u2014 og s\u00e5 videre s\u00e5 mange som du har brug for), vi f\u00e5r Hierarchical Finite State Machine eller HFSM (hierarkisk endelig automat). Ved at gruppere den ikke-kamp tilstand, skar vi en masse overfl\u00f8dige overgange v\u00e6k. Det samme kan g\u00f8res for enhver ny tilstand med f\u00e6lles overgange. For eksempel, hvis vi i fremtiden udvider tilstanden Attacking til tilstandene MeleeAttacking og MissileAttacking, vil de v\u00e6re undertilstande, der skifter imellem hinanden baseret p\u00e5 afstanden til fjenden og tilg\u00e6ngeligheden af ammunition. I sidste ende kan komplekse adf\u00e6rdsm\u00f8nstre og adf\u00e6rdssubmodeller pr\u00e6senteres med et minimum af duplikerede overgange.<\/p>\n<h3>Adf\u00e6rdstr\u00e6<\/h3>\n<p>\nMed HFSM skabes komplekse kombinationer af adf\u00e6rd p\u00e5 en enkel m\u00e5de. Der er imidlertid en lille udfordring; beslutningstagning i form af overgangsregler er t\u00e6t knyttet til den nuv\u00e6rende tilstand. Og i mange spil er det netop det, der er n\u00f8dvendigt. Omhyggelig brug af tilstandshierarkiet kan reducere antallet af gentagelser ved overgange. Men nogle gange har man brug for regler, der fungerer uafh\u00e6ngigt af, hvilken tilstand du er i, eller som kan anvendes i n\u00e6sten alle tilstande. For eksempel, hvis agentens sundhed falder til 25%, \u00f8nsker du, at han skal flygte uanset om han har v\u00e6ret i kamp, v\u00e6ret inaktiv eller talt \u2014 du bliver n\u00f8dt til at tilf\u00f8je denne betingelse i hver tilstand. Og hvis din designer senere \u00f8nsker at \u00e6ndre t\u00e6rsklen for lav sundhed fra 25% til 10%, skal der igen arbejdes med dette.<\/p>\n<p>Ideelt set kr\u00e6ver denne situation et system, hvor beslutninger om \"hvilken tilstand man skal v\u00e6re i\" ligger uden for tilstandene selv, s\u00e5 \u00e6ndringer kun skal foretages \u00e9t sted uden at r\u00f8re ved overgangsbetingelserne. Her kommer adf\u00e6rds-tr\u00e6er ind i billedet.<\/p>\n<p>Der er flere m\u00e5der at implementere dem p\u00e5, men essensen er stort set den samme og ligner et beslutningstr\u00e6: algoritmen starter med en \"rod\"-node, og i tr\u00e6et findes noder, der repr\u00e6senterer enten beslutninger eller handlinger. Der er dog nogle v\u00e6sentlige forskelle:<\/p>\n<ul>\n<li>Nu returnerer noderne en af tre v\u00e6rdier: Succeeded (hvis arbejdet er udf\u00f8rt), Failed (hvis det ikke kan startes) eller Running (hvis det stadig k\u00f8rer og der ikke er et endeligt resultat).<\/li>\n<li>Der er ikke l\u00e6ngere beslutningsnoder til at v\u00e6lge mellem to alternativer. I stedet er der Decorator-noder, som har en enkelt datterenode. Hvis de lykkes, udf\u00f8rer de deres eneste datterenode.<\/li>\n<li>Noder, der udf\u00f8rer handlinger, returnerer v\u00e6rdien Running for at repr\u00e6sentere igangv\u00e6rende handlinger.<\/li>\n<\/ul>\n<p>\nDette lille udvalg af noder kan kombineres for at skabe et stort antal komplekse adf\u00e6rdsmodeller. Lad os forestille os HFSM-vagten fra det forrige eksempel som et adf\u00e6rds-tr\u00e6:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/5eaa5c725e4ada8285f16f95bb206d53.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMed denne struktur skal der ikke v\u00e6re nogen \u00e5benlyse overgange fra tilstandene Idling\/Patrolling til tilstanden Attacking eller andre. Hvis fjenden er synlig, og karakterens helbred er lavt, vil udf\u00f8relsen stoppe ved noden Fleeing, uanset hvilken node den tidligere har k\u00f8RT \u2014 Patrolling, Idling, Attacking eller en anden.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/e1c1dcc2055174aa7cfa846364b1709a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAdf\u00e6rdstr\u00e6er er komplekse \u2014 der er mange m\u00e5der at konstruere dem p\u00e5, og det kan v\u00e6re problematisk at finde den rigtige kombination af dekoratorer og sammensatte noder. Der er ogs\u00e5 sp\u00f8rgsm\u00e5l om, hvor ofte man skal kontrollere tr\u00e6et \u2014 vil vi gerne gennemg\u00e5 det hver del, eller kun n\u00e5r en af betingelserne \u00e6ndres? Hvordan gemmer man tilstanden, der relaterer sig til noderne \u2014 hvordan kan man vide, hvorn\u00e5r vi har v\u00e6ret i tilstanden Idling i 10 sekunder, eller hvordan kan man vide, hvilke noder der blev udf\u00f8rt sidst for at behandle sekvenserne korrekt?<\/p>\n<p>Netop derfor findes der mange implementationer. For eksempel har nogle systemer dekorator-noder erstattet med indbyggede dekoratorer. De evaluerer tr\u00e6et igen, n\u00e5r dekatorbetingelserne \u00e6ndres, hj\u00e6lper med at tilslutte noder og giver periodiske opdateringer.<\/p>\n<h3>Utility-baseret system<\/h3>\n<p>\nNogle spil har mange forskellige mekanikker. Det er \u00f8nskeligt, at de f\u00e5r alle fordelene ved enkle og generelle overgangspunktregler, men det er ikke n\u00f8dvendigt i form af et fuldt adf\u00e6rdsdiagram. I stedet for at have et klart s\u00e6t valg eller et tr\u00e6 af mulige handlinger er det lettere at l\u00e6re alle handlinger at kende og v\u00e6lge den mest passende i det givne \u00f8jeblik.<\/p>\n<p>Et system baseret p\u00e5 nytte (utility-based system) hj\u00e6lper netop med dette. Det er et system, hvor agenten har mange handlinger at v\u00e6lge imellem, og selv v\u00e6lger hvilken der skal udf\u00f8res, baseret p\u00e5 den relative nytte af hver handling. Hvor nytte er et vilk\u00e5rligt m\u00e5l for, hvor vigtigt eller \u00f8nskeligt det er for agenten at udf\u00f8re denne handling. <\/p>\n<p>Den beregnede nytte af en handling baseret p\u00e5 den nuv\u00e6rende tilstand og milj\u00f8 kan agenten kontrollere og v\u00e6lge det mest passende alternative tilstand n\u00e5r som helst. Det ligner en FSM, bortset fra at overgange defineres af vurderingen af hver potentiel tilstand, inklusive den nuv\u00e6rende. Bem\u00e6rk, at vi v\u00e6lger den mest nyttige handling til at overg\u00e5 (eller bliver, hvis vi allerede har udf\u00f8rt den). For at skabe st\u00f8rre variation kan det v\u00e6re et v\u00e6gtet, men tilf\u00e6ldigt valg fra en lille liste.<\/p>\n<p>Systemet tildeler et vilk\u00e5rligt interval af nyttev\u00e6rdier - for eksempel fra 0 (helt u\u00f8nsket) til 100 (fuldt \u00f8nsket). Hver handling har en r\u00e6kke parametre, der p\u00e5virker beregningen af denne v\u00e6rdi. Tilbage til vores eksempel med vagten:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/085fb2c197bde93d78455d18e63c9c25.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nOvergange mellem handlinger er flertydige - enhver tilstand kan f\u00f8lge efter enhver anden. Prioriteterne for handlinger findes i de returnerede nyttev\u00e6rdier. Hvis fjenden er synlig, og denne fjende er st\u00e6rk, mens karakterens helbred er lavt, vil b\u00e5de Fleeing og FindingHelp returnere h\u00f8je, ikke-nul v\u00e6rdier. Her vil FindingHelp dog altid v\u00e6re h\u00f8jere. P\u00e5 samme m\u00e5de returnerer ikke-kamphandlinger aldrig mere end 50, s\u00e5 de vil altid v\u00e6re lavere end kamphandlinger. Dette skal tages i betragtning ved oprettelsen af handlinger og beregningen af deres nytte.<\/p>\n<p>I vores eksempel returnerer handlingerne enten en fast konstant v\u00e6rdi eller en af to faste v\u00e6rdier. Et mere realistisk system foruds\u00e6tter, at der returneres en vurdering fra et kontinuerligt interval af v\u00e6rdier. For eksempel returnerer handlingen Fleeing h\u00f8jere nyttev\u00e6rdier, hvis agentens helbred er lavt, mens handlingen Attacking returnerer lavere, hvis fjenden er for st\u00e6rk. P\u00e5 grund af dette har handlingen Fleeing forrang over Attacking i enhver situation, hvor agenten f\u00f8ler, at der ikke er tilstr\u00e6kkeligt helbred til at overvinde modstanderen. Dette giver mulighed for at \u00e6ndre prioriteterne for handlinger baseret p\u00e5 et vilk\u00e5rligt antal kriterier, hvilket g\u00f8r denne tilgang mere fleksibel og variabel end adf\u00e6rdstr\u00e6er eller FSM.<\/p>\n<p>Hver handling har mange betingelser for at beregne programmet. De kan skrives i scriptsprog eller som en r\u00e6kke matematiske formler. I The Sims, som modellerer en karakters dagligdag, tilf\u00f8jes der et ekstra niveau af beregninger \u2014 agenten modtager en r\u00e6kke 'motivationer', der p\u00e5virker nyttevurderingerne. Hvis karakteren er sulten, vil den over tid blive endnu mere sulten, og nyttev\u00e6rdien af handlingen EatFood vil stige, indtil karakteren udf\u00f8rer den, hvilket reducerer sulten og bringer v\u00e6rdien af EatFood tilbage til nul. <\/p>\n<p>Id\u00e9en om at v\u00e6lge handlinger baseret p\u00e5 et vurderingssystem er ret simpel, s\u00e5 et nyttebaseret system kan bruges som del af AI-beslutningsprocesser, snarere end som en fuldst\u00e6ndig erstatning. Beslutningstr\u00e6et kan anmode om en nyttevurdering af to undernoder og v\u00e6lge den h\u00f8jere. P\u00e5 samme m\u00e5de kan adf\u00e6rdstr\u00e6et have en sammensat nytte-knude til at vurdere nyttev\u00e6rdien af handlinger for at beslutte, hvilken underenhed der skal udf\u00f8res.<\/p>\n<h2>Bev\u00e6gelse og navigation<\/h2>\n<p>\nI de tidligere eksempler havde vi en platform, som vi bev\u00e6gede til venstre eller h\u00f8jre, og en vagt, der patruljerede eller angreb. Men hvordan h\u00e5ndterer vi faktisk agentens bev\u00e6gelse over en bestemt tid? Hvordan fasts\u00e6tter vi hastigheden, hvordan undg\u00e5r vi forhindringer, og hvordan planl\u00e6gger vi ruten, hvis det er sv\u00e6rere at n\u00e5 destinationen end blot at bev\u00e6ge sig lige frem? Lad os tage et kig p\u00e5 det.<\/p>\n<h3>Administration<\/h3>\n<p>\nI starten antager vi, at hver agent har en hastighedsv\u00e6rdi, som inkluderer, hvor hurtigt den bev\u00e6ger sig, og i hvilken retning. Den kan m\u00e5les i meter pr. sekund, kilometer i timen, pixels pr. sekund osv. N\u00e5r vi husker cyklussen Sense\/T\u00e6nke\/Handle, kan vi forestille os, at en del af T\u00e6nke v\u00e6lger hastighed, mens en del af Handle anvender denne hastighed p\u00e5 agenten. Normalt er der i spil et fysiksystem, der udf\u00f8rer denne opgave for dig ved at studere hastighedsv\u00e6rdien af hver objekt og justere den. Derfor kan AI efterlades med \u00e9n opgave \u2014 at beslutte, hvilken hastighed agenten skal have. Hvis det er kendt, hvor agenten skal v\u00e6re, skal den flyttes i den rigtige retning med den angivne hastighed. Et meget trivielt ligning:<\/p>\n<p><i>desired_travel = destination_position \u2013 agent_position<\/i><\/p>\n<p>Forestil dig en 2D-verden. Agenten er i punktet (-2,-2), destinationspunktet ligger et sted mod nord\u00f8st i punktet (30, 20), og den n\u00f8dvendige vej for agenten at n\u00e5 dertil er (32, 22). Antag, at disse positioner m\u00e5les i meter \u2014 hvis vi tager hastigheden for agenten som 5 meter pr. sekund, vil vi skalere vores bev\u00e6gelsesvektor og f\u00e5 en hastighed p\u00e5 cirka (4.12, 2.83). Med disse parametre ville agenten n\u00e5 destinationen om n\u00e6sten 8 sekunder.<\/p>\n<p>V\u00e6rdierne kan genberegnes n\u00e5r som helst. Hvis agenten er halvvejs til m\u00e5let, vil bev\u00e6gelsen v\u00e6re halvdelen af l\u00e6ngden, men da agentens maksimale hastighed er 5 m\/s (som vi har besluttet ovenfor), vil hastigheden v\u00e6re den samme. Dette fungerer ogs\u00e5 for bev\u00e6gende m\u00e5l, hvilket giver agenten mulighed for at foretage sm\u00e5 justeringer, mens de bev\u00e6ger sig.<\/p>\n<p>Men vi \u00f8nsker mere variabilitet \u2014 for eksempel langsomt at \u00f8ge hastigheden for at simulere en karakter, der bev\u00e6ger sig fra stillest\u00e5ende til l\u00f8b. Det samme kan g\u00f8res i slutningen f\u00f8r stop. Disse funktioner kaldes steering behaviours, hver med specifikke navne: Seek (s\u00f8ge), Flee (flygte), Arrival (ankomst) osv. Ideen er, at accelerationskr\u00e6fter kan anvendes p\u00e5 agentens hastighed, baseret p\u00e5 sammenligning af agentens position og nuv\u00e6rende hastighed med destinationspunktet, for at bruge forskellige m\u00e5der at bev\u00e6ge sig mod m\u00e5let.<\/p>\n<p>Hver adf\u00e6rd har et lidt andet form\u00e5l. Seek og Arrival er m\u00e5der at flytte agenten til en destination. Obstacle Avoidance (undg\u00e5else af forhindringer) og Separation (adskillelse) justerer agentens bev\u00e6gelse for at undg\u00e5 forhindringer p\u00e5 vejen mod m\u00e5let. Alignment (justering) og Cohesion (sammenhold) holder agenterne sammen, n\u00e5r de bev\u00e6ger sig. Ethvert antal forskellige steering behaviours kan summere til en enkelt banevektor, der tager h\u00f8jde for alle faktorer. En agent, der bruger adf\u00e6rd som Arrival, Separation og Obstacle Avoidance for at holde sig v\u00e6k fra v\u00e6gge og andre agenter. Denne tilgang fungerer godt i \u00e5bne omr\u00e5der uden for mange detaljer. <\/p>\n<p>Under sv\u00e6rere forhold fungerer summen af forskellige adf\u00e6rd d\u00e5rligere \u2014 for eksempel kan en agent sidde fast i en v\u00e6g p\u00e5 grund af konflikten mellem Arrival og Obstacle Avoidance. Derfor er det n\u00f8dvendigt at overveje muligheder, der er mere komplekse end blot at summere alle v\u00e6rdier. En metode er: i stedet for at summere resultaterne fra hver adf\u00e6rd, kan man overveje bev\u00e6gelse i forskellige retninger og v\u00e6lge den bedste mulighed. <\/p>\n<p>Men i et komplekst milj\u00f8 med blindgader og valg om, hvilken retning man skal g\u00e5, har vi brug for noget endnu mere avanceret.<\/p>\n<h3>S\u00f8gevej<\/h3>\n<p>\nSteering behaviours er ideelle til simpel bev\u00e6gelse p\u00e5 \u00e5bne omr\u00e5der (fodboldbane eller arena), hvor det at komme fra A til B er en direkte vej med sm\u00e5 afvigelser forbi forhindringer. For komplekse ruter har vi brug for pathfinding (vejfinding), som er en metode til at udforske verden og tr\u00e6ffe beslutninger om ruten gennem den.<\/p>\n<p>Den mest enkle m\u00e5de er at l\u00e6gge et net over hvert kvadrat ved siden af agenten og vurdere, hvilke der er tilladt at bev\u00e6ge sig ind i. Hvis et af dem er bestemmelsesstedet, skal du f\u00f8lge vejen fra hvert kvadrat tilbage til det forrige, indtil du n\u00e5r starten. Det er ruten. Ellers gentag processen med de n\u00e6rmeste andre kvadrater, indtil du finder bestemmelsesstedet eller l\u00f8ber t\u00f8r for kvadrater (hvilket betyder, at der ikke er nogen mulig rute). Dette er formelt kendt som Breadth-First Search eller BFS (bredde-f\u00f8rst s\u00f8gning). P\u00e5 hvert trin ser den i alle retninger (deraf breadth, 'bredde'). S\u00f8geomr\u00e5det ligner en b\u00f8lgefront, der bev\u00e6ger sig, indtil den n\u00e5r det \u00f8nskede sted - s\u00f8geomr\u00e5det udvider sig ved hvert skridt, indtil det n\u00e5r slutpunktet, hvorefter vejen tilbage til starten kan spores.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/d367e62bc53033b05388538649853a41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSom resultat f\u00e5r du en liste over kvadrater, der udg\u00f8r den \u00f8nskede rute. Det er vejen (deraf pathfinding) - en liste over steder, som agenten vil bes\u00f8ge, mens den bev\u00e6ger sig mod bestemmelsen.<\/p>\n<p>I betragtning af at vi kender positionen af hvert kvadrat i verden, kan vi bruge steering behaviours til at bev\u00e6ge os langs ruten - fra node 1 til node 2, derefter fra node 2 til node 3 og s\u00e5 videre. Den enkleste tilgang er at styre mod midten af det n\u00e6ste kvadrat, men det er endnu bedre at stoppe ved midten af kanten mellem det aktuelle kvadrat og det n\u00e6ste. Dette g\u00f8r det muligt for agenten at sk\u00e6re hj\u00f8rnerne p\u00e5 skarpe sving.<\/p>\n<p>BFS-algoritmen har ogs\u00e5 ulemper - den unders\u00f8ger lige s\u00e5 mange kvadrater i den 'forkerte' retning som i den 'rette'. Her introduceres en mere kompleks algoritme kaldet A* (A stjerne). Den fungerer p\u00e5 samme m\u00e5de, men i stedet for blindt at unders\u00f8ge nabokvadrater (derefter nabokvadraternes naboer, s\u00e5 naboernes naboer osv.), samler den noder i en liste og sorterer dem, s\u00e5 den n\u00e6ste unders\u00f8gte node altid er den, der vil f\u00f8re til den korteste rute. Noderne sorteres baseret p\u00e5 en heuristik, der tager h\u00f8jde for to ting - 'omkostningerne' ved den hypotetiske rute til det \u00f8nskede kvadrat (herunder eventuelle omkostninger ved bev\u00e6gelse) og en vurdering af, hvor langt dette kvadrat er fra bestemmelsesstedet (ved at lede s\u00f8gningen i den rigtige retning).<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/1cab4f53fa5af6b31d352c7bcf453d7e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI dette eksempel ses det, at agenten unders\u00f8ger \u00e9n sektion ad gangen og hver gang v\u00e6lger den mest lovende nabosektion. Den resulterende sti er den samme som ved BFS, men f\u00e6rre sektioner er blevet overvejet undervejs - og det har stor betydning for spillets ydeevne.<\/p>\n<h3>Bev\u00e6gelse uden net<\/h3>\n<p>\nMen de fleste spil er ikke opdelt i net, og det er ofte umuligt at g\u00f8re det uden at skade realismen. Kompromiser er n\u00f8dvendige. Hvad skal st\u00f8rrelsen p\u00e5 sektionerne v\u00e6re? Hvis de er for store, kan de ikke korrekt repr\u00e6sentere sm\u00e5 gange eller sving; hvis de er for sm\u00e5, vil der v\u00e6re alt for mange sektioner at s\u00f8ge i, hvilket til sidst tager en masse tid.<\/p>\n<p>Det f\u00f8rste, man skal forst\u00e5, er, at nettet giver os et graf over forbundet noder. A* og BFS algoritmer arbejder reelt med grafer og bekymrer sig slet ikke om vores net. Vi kunne placere noder hvor som helst i spillets verden: hvis der er forbindelse mellem to tilsluttede noder samt mellem start- og slutpunktet og mindst \u00e9n af noderne, s\u00e5 vil algoritmen fungere lige s\u00e5 godt som f\u00f8r. Dette kaldes ofte et waypoint-system, da hver node repr\u00e6senterer en betydningsfuld position i verden, der kan v\u00e6re del af et uendeligt antal hypotetiske stier.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/d87e9d4bb2a2fc713d32abc158506eaa.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Eksempel 1: En node i hver sektion. S\u00f8gningen begynder fra noden, som agenten befinder sig i, og slutter i noden for den \u00f8nskede sektion.<\/i><\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/b535a5db805efdc427d7c5724b866982.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Eksempel 2: Et mindre udvalg af noder (waypoints). S\u00f8gningen begynder i sektionen med agenten, g\u00e5r gennem det n\u00f8dvendige antal noder, og forts\u00e6tter derefter til destinationen.<\/i><\/p>\n<p>Dette er et ret fleksibelt og kraftfuldt system. Men der skal tages visse forholdsregler, n\u00e5r det kommer til, hvor og hvordan man placerer waypoints, ellers kan agenterne simpelthen ikke se den n\u00e6rmeste punkt og ikke v\u00e6re i stand til at starte deres rute. Det ville v\u00e6re lettere, hvis vi kunne placere waypoints automatisk baseret p\u00e5 verdens geometri.<\/p>\n<p>Her kommer navigation mesh eller navmesh (navigationsnet) ind. Det er typisk et 2D-net af trekanter, der er lagt over verdens geometri - hvor agenten har tilladelse til at bev\u00e6ge sig. Hver trekant i nettet bliver en node i grafen og kan have op til tre nabotrekants, som bliver tilst\u00f8dende noder i grafen. <\/p>\n<p>Dette billede er et eksempel fra Unity-engine \u2014 den har analyseret geometrien i verden og skabt en navmesh (vist lys bl\u00e5 p\u00e5 sk\u00e6rmen). Hver polygon i navmesh er et omr\u00e5de, hvor en agent kan st\u00e5 eller bev\u00e6ge sig fra en polygon til en anden. I dette eksempel er polygonerne mindre end de etager, de er placeret p\u00e5 \u2014 dette er gjort for at tage h\u00f8jde for st\u00f8rrelsen af agenten, som vil overskride sin nominelle position.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/845705ba7b9a9d469203aedf7942da41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVi kan finde en rute gennem dette netv\u00e6rk ved igen at bruge A*-algoritmen. Dette vil give os en n\u00e6sten perfekt rute i verden, der tager h\u00f8jde for al geometrien og samtidig ikke kr\u00e6ver un\u00f8dvendige noder eller oprettelse af waypoint.<\/p>\n<p>Pathfinding er et alt for omfattende emne til blot at blive d\u00e6kket i et afsnit i en artikel. \u00d8nsker du at dykke dybere ned i det, kan du finde hj\u00e6lp p\u00e5 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.redblobgames.com\/pathfinding\/a-star\/introduction.html\">Amit Patels hjemmeside<\/a><\/noindex>.<\/p>\n<h2>Planl\u00e6gning<\/h2>\n<p>\nVi har med pathfinding set, at det nogle gange ikke er nok blot at v\u00e6lge en retning og bev\u00e6ge sig \u2014 vi skal v\u00e6lge en rute og tage nogle drejninger for at n\u00e5 vores \u00f8nskede destination. Vi kan opsummere denne id\u00e9: at n\u00e5 et m\u00e5l er ikke blot n\u00e6ste skridt, men en hel sekvens, hvor det til tider kr\u00e6ver, at vi ser fremad et par skridt for at finde ud af, hvad det f\u00f8rste skridt skal v\u00e6re. Dette kaldes planl\u00e6gning. Pathfinding kan betragtes som et af flere supplementer til planl\u00e6gning. Set fra vores Sense\/Think\/Act cyklus er dette, hvor en del af Think planl\u00e6gger flere dele af Act for fremtiden.<\/p>\n<p>Lad os se p\u00e5 et eksempel fra br\u00e6tspillet Magic: The Gathering. Vi spiller f\u00f8rst med f\u00f8lgende kort p\u00e5 h\u00e5nden:<\/p>\n<ul>\n<li>Swamp \u2014 giver 1 sort mana (landkort).<\/li>\n<li>Forest \u2014 giver 1 gr\u00f8n mana (landkort).<\/li>\n<li>Fugitive Wizard \u2014 kr\u00e6ver 1 bl\u00e5 mana for at kunne blive kaldt.<\/li>\n<li>Elvish Mystic \u2014 kr\u00e6ver 1 gr\u00f8n mana for at kunne blive kaldt.<\/li>\n<\/ul>\n<p>\nDe resterende tre kort ignorerer vi for at g\u00f8re det enklere. If\u00f8lge reglerne er det tilladt for spilleren at spille 1 landkort per tur; han kan \"tappe\" dette kort for at f\u00e5 mana, og derefter bruge trylleformularer (inklusive at kalde skabninger) i henhold til m\u00e6ngden af mana. I denne situation ved den menneskelige spiller, at han skal spille Forest, \"tappe\" 1 gr\u00f8n mana, og derefter kalde Elvish Mystic. Men hvordan kan den spillede AI g\u00e6tte dette?<\/p>\n<h3>Simpel planl\u00e6gning<\/h3>\n<p>\nDen trivielle tilgang er at pr\u00f8ve hver handling i r\u00e6kkef\u00f8lge, indtil der ikke er flere passende. N\u00e5r AI kigger p\u00e5 kortene, ser det, at det kan spille Swamp. Og det spiller det. Er der andre handlinger tilbage i denne tur? Det kan ikke spille hverken Elvish Mystic eller Fugitive Wizard, da der kr\u00e6ves henholdsvis gr\u00f8n og bl\u00e5 mana for at spille dem, og Swamp giver kun sort mana. Og det kan ikke spille Forest, fordi det allerede har spillet Swamp. Dermed har den spilleg\u00e5ende AI handlet efter reglerne, men gjort det d\u00e5rligt. Det kan forbedres.<\/p>\n<p>Planl\u00e6gning kan finde en liste over handlinger, der f\u00f8rer spillet til den \u00f8nskede tilstand. Ligesom hver firkant p\u00e5 stien havde naboer (i pathfinding), har hver handling i planen ogs\u00e5 naboer eller efterf\u00f8lgere. Vi kan s\u00f8ge efter disse handlinger og efterf\u00f8lgende handlinger, indtil vi n\u00e5r den \u00f8nskede tilstand.<\/p>\n<p>I vores eksempel er det \u00f8nskede resultat \"at p\u00e5kalde en skabning, hvis det er muligt\". I starten af turen ser vi kun to mulige handlinger, som er tilladt af spillets regler:<\/p>\n<p><i>1. Spille Swamp (resultat: Swamp i spillet)<br \/>\n2. Spille Forest (resultat: Forest i spillet)<\/i><\/p>\n<p>Hver accepteret handling kan f\u00f8re til yderligere handlinger og lukke andre, igen afh\u00e6ngigt af spillets regler. Forestil dig, at vi spiller Swamp - det fjerner Swamp som n\u00e6ste skridt (vi har allerede spillet det), og det fjerner ogs\u00e5 Forest (da reglerne tillader at spille et landkort pr. tur). Herefter tilf\u00f8jer AI som n\u00e6ste skridt - at f\u00e5 1 sort mana, fordi der ikke er andre muligheder. Hvis det forts\u00e6tter og v\u00e6lger at Tap the Swamp, f\u00e5r det 1 enhed sort mana og kan ikke g\u00f8re noget med det.<\/p>\n<p><i>1. Spille Swamp (resultat: Swamp i spillet)<br \/>\n 1.1 \"Tap\" Swamp (resultat: Swamp \"tapet\", +1 enhed sort mana)<br \/>\n Ingen tilg\u00e6ngelige handlinger \u2013 SLUT<br \/>\n2. Spille Forest (resultat: Forest i spillet)<\/i><\/p>\n<p>Listen over handlinger blev kort, vi er g\u00e5et i st\u00e5. Vi gentager processen for n\u00e6ste handling. Vi spiller Forest, \u00e5bnende handlingen \"f\u00e5 1 gr\u00f8n mana\", som i sin tur vil \u00e5bne den tredje handling - p\u00e5kaldelse af Elvish Mystic.<\/p>\n<p><i>1. Spille Swamp (resultat: Swamp i spillet)<br \/>\n 1.1 \"Tap\" Swamp (resultat: Swamp \"tapet\", +1 enhed sort mana)<br \/>\n Ingen tilg\u00e6ngelige handlinger \u2013 SLUT<br \/>\n2. Spille Forest (resultat: Forest i spillet)<br \/>\n 2.1 \"Tap\" Forest (resultat: Forest \"tapet\", +1 enhed gr\u00f8n mana)<br \/>\n 2.1.1 P\u00e5kalde Elvish Mystic (resultat: Elvish Mystic i spillet, -1 enhed gr\u00f8n mana)<br \/>\n Ingen tilg\u00e6ngelige handlinger \u2013 SLUT<\/i><\/p>\n<p>Endelig har vi unders\u00f8gt alle mulige handlinger og fundet en plan for at p\u00e5kalde en skabning.<\/p>\n<p>Dette er et meget forenklet eksempel. Det er bedst at v\u00e6lge den bedst mulige plan i stedet for hvilken som helst, der opfylder nogle kriterier. Generelt kan man vurdere potentielle planer baseret p\u00e5 det endelige resultat eller den samlede gevinst ved deres udf\u00f8relse. Man kan f\u00e5 1 point for at spille et land-kort og 3 point for at p\u00e5kalde en skabning. At spille Swamp ville give en plan, der giver 1 point. At spille Forest \u2192 Tap the Forest \u2192 p\u00e5kalde Elvish Mystic vil straks give 4 point. <\/p>\n<p>S\u00e5dan fungerer planl\u00e6gning i Magic: The Gathering, men denne logik kan anvendes i andre situationer ogs\u00e5. For eksempel at flytte en bonde for at frig\u00f8re plads til at flytte en l\u00f8ber i skak. Eller at tage skjul bag en v\u00e6g for sikkert at skyde i XCOM p\u00e5 den m\u00e5de. I det store hele forst\u00e5r du essensen.<\/p>\n<h3>Forbedret planl\u00e6gning<\/h3>\n<p>\nNogle gange er der for mange potentielle handlinger til at overveje hver eneste mulighed. Lad os vende tilbage til eksemplet med Magic: The Gathering: antag, at der er flere land- og skabninger p\u00e5 h\u00e5nden \u2014 antallet af mulige bev\u00e6gelseskombinationer kan t\u00e6lles i flere titalls. Der er flere l\u00f8sninger p\u00e5 problemet.<\/p>\n<p>Den f\u00f8rste metode er backwards chaining (bagl\u00e6ns k\u00e6dning). I stedet for at gennemg\u00e5 alle kombinationer, er det bedre at starte med det \u00f8nskede resultat og pr\u00f8ve at finde en direkte rute. I stedet for at bev\u00e6ge os fra roden af tr\u00e6et til et bestemt blad, bev\u00e6ger vi os i modsatte retning \u2014 fra bladet til roden. Denne metode er enklere og hurtigere.<\/p>\n<p>Hvis modstanderen har 1 liv, kan man finde planen 'p\u00e5f\u00f8r 1 eller flere skadede'. For at opn\u00e5 dette skal en r\u00e6kke betingelser opfyldes: <\/p>\n<p>1. Skaden kan for\u00e5rsages af en trylleformel \u2014 den skal v\u00e6re p\u00e5 h\u00e5nden.<br \/>\n2. For at spille trylleformlen kr\u00e6ves mana.<br \/>\n3. For at f\u00e5 mana skal man spille et land-kort.<br \/>\n4. For at spille et land-kort skal man have det p\u00e5 h\u00e5nden.<\/p>\n<p>En anden metode er best-first search (bedste f\u00f8rst s\u00f8gning). I stedet for at gennemg\u00e5 alle ruter, v\u00e6lger vi den mest passende. Ofte giver denne metode en optimal plan uden un\u00f8dvendige omkostninger ved s\u00f8gning. A* er en form for bedste f\u00f8rst s\u00f8gning \u2014 ved at udforske de mest lovende ruter fra starten kan den allerede finde den bedste vej uden at skulle tjekke de \u00f8vrige muligheder.<\/p>\n<p>En interessant og altid mere popul\u00e6r variant af best-first search er Monte Carlo Tree Search. I stedet for at g\u00e6tte, hvilke planer der er bedre end andre ved valget af hver efterf\u00f8lgende handling, v\u00e6lger algoritmen tilf\u00e6ldige efterf\u00f8lgere p\u00e5 hvert trin, indtil den n\u00e5r en afslutning (n\u00e5r planen f\u00f8rer til sejr eller nederlag). Den endelige resultat bruges derefter til at h\u00e6ve eller s\u00e6nke vurderingen af \"v\u00e6gten\" af de tidligere muligheder. Ved at gentage denne proces flere gange, giver algoritmen en god vurdering af, hvilket n\u00e6ste skridt der er bedst, selvom situationen \u00e6ndrer sig (hvis modstanderen tager skridt til at forhindre spilleren). <\/p>\n<p>N\u00e5r man taler om planl\u00e6gning i spil, kan man ikke undg\u00e5 Goal-Oriented Action Planning eller GOAP (m\u00e5lrettet handlingsplanl\u00e6gning). Dette er en vidt brugt og diskuteret metode, men bortset fra et par s\u00e6rpr\u00e6gede detaljer, er det i bund og grund en metode til backwards chaining, som vi tidligere har omtalt. Hvis opgaven var \"at eliminere spilleren\", og spilleren er d\u00e6kket af noget, kan planen v\u00e6re: kast en granat \u2192 f\u00e5 fat i den \u2192 kast.<\/p>\n<p>Der er normalt flere m\u00e5l, hver med sin egen prioritet. Hvis m\u00e5let med h\u00f8jeste prioritet ikke kan opfyldes (ingen kombination af handlinger skaber planen \"eliminere spilleren\", fordi spilleren ikke kan ses), vil AI'en g\u00e5 tilbage til m\u00e5lene med lavere prioriteter.<\/p>\n<h2>L\u00e6ring og tilpasning<\/h2>\n<p>\nVi har allerede sagt, at spils AI normalt ikke bruger maskinl\u00e6ring, fordi det ikke er egnet til at styre agenter i realtid. Men det betyder ikke, at man ikke kan l\u00e5ne noget fra dette omr\u00e5de. Vi \u00f8nsker en modstander i en shooter, som man kan l\u00e6re noget af. For eksempel at l\u00e6re om de bedste positioner p\u00e5 kortet. Eller en modstander i et fighting-spil, der ville blokere ofte brugte spillers kombinationsangreb, hvilket motiverer til at bruge andre. S\u00e5 maskinl\u00e6ring kan i s\u00e5danne situationer v\u00e6re ret nyttigt.<\/p>\n<h3>Statistik og sandsynligheder<\/h3>\n<p>\nF\u00f8r vi g\u00e5r videre til de komplekse eksempler, lad os vurdere, hvor langt vi kan g\u00e5 ved at tage nogle enkle m\u00e5linger og bruge dem til at tr\u00e6ffe beslutninger. For eksempel, hvordan kan vi vurdere, om en spiller kan starte et angreb i de f\u00f8rste par minutter af spillet, og hvilken forsvarsstrategi vi skal forberede mod dette? Vi kan unders\u00f8ge spillerens tidligere erfaring for at forst\u00e5, hvordan fremtidig reaktion kan se ud. Lad os starte med, at vi ikke har disse data, men vi kan indsamle dem \u2014 hver gang AI spiller mod en menneskelig modstander, kan den registrere tidsrammen for det f\u00f8rste angreb. Efter flere sessioner vil vi f\u00e5 et gennemsnitligt tidspunkt for, hvorn\u00e5r spilleren vil angribe i fremtiden.<\/p>\n<p>Der er dog et problem med gennemsnitsv\u00e6rdierne: hvis en spiller har 'rush'et' 20 gange og spillet langsomt 20 gange, vil de n\u00f8dvendige v\u00e6rdier ligge et sted i midten, hvilket ikke giver os noget nyttigt. En af l\u00f8sningerne er at begr\u00e6nse inputdataene \u2014 vi kan tage de seneste 20 tilf\u00e6lde i betragtning.<\/p>\n<p>En lignende tilgang anvendes ved vurderingen af sandsynligheden for bestemte handlinger, idet man antager, at spillerens tidligere pr\u00e6ferencer vil v\u00e6re de samme i fremtiden. Hvis spilleren angriber os med en ildkugle fem gange, med lyn to gange, og med n\u00e6rkamp \u00e9n gang, er det tydeligt, at han foretr\u00e6kker ildkuglen. Lad os ekstrapolere og se sandsynligheden for brugen af forskellige v\u00e5ben: ildkugle=62,5%, lyn=25% og n\u00e6rkamp=12,5%. Vores spille-AI skal forberede sig p\u00e5 at forsvare sig mod ild.<\/p>\n<p>En anden interessant metode er at bruge Naive Bayes Classifier (naiv bayesisk klassifikator) til at analysere store m\u00e6ngder inputdata og klassificere situationen, s\u00e5 AI reagerer korrekt. Bayesianske klassifikatorer er mest kendte for deres anvendelse i spamfiltre for e-mail. Her analyserer de ord, sammenligner dem med, hvor disse ord tidligere har optr\u00e5dt (i spam eller ej), og drager konklusioner om indkommende e-mails. Vi kan g\u00f8re det samme, selv med f\u00e6rre inputdata. Baseret p\u00e5 al den nyttige information, som AI ser (f.eks. hvilke fjendtlige enheder der er blevet oprettet, eller hvilke besv\u00e6rgelser de bruger, eller hvilke teknologier de har forsket i), samt det endelige resultat (krig eller fred, 'rush'e eller forsvare os osv.) \u2014 vil vi v\u00e6lge den \u00f8nskede adf\u00e6rd for AI.<\/p>\n<p>Alle disse metoder til l\u00e6ring er tilstr\u00e6kkelige, men det er \u00f8nskeligt at bruge dem baseret p\u00e5 data fra testningen. AI'en vil l\u00e6re at tilpasse sig de forskellige strategier, som dine playtestere har brugt. En AI, der tilpasser sig spilleren efter lanceringen, kan blive forudsigelig eller omvendt for sv\u00e6r at overvinde.<\/p>\n<h3>Tilpasning baseret p\u00e5 v\u00e6rdier<\/h3>\n<p>\nI betragtning af indholdet i vores spilverden og reglerne kan vi \u00e6ndre s\u00e6ttet af v\u00e6rdier, der p\u00e5virker beslutningstagningen, i stedet for blot at bruge inputdata. Vi g\u00f8r det s\u00e5dan her:<\/p>\n<ul>\n<li>Lad AI'en indsamle data om verdens tilstand og n\u00f8glebegivenheder under spillet (som angivet ovenfor).<\/li>\n<li>Vi \u00e6ndrer nogle vigtige v\u00e6rdier baseret p\u00e5 disse data.<\/li>\n<li>Vi implementerer vores beslutninger, som er baseret p\u00e5 behandlingen eller evalueringen af disse v\u00e6rdier.<\/li>\n<\/ul>\n<p>\nFor eksempel har agenten flere v\u00e6relser at v\u00e6lge imellem p\u00e5 et f\u00f8rstepersons skydespil. Hvert v\u00e6relse har sin egen v\u00e6rdi, der bestemmer, hvor \u00f8nskeligt det er at bes\u00f8ge. AI'en v\u00e6lger tilf\u00e6ldigt, hvilket v\u00e6relse den vil g\u00e5 ind i, baseret p\u00e5 v\u00e6rdien. Derefter husker agenten, i hvilket v\u00e6relse han blev dr\u00e6bt, og s\u00e6nker dens v\u00e6rdi (sandynligheden for, at han vil vende tilbage dertil). Det samme g\u00e6lder for den omvendte situation - hvis agenten dr\u00e6ber mange modstandere, \u00f8ges v\u00e6rdien af v\u00e6relset.<\/p>\n<h3>Markov-model<\/h3>\n<p>\nHvad hvis vi bruger de indsamlede data til at lave forudsigelser? Hvis vi husker hvert v\u00e6relse, hvor vi ser spilleren i l\u00f8bet af en bestemt tidsperiode, vil vi kunne forudsige, hvilket v\u00e6relse spilleren kan g\u00e5 til. Ved at spore og registrere spillerens bev\u00e6gelser mellem v\u00e6relserne (v\u00e6rdier), kan vi lave forudsigelser.<\/p>\n<p>Lad os tage tre v\u00e6relser: r\u00f8dt, gr\u00f8nt og bl\u00e5t. Og ogs\u00e5 de observationer, vi har registreret under vores visning af spilsessionen:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/6e90a365b72a176c36c9a14213baaafc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nAntallet af observationer for hvert v\u00e6relse er n\u00e6sten ligeligt - hvor vi skal placere et godt sted til bagholdet, ved vi stadig ikke. Indsamling af statistik kompliceres ogs\u00e5 af respawn af spillere, som dukker op j\u00e6vnt over hele kortet. Men dataene om det n\u00e6ste v\u00e6relse, de g\u00e5r ind i efter at v\u00e6re blevet respawnet p\u00e5 kortet, er allerede nyttige.<\/p>\n<p>Det er tydeligt, at det gr\u00f8nne rum tilfredsstiller spillerne - de fleste fra det r\u00f8de rum g\u00e5r ind i det, og 50% af dem bliver der. Det bl\u00e5 rum derimod er ikke popul\u00e6rt, n\u00e6sten ingen g\u00e5r ind i det, og hvis de g\u00f8r, s\u00e5 bliver de ikke l\u00e6nge. <\/p>\n<p>Men dataene fort\u00e6ller os noget mere vigtigt - n\u00e5r spilleren er i det bl\u00e5 rum, s\u00e5 vil det n\u00e6ste rum, hvor vi h\u00f8jst sandsynligt ser ham, v\u00e6re det r\u00f8de og ikke det gr\u00f8nne. Selvom det gr\u00f8nne rum er mere popul\u00e6rt end det r\u00f8de, \u00e6ndrer situationen sig, hvis spilleren er i det bl\u00e5. Den n\u00e6ste tilstand (dvs. det rum, som spilleren vil g\u00e5 ind i) afh\u00e6nger af den forrige tilstand (dvs. rummet, som spilleren befinder sig i nu). Gennem unders\u00f8gelse af afh\u00e6ngigheder vil vi kunne lave mere pr\u00e6cise forudsigelser end hvis vi blot t\u00e6ller observationerne uafh\u00e6ngigt af hinanden.<\/p>\n<p>At forudsige den fremtidige tilstand baseret p\u00e5 data fra den forrige tilstand kaldes en Markov-model, og s\u00e5danne eksempler (med rummene) kaldes Markov-k\u00e6der. Da modellerne repr\u00e6senterer sandsynligheden for \u00e6ndringer mellem de f\u00f8lgende tilstande, vises de visuelt i form af en FSM med sandsynligheder omkring hver overgang. Tidligere har vi brugt FSM til at repr\u00e6sentere den adf\u00e6rdsm\u00e6ssige tilstand, som agenten befandt sig i, men dette koncept kan anvendes p\u00e5 enhver tilstand, uanset om den er relateret til agenten eller ej. I dette tilf\u00e6lde repr\u00e6senterer tilstandene det rum, som agenten optager:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/edb32dff7a3298b19c3fa4d66f48e9f4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDette er en enkel m\u00e5de at repr\u00e6sentere den relative sandsynlighed for \u00e6ndringer i tilstande, som giver AI en mulighed for at forudsige den n\u00e6ste tilstand. Der kan forudses flere skridt fremad.<\/p>\n<p>Hvis spilleren er i det gr\u00f8nne rum, er der 50% chance for, at han forbliver der ved den n\u00e6ste observation. Men hvad er sandsynligheden for, at han stadig vil v\u00e6re der bagefter? Der er ikke kun en chance for, at spilleren er forblevet i det gr\u00f8nne rum efter to observationer, men ogs\u00e5 en chance for, at han har forladt og derefter kommet tilbage. Her er en ny tabel, der tager h\u00f8jde for de nye data:<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/f87afff68b066a879661e37f68654ae2.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nHeraf fremg\u00e5r det, at chancen for at se spilleren i det gr\u00f8nne rum efter to observationer vil v\u00e6re 51% - 21%, at han kommer fra det r\u00f8de rum, 5% af dem, der indikerer, at spilleren bes\u00f8ger det bl\u00e5 rum imellem, og 25%, at spilleren slet ikke forlader det gr\u00f8nne rum.<\/p>\n<p>En tabel er et visuelt v\u00e6rkt\u00f8j - proceduren kr\u00e6ver blot, at man multiplicerer sandsynlighederne ved hvert skridt. Det betyder, at du kan kigge langt ind i fremtiden med \u00e9t forbehold: Vi antager, at chancen for at komme ind i et rum helt afh\u00e6nger af det nuv\u00e6rende rum. Dette kaldes Markov-ejendommen - fremtidige tilstande afh\u00e6nger kun af den nuv\u00e6rende. Men dette er ikke 100% sikkert. Spillerne kan \u00e6ndre beslutninger baseret p\u00e5 andre faktorer: helbredsniveau eller m\u00e6ngden af ammunition. Da vi ikke fasts\u00e6tter disse v\u00e6rdier, vil vores forudsigelser v\u00e6re mindre pr\u00e6cise.<\/p>\n<h3>N-Grams<\/h3>\n<p>\nHvad med eksemplet med fight-spillet og forudsigelse af spillerens combo-bev\u00e6gelser? Det samme g\u00e6lder! Men i stedet for \u00e9n tilstand eller begivenhed vil vi unders\u00f8ge hele sekvenserne, der udg\u00f8r en combo-hit.<\/p>\n<p>En m\u00e5de at g\u00f8re dette p\u00e5 er at gemme hver input (f.eks. Kick, Punch eller Block) i en buffer og registrere hele bufferen som en begivenhed. S\u00e5 n\u00e5r spilleren gentagne gange trykker p\u00e5 Kick, Kick, Punch for at udf\u00f8re SuperDeathFist-angrebet, gemmer AI-systemet alle inputs i bufferen og husker de seneste tre, der bruges ved hvert skridt.<\/p>\n<p><img decoding=\"async\" alt=\"S\u00e5dan skaber du spil-AI: en guide for begyndere\" src=\"\/wp-content\/uploads\/2019\/11\/9a95226ae155dca5e45a66d4440f3cd4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n(Fremh\u00e6vede linjer, n\u00e5r spilleren aktiverer SuperDeathFist-angrebet.)<\/p>\n<p>AI vil se alle mulighederne, n\u00e5r spilleren v\u00e6lger Kick efterfulgt af Kick, og derefter bem\u00e6rke, at det n\u00e6ste input altid er Punch. Dette vil give agenten mulighed for at forudsige SuperDeathFist-comboen og blokere den, hvis det er muligt.<\/p>\n<p>Disse sekvenser af begivenheder kaldes N-grammer, hvor N er antallet af gemte elementer. I det forrige eksempel var det en 3-gram (trigram), hvilket betyder, at de to f\u00f8rste posters bruges til at forudsige den tredje. Tilsvarende i en 5-gram forudsiger de f\u00f8rste fire posters den femte, og s\u00e5 videre.<\/p>\n<p>Udvikleren skal n\u00f8je overveje st\u00f8rrelsen af N-grammerne. Et mindre antal N kr\u00e6ver mindre hukommelse, men gemmer ogs\u00e5 en kortere historie. For eksempel vil en 2-gram (bigram) gemme Kick, Kick eller Kick, Punch, men kan ikke gemme Kick, Kick, Punch, s\u00e5 AI vil ikke reagere p\u00e5 SuperDeathFist-comboen.<\/p>\n<p>P\u00e5 den anden side kr\u00e6ver st\u00f8rre tal mere hukommelse, og AI vil have sv\u00e6rere ved at l\u00e6re, da der vil v\u00e6re mange flere mulige varianter. Hvis du har tre mulige inputs Kick, Punch eller Block, og vi bruger en 10-gram, vil der approximativt v\u00e6re omkring 60.000 forskellige varianter.<\/p>\n<p>Modellen af bigrammer er en simpel Markov-k\u00e6de \u2014 hvert par \"tidligere tilstand\/nuv\u00e6rende tilstand\" er en bigram, og du kan forudsige den anden tilstand baseret p\u00e5 den f\u00f8rste. 3-grammer og st\u00f8rre N-grammer kan ogs\u00e5 betragtes som Markov-k\u00e6der, hvor alle elementer (undtagen det sidste i N-grammet) tilsammen danner den f\u00f8rste tilstand, og det sidste element er den anden. Et eksempel med kampe viser chancen for at g\u00e5 fra tilstanden Kick og Kick til tilstanden Kick og Punch. Ved at betragte flere poster i indgangshistorikken som \u00e9n enhed, omdanner vi i bund og grund indgangssekvensen til en del af en hel tilstand. Dette giver os Markov-egenskaber, der g\u00f8r det muligt at bruge Markov-k\u00e6der til at forudsige n\u00e6ste input og g\u00e6tte, hvilken kombinationsbev\u00e6gelse der vil komme n\u00e6ste.<\/p>\n<h2>Konklusion<\/h2>\n<p>\nVi har talt om de mest almindelige v\u00e6rkt\u00f8jer og tilgange inden for udvikling af kunstig intelligens. Vi har ogs\u00e5 gennemg\u00e5et situationer, hvor de skal anvendes, og hvor de er s\u00e6rligt nyttige. <\/p>\n<p>Dette burde v\u00e6re tilstr\u00e6kkeligt til at forst\u00e5 de grundl\u00e6ggende aspekter af spil-AI. Men selvf\u00f8lgelig er dette langt fra alle metoder. Blandt de mindre popul\u00e6re, men ikke mindre effektive er:<\/p>\n<ul>\n<li>optimeringsalgoritmer, herunder bjergbestigning, gradientnedstigning og genetiske algoritmer<\/li>\n<li>konkurrences\u00f8gning\/planl\u00e6gningsalgoritmer (minimax og alpha-beta pruning)<\/li>\n<li>klassifikationsmetoder (perceptroner, neurale netv\u00e6rk og st\u00f8ttevektormaskiner)<\/li>\n<li>systemer til behandling af agenter, opfattelse og hukommelse<\/li>\n<li>arkitektoniske tilgange til AI (hybridsystemer, undergrupper af arkitekturer og andre m\u00e5der at l\u00e6gge AI-systemer oven p\u00e5 hinanden)<\/li>\n<li>animationsv\u00e6rkt\u00f8jer (planl\u00e6gning og koordinering af bev\u00e6gelse)<\/li>\n<li>ydelsesfaktorer (detaljeniveau, anytime-algoritmer og timeslicing)<\/li>\n<\/ul>\n<p>\nInternetsider om emnet:<\/p>\n<p>1. P\u00e5 GameDev.net findes der <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/articles\/programming\/artificial-intelligence\/\">en sektion med artikler og tutorials om AI<\/a><\/noindex>, samt <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gamedev.net\/forums\/forum\/6-artificial-intelligence\/\">et forum<\/a><\/noindex>.<br \/>\n2. <noindex><a rel=\"nofollow\" href=\"http:\/\/aigamedev.com\/\">AiGameDev.com<\/a><\/noindex> indeholder mange pr\u00e6sentationer og artikler om en bred vifte af emner relateret til udviklingen af spil-AI.<br \/>\n3. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gdcvault.com\/\">The GDC Vault<\/a><\/noindex> inkluderer emner fra GDC AI summit, hvor mange er tilg\u00e6ngelige gratis.<br \/>\n4. Nyttige materialer kan ogs\u00e5 findes p\u00e5 <noindex><a rel=\"nofollow\" href=\"http:\/\/gameai.com\/\">AI Game Programmers Guild<\/a><\/noindex>.<br \/>\n5. Tommy Thompson, AI- forsker og spiludvikler, laver videoer p\u00e5 YouTube-kanalen <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/user\/tthompso\">AI and Games<\/a><\/noindex> med forklaringer og studier af AI i kommercielle spil.<\/p>\n<p>B\u00f8ger om emnet:<\/p>\n<p>1. Serien af b\u00f8gerne Game AI Pro er samlinger af korte artikler, der forklarer, hvordan man implementerer specifikke funktioner eller hvordan man l\u00f8ser specifikke problemer.<\/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: Samlet visdom fra 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: Samlet visdom fra game AI-professionals<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/amzn.to\/2KF4irS\">Game AI Pro 3: Samlet visdom fra game AI-professionals<\/a><\/noindex><\/p>\n<p>2. Serien AI Game Programming Wisdom er forg\u00e6ngeren til serien Game AI Pro. Den indeholder \u00e6ldre metoder, men n\u00e6sten alle er stadig relevante i dag.<\/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> \u2014 er en af de grundl\u00e6ggende tekster for alle, der \u00f8nsker at forst\u00e5 det generelle omr\u00e5de inden for kunstig intelligens. Denne bog handler ikke om spiludvikling \u2014 den l\u00e6rer de grundl\u00e6ggende principper for AI.<br \/>\n<br \/>Kilde: <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\/da\/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=\"da_DK\" \/>\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\/da\/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\udd47Hvordan man laver game AI: en guide til begyndere | ProHoster","description":"Jeg st\u00f8dte p\u00e5 interessant materiale om.","canonical_url":"https:\/\/prohoster.info\/da\/blog\/news\/kak-sozdat-igrovoj-ii-gajd-dlya-nachinayushhih","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","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\/da\/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\/da\/wp-json\/wp\/v2\/posts\/52118","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=52118"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/52118\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=52118"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=52118"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=52118"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}