Hur man skapar en spel-AI: en guide för nybörjare

Hur man skapar en spel-AI: en guide för nybörjare

Jag kom över en del intressant material om artificiell intelligens i spel. Med en förklaring av grundlÀggande saker om AI med enkla exempel, och inuti finns det mÄnga anvÀndbara verktyg och metoder för dess bekvÀma utveckling och design. Hur, var och nÀr de ska anvÀndas finns ocksÄ dÀr.

De flesta av exemplen Àr skrivna i pseudokod, sÄ inga avancerade programmeringskunskaper krÀvs. Under klippet finns 35 textark med bilder och gifs, sÄ gör dig redo.

UPD. Jag ber om ursÀkt, men jag har redan gjort min egen översÀttning av den hÀr artikeln pÄ Habré PatientZero. Du kan lÀsa hans version hÀr, men av nÄgon anledning gick artikeln mig förbi (jag anvÀnde sökningen, men nÄgot gick fel). Och eftersom jag skriver pÄ en blogg dedikerad till spelutveckling, bestÀmde jag mig för att lÀmna min version av översÀttningen till prenumeranter (vissa punkter Àr formaterade pÄ ett annat sÀtt, nÄgra utelÀmnades medvetet pÄ rÄd frÄn utvecklarna).

Vad Àr AI?

Game AI fokuserar pÄ vilka ÄtgÀrder ett objekt ska utföra baserat pÄ förhÄllandena dÀr det befinner sig. Detta kallas vanligtvis för "intelligent agent", dÀr en agent Àr en spelarkaraktÀr, ett fordon, en bot eller ibland nÄgot mer abstrakt: en hel grupp av enheter eller till och med en civilisation. I varje fall Àr det en sak som mÄste se sin omgivning, fatta beslut utifrÄn den och agera i enlighet med dem. Detta kallas Sense/Think/Act-cykeln:

  • Sense: Agenten hittar eller tar emot information om saker i sin omgivning som kan pĂ„verka dess beteende (hot i nĂ€rheten, föremĂ„l att samla in, intressanta platser att utforska).
  • TĂ€nk: Agenten bestĂ€mmer hur han ska reagera (övervĂ€ger om det Ă€r sĂ€kert nog att samla föremĂ„l eller om han ska slĂ„ss/gömma sig först).
  • Agera: agenten utför Ă„tgĂ€rder för att implementera det tidigare beslutet (börjar röra sig mot fienden eller objektet).
  • ...nu har situationen förĂ€ndrats pĂ„ grund av karaktĂ€rernas handlingar, sĂ„ cykeln upprepas med nya data.

AI tenderar att fokusera pÄ Sense-delen av loopen. Till exempel tar autonoma bilar bilder av vÀgen, kombinerar dem med radar- och lidardata och tolkar dem. Detta görs vanligtvis genom maskininlÀrning, som bearbetar inkommande data och ger den mening, extraherar semantisk information som "det finns en annan bil 20 meter framför dig." Det Àr de sÄ kallade klassificeringsproblemen.

Spel behöver inte ett komplext system för att extrahera information eftersom det mesta av data redan Ă€r en integrerad del av den. Det finns inget behov av att köra bildigenkĂ€nningsalgoritmer för att avgöra om det finns en fiende framför sig – spelet kĂ€nner redan till och matar in informationen direkt i beslutsprocessen. DĂ€rför Ă€r Sense-delen av cykeln ofta mycket enklare Ă€n Think and Act-delen.

BegrÀnsningar för Game AI

AI har ett antal begrÀnsningar som mÄste observeras:

  • AI behöver inte trĂ€nas i förvĂ€g, som om det vore en maskininlĂ€rningsalgoritm. Det Ă€r ingen mening att skriva ett neuralt nĂ€tverk under utvecklingen för att övervaka tiotusentals spelare och lĂ€ra sig det bĂ€sta sĂ€ttet att spela mot dem. Varför? Eftersom spelet inte har slĂ€ppts och det finns inga spelare.
  • Spelet ska vara roligt och utmanande, sĂ„ agenter ska inte hitta den bĂ€sta strategin mot mĂ€nniskor.
  • Agenter mĂ„ste se realistiska ut sĂ„ att spelarna kĂ€nner att de spelar mot riktiga mĂ€nniskor. AlphaGo-programmet övertrĂ€ffade mĂ€nniskor, men stegen som valdes var mycket lĂ„ngt ifrĂ„n den traditionella förstĂ„elsen av spelet. Om spelet simulerar en mĂ€nsklig motstĂ„ndare borde denna kĂ€nsla inte existera. Algoritmen mĂ„ste Ă€ndras sĂ„ att den fattar rimliga beslut snarare Ă€n idealiska.
  • AI mĂ„ste fungera i realtid. Detta innebĂ€r att algoritmen inte kan monopolisera CPU-anvĂ€ndning under lĂ„nga tidsperioder för att fatta beslut. Även 10 millisekunder Ă€r för lĂ„ngt, eftersom de flesta spel bara behöver 16 till 33 millisekunder för att göra all bearbetning och gĂ„ vidare till nĂ€sta grafikram.
  • Helst bör Ă„tminstone en del av systemet vara datadrivet, sĂ„ att icke-kodare kan göra Ă€ndringar och justeringar kan ske snabbare.

LÄt oss titta pÄ AI-metoder som tÀcker hela Sense/Think/Act-cykeln.

Att fatta grundlÀggande beslut

LÄt oss börja med det enklaste spelet - Pong. MÄl: flytta paddeln sÄ att bollen studsar av den istÀllet för att flyga förbi den. Det Àr som tennis, dÀr man förlorar om man inte slÄr bollen. HÀr har AI en relativt enkel uppgift - att bestÀmma i vilken riktning plattformen ska flyttas.

Hur man skapar en spel-AI: en guide för nybörjare

Villkorliga uttalanden

För AI i Pong Àr den mest uppenbara lösningen att alltid försöka placera plattformen under bollen.

En enkel algoritm för detta, skriven i pseudokod:

varje bildruta/uppdatering medan spelet körs:
om bollen Àr till vÀnster om paddeln:
flytta paddeln Ät vÀnster
annars om bollen Àr till höger om paddeln:
flytta paddeln Ät höger

Om plattformen rör sig med bollens hastighet Àr detta den idealiska algoritmen för AI i Pong. Det finns ingen anledning att komplicera nÄgot om det inte finns sÄ mycket data och möjliga ÄtgÀrder för agenten.

Detta tillvÀgagÄngssÀtt Àr sÄ enkelt att hela Sense/Think/Act-cykeln knappt mÀrks. Men det finns dÀr:

  • Sense-delen Ă€r i tvĂ„ om-satser. Spelet vet var bollen Ă€r och var plattformen Ă€r, sĂ„ AI ser till den för den informationen.
  • TĂ€nk-delen ingĂ„r ocksĂ„ i de tvĂ„ if-pĂ„stĂ„endena. De förkroppsligar tvĂ„ lösningar, som i detta fall utesluter varandra. Som ett resultat vĂ€ljs en av tre Ă„tgĂ€rder - flytta plattformen till vĂ€nster, flytta den till höger eller gör ingenting om den redan Ă€r korrekt placerad.
  • Akt-delen finns i satserna Move Paddle Left och Move Paddle Right. Beroende pĂ„ speldesignen kan de flytta plattformen direkt eller med en viss hastighet.

SÄdana tillvÀgagÄngssÀtt kallas reaktiva - det finns en enkel uppsÀttning regler (i det hÀr fallet om uttalanden i koden) som reagerar pÄ det aktuella tillstÄndet i vÀrlden och vidtar ÄtgÀrder.

BeslutstrÀd

Pong-exemplet Àr faktiskt likvÀrdigt med ett formellt AI-koncept som kallas ett beslutstrÀd. Algoritmen gÄr igenom den för att nÄ ett "blad" - ett beslut om vilken ÄtgÀrd som ska vidtas.

LÄt oss göra ett blockschema över beslutstrÀdet för vÄr plattforms algoritm:

Hur man skapar en spel-AI: en guide för nybörjare

Varje del av trÀdet kallas en nod - AI anvÀnder grafteori för att beskriva sÄdana strukturer. Det finns tvÄ typer av noder:

  • Beslutsnoder: att vĂ€lja mellan tvĂ„ alternativ baserat pĂ„ att testa nĂ„got tillstĂ„nd, dĂ€r varje alternativ representeras som en separat nod.
  • Slutnoder: ÅtgĂ€rden som ska utföras som representerar det slutliga beslutet.

Algoritmen startar frÄn den första noden (trÀdets "rot"). Den fattar antingen ett beslut om vilken underordnad nod den ska gÄ till, eller sÄ utför den ÄtgÀrden som Àr lagrad i noden och avslutas.

Vad Àr fördelen med att ett beslutstrÀd gör samma jobb som if-uttalandena i föregÄende avsnitt? HÀr finns ett generellt system dÀr varje beslut endast har ett villkor och tvÄ möjliga utfall. Detta gör att utvecklaren kan skapa AI frÄn data som representerar beslut i ett trÀd utan att behöva hÄrdkoda det. LÄt oss presentera det i form av en tabell:

Hur man skapar en spel-AI: en guide för nybörjare

PÄ kodsidan fÄr du ett system för att lÀsa strÀngar. Skapa en nod för var och en av dem, anslut beslutslogik baserat pÄ den andra kolumnen och underordnade noder baserat pÄ den tredje och fjÀrde kolumnen. Du behöver fortfarande programmera villkoren och ÄtgÀrderna, men nu kommer spelets struktur att bli mer komplex. HÀr lÀgger du till ytterligare beslut och ÄtgÀrder och anpassar sedan hela AI genom att helt enkelt redigera trÀddefinitionstextfilen. DÀrefter överför du filen till speldesignern, som kan Àndra beteendet utan att kompilera om spelet eller Àndra koden.

BeslutstrÀd Àr mycket anvÀndbara nÀr de byggs automatiskt frÄn en stor uppsÀttning exempel (till exempel med ID3-algoritmen). Detta gör dem till ett effektivt och högpresterande verktyg för att klassificera situationer baserat pÄ erhÄllen data. Men vi gÄr lÀngre Àn ett enkelt system för agenter att vÀlja ÄtgÀrder.

scenarier

Vi analyserade ett beslutstrÀdssystem som anvÀnde förskapade förutsÀttningar och ÄtgÀrder. Personen som designar AI kan organisera trÀdet hur han vill, men han mÄste fortfarande lita pÄ kodaren som programmerade allt. TÀnk om vi kunde ge designern verktygen att skapa sina egna förutsÀttningar eller handlingar?

För att programmeraren inte ska behöva skriva kod för villkoren Is Ball Left Of Paddle och Is Ball Right Of Paddle, kan han skapa ett system dÀr designern kommer att skriva villkor för att kontrollera dessa vÀrden. DÄ kommer beslutstrÀdets data att se ut sÄ hÀr:

Hur man skapar en spel-AI: en guide för nybörjare

Detta Àr i huvudsak samma som i den första tabellen, men lösningarna inom sig har sin egen kod, lite som den villkorliga delen av en if-sats. PÄ kodsidan skulle detta lÀsas i den andra kolumnen för beslutsnoderna, men istÀllet för att leta efter ett specifikt villkor att exekvera (Is Ball Left Of Paddle), utvÀrderar det det villkorliga uttrycket och returnerar sant eller falskt i enlighet med detta. Detta görs med hjÀlp av skriptsprÄket Lua eller Angelscript. Med hjÀlp av dem kan en utvecklare ta objekt i sitt spel (boll och paddla) och skapa variabler som kommer att finnas tillgÀngliga i skriptet (ball.position). Dessutom Àr skriptsprÄket enklare Àn C++. Det krÀver inte ett fullstÀndigt kompileringssteg, sÄ det Àr idealiskt för att snabbt justera spellogik och lÄter "icke-kodare" skapa de nödvÀndiga funktionerna sjÀlva.

I exemplet ovan anvÀnds skriptsprÄket endast för att utvÀrdera det villkorliga uttrycket, men det kan ocksÄ anvÀndas för ÄtgÀrder. Till exempel kan data Flytta paddel Ät höger bli en skriptsats (ball.position.x += 10). SÄ att ÄtgÀrden ocksÄ definieras i skriptet, utan att behöva programmera Move Paddle Right.

Du kan gÄ Ànnu lÀngre och skriva hela beslutstrÀdet pÄ ett skriptsprÄk. Detta kommer att vara kod i form av hÄrdkodade villkorliga uttalanden, men de kommer att finnas i externa skriptfiler, det vill sÀga de kan Àndras utan att kompilera om hela programmet. Du kan ofta redigera skriptfilen under spelandet för att snabbt testa olika AI-svar.

HĂ€ndelsesvar

Exemplen ovan Àr perfekta för Pong. De kör kontinuerligt Sense/Think/Act-cykeln och agerar utifrÄn det senaste tillstÄndet i vÀrlden. Men i mer komplexa spel mÄste du reagera pÄ enskilda hÀndelser och inte utvÀrdera allt pÄ en gÄng. Pong i det hÀr fallet Àr redan ett dÄligt exempel. LÄt oss vÀlja en annan.

FörestÀll dig en shooter dÀr fienderna Àr orörliga tills de upptÀcker spelaren, varefter de agerar beroende pÄ deras "specialisering": nÄgon kommer att springa för att "rusa", nÄgon kommer att attackera pÄ lÄngt hÄll. Det Àr fortfarande ett grundlÀggande reaktivt system - "om en spelare blir upptÀckt, gör nÄgot" - men det kan logiskt delas upp i en Player Seen-hÀndelse och en Reaction (vÀlj ett svar och kör det).

Detta för oss tillbaka till Sense/Think/Act-cykeln. Vi kan koda en Sense-del som kommer att kontrollera varje bildruta om AI ser spelaren. Om inte hÀnder ingenting, men om den ser skapas evenemanget Player Seen. Koden kommer att ha ett separat avsnitt som sÀger "nÀr Player Seen-hÀndelsen intrÀffar, gör" var Àr svaret du behöver för att ta itu med Think och Act-delarna. SÄledes kommer du att stÀlla in reaktioner pÄ Player Seen-hÀndelsen: för den "rusande" karaktÀren - ChargeAndAttack, och för prickskytten - HideAndSnipe. Dessa relationer kan skapas i datafilen för snabb redigering utan att behöva kompilera om. SkriptsprÄk kan ocksÄ anvÀndas hÀr.

Att fatta svÄra beslut

Även om enkla reaktionssystem Ă€r mycket kraftfulla finns det mĂ„nga situationer dĂ€r de inte rĂ€cker till. Ibland behöver du fatta olika beslut baserat pĂ„ vad agenten gör just nu, men det Ă€r svĂ„rt att förestĂ€lla sig detta som ett villkor. Ibland finns det för mĂ„nga villkor för att effektivt representera dem i ett beslutstrĂ€d eller ett manus. Ibland behöver man i förvĂ€g bedöma hur situationen kommer att förĂ€ndras innan man bestĂ€mmer sig för nĂ€sta steg. Mer sofistikerade tillvĂ€gagĂ„ngssĂ€tt behövs för att lösa dessa problem.

Finite state-maskin

Finite state machine eller FSM (finite state machine) Ă€r ett sĂ€tt att sĂ€ga att vĂ„r agent för nĂ€rvarande befinner sig i ett av flera möjliga tillstĂ„nd, och att den kan övergĂ„ frĂ„n ett tillstĂ„nd till ett annat. Det finns ett visst antal sĂ„dana stater – dĂ€rav namnet. Det bĂ€sta exemplet frĂ„n livet Ă€r ett trafikljus. Det finns olika sekvenser av ljus pĂ„ olika platser, men principen Ă€r densamma - varje tillstĂ„nd representerar nĂ„got (stopp, gĂ„, etc.). Ett trafikljus Ă€r bara i ett tillstĂ„nd vid varje given tidpunkt och flyttar sig frĂ„n ett till ett annat baserat pĂ„ enkla regler.

Det Àr en liknande historia med NPC:er i spel. LÄt oss till exempel ta en vakt med följande tillstÄnd:

  • Patrullerar.
  • Att attackera.
  • Flyr.

Och dessa villkor för att Àndra dess tillstÄnd:

  • Om vakten ser fienden anfaller han.
  • Om vakten attackerar men inte lĂ€ngre ser fienden, Ă„tervĂ€nder han för att patrullera.
  • Om en vakt attackerar men blir svĂ„rt sĂ„rad, springer han ivĂ€g.

Du kan ocksÄ skriva if-statement med en vÀktartillstÄndsvariabel och olika kontroller: finns det en fiende i nÀrheten, vad Àr hÀlsonivÄn för NPC, etc. LÄt oss lÀgga till nÄgra fler tillstÄnd:

  • Sysslolöshet - mellan patrullerna.
  • Sökande - nĂ€r den uppmĂ€rksammade fienden har försvunnit.
  • Hitta hjĂ€lp - nĂ€r en fiende upptĂ€cks, men Ă€r för stark för att slĂ„ss ensam.

Valet för var och en av dem Àr begrÀnsat - till exempel kommer vakten inte att leta efter en dold fiende om han har lÄg hÀlsa.

Det finns trots allt en enorm lista med "om" , Den dÀr " kan bli för krÄngligt, sÄ vi mÄste formalisera en metod som gör att vi kan hÄlla tillstÄnd och övergÄngar mellan stater i Ätanke. För att göra detta tar vi hÀnsyn till alla stater, och under varje stat skriver vi ner i en lista alla övergÄngar till andra stater, tillsammans med de villkor som Àr nödvÀndiga för dem.

Hur man skapar en spel-AI: en guide för nybörjare

Detta Àr en tillstÄndsövergÄngstabell - ett heltÀckande sÀtt att representera FSM. LÄt oss rita ett diagram och fÄ en fullstÀndig översikt över hur NPC-beteendet förÀndras.

Hur man skapar en spel-AI: en guide för nybörjare

Diagrammet Äterspeglar kÀrnan i beslutsfattandet för denna agent baserat pÄ den aktuella situationen. Dessutom visar varje pil en övergÄng mellan tillstÄnd om villkoret bredvid den Àr sant.

Varje uppdatering kontrollerar vi agentens aktuella tillstÄnd, tittar igenom listan över övergÄngar, och om villkoren för övergÄngen Àr uppfyllda, accepterar den det nya tillstÄndet. Till exempel kontrollerar varje ram om 10-sekunderstimern har gÄtt ut, och i sÄ fall gÄr vakten frÄn tomgÄngstillstÄnd till patrullering. PÄ samma sÀtt kontrollerar den attackerande staten agentens hÀlsa - om den Àr lÄg gÄr den in i den flyende staten.

Detta Àr att hantera övergÄngar mellan stater, men hur Àr det med beteendet som Àr förknippat med staterna sjÀlva? NÀr det gÀller att implementera det faktiska beteendet för ett visst tillstÄnd, finns det vanligtvis tvÄ typer av "krok" dÀr vi tilldelar ÄtgÀrder till FSM:

  • ÅtgĂ€rder som vi regelbundet utför för det aktuella tillstĂ„ndet.
  • De Ă„tgĂ€rder vi vidtar nĂ€r vi övergĂ„r frĂ„n ett tillstĂ„nd till ett annat.

Exempel för den första typen. TillstÄndet Patrullering kommer att flytta agenten lÀngs patrullrutten för varje bildruta. Det attackerande tillstÄndet kommer att försöka initiera en attack varje bildruta eller övergÄng till ett tillstÄnd dÀr detta Àr möjligt.

För den andra typen, övervÀga övergÄngen "om fienden Àr synlig och fienden Àr för stark, gÄ sedan till lÀget Hitta hjÀlp. Agenten mÄste vÀlja var den ska vÀnda sig för att fÄ hjÀlp och lagra denna information sÄ att tillstÄndet Hitta hjÀlp vet vart det ska gÄ. NÀr hjÀlp har hittats gÄr agenten tillbaka till den attackerande staten. Vid det hÀr laget kommer han att vilja berÀtta för allierade om hotet, sÄ att NotifyFriendOfThreat-ÄtgÀrden kan intrÀffa.

Återigen kan vi titta pĂ„ detta system genom linsen av Sense/Think/Act-cykeln. Sense finns i data som anvĂ€nds av övergĂ„ngslogiken. TĂ€nk - övergĂ„ngar tillgĂ€ngliga i varje stat. Och Act utförs av Ă„tgĂ€rder som utförs periodiskt inom en stat eller vid övergĂ„ngar mellan stater.

Ibland kan det vara kostsamt att kontinuerligt avlÀsa övergÄngsförhÄllanden. Till exempel, om varje agent utför komplexa berÀkningar varje bildruta för att avgöra om den kan se fiender och förstÄ om den kan övergÄ frÄn patrullerande till attackerande tillstÄnd, kommer detta att ta mycket CPU-tid.

Viktiga förÀndringar i vÀrldens tillstÄnd kan ses som hÀndelser som kommer att bearbetas nÀr de intrÀffar. IstÀllet för att FSM kontrollerar övergÄngsvillkoret "kan min agent se spelaren?" varje bildruta, kan ett separat system konfigureras för att kontrollera mindre ofta (t.ex. 5 gÄnger per sekund). Och resultatet Àr att utfÀrda Player Seen nÀr checken passerar.

Detta skickas till FSM, som nu ska gÄ till lÀget Player Seen-hÀndelse mottagen och svara dÀrefter. Det resulterande beteendet Àr detsamma förutom en nÀstan omÀrklig fördröjning innan svar. Men prestandan har förbÀttrats som ett resultat av att Sense-delen delas upp i en separat del av programmet.

Hierarkisk finita tillstÄndsmaskin

Det Ă€r dock inte alltid bekvĂ€mt att arbeta med stora FSM. Om vi ​​vill utöka attacktillstĂ„ndet för att separera MeleeAttacking och RangedAttacking, mĂ„ste vi Ă€ndra övergĂ„ngarna frĂ„n alla andra tillstĂ„nd som leder till Attacking state (nuvarande och framtida).

Du har sĂ€kert mĂ€rkt att i vĂ„rt exempel finns det mĂ„nga dubbla övergĂ„ngar. De flesta övergĂ„ngar i tomgĂ„ngstillstĂ„nd Ă€r identiska med övergĂ„ngar i patrullerande tillstĂ„nd. Det skulle vara trevligt att inte upprepa oss sjĂ€lva, sĂ€rskilt om vi lĂ€gger till fler liknande tillstĂ„nd. Det Ă€r vettigt att gruppera tomgĂ„ng och patrullering under den allmĂ€nna etiketten "icke-strid", dĂ€r det bara finns en gemensam uppsĂ€ttning övergĂ„ngar till stridsstater. Om vi ​​tĂ€nker pĂ„ denna etikett som en stat, dĂ„ blir tomgĂ„ng och patrullering undertillstĂ„nd. Ett exempel pĂ„ att anvĂ€nda en separat övergĂ„ngstabell för ett nytt icke-stridsunderlĂ€ge:

Huvudstater:
Hur man skapar en spel-AI: en guide för nybörjare

Status utanför strid:
Hur man skapar en spel-AI: en guide för nybörjare

Och i diagramform:

Hur man skapar en spel-AI: en guide för nybörjare

Det Àr samma system, men med ett nytt icke-stridstillstÄnd som inkluderar tomgÄng och patrullering. Med varje tillstÄnd som innehÄller en FSM med undertillstÄnd (och dessa undertillstÄnd i sin tur innehÄller sina egna FSMs - och sÄ vidare sÄ lÀnge du behöver), fÄr vi en Hierarchical Finite State Machine eller HFSM (hierarchical finite state machine). Genom att gruppera den icke-stridande staten klipper vi bort ett gÀng redundanta övergÄngar. Vi kan göra detsamma för alla nya stater med gemensamma övergÄngar. Till exempel, om vi i framtiden utökar Attacking-staten till MeleeAttacking- och MissileAttacking-staterna, kommer de att vara substater som övergÄr mellan varandra baserat pÄ avstÄnd till fienden och ammunition. Som ett resultat kan komplexa beteenden och subbeteenden representeras med ett minimum av dubbla övergÄngar.

BeteendetrÀd

Med HFSM skapas komplexa kombinationer av beteenden pÄ ett enkelt sÀtt. Det finns dock en viss svÄrighet att beslutsfattande i form av övergÄngsregler Àr nÀra relaterat till det nuvarande tillstÄndet. Och i mÄnga spel Àr det precis vad som behövs. Och noggrann anvÀndning av statlig hierarki kan minska antalet övergÄngsupprepningar. Men ibland behöver du regler som fungerar oavsett vilket tillstÄnd du befinner dig i, eller som gÀller i nÀstan alla stater. Till exempel, om en agents hÀlsa sjunker till 25 %, vill du att han ska springa ivÀg oavsett om han var i strid, ledig eller pratade - du mÄste lÀgga till detta tillstÄnd till varje stat. Och om din designer senare vill Àndra den lÄga hÀlsotröskeln frÄn 25 % till 10 %, mÄste detta göras igen.

Helst krÀver denna situation ett system dÀr beslut om "vilket tillstÄnd man ska vara i" ligger utanför staterna sjÀlva, för att göra förÀndringar endast pÄ ett stÀlle och inte röra övergÄngsvillkoren. BeteendetrÀd visas hÀr.

Det finns flera sÀtt att implementera dem, men essensen Àr ungefÀr densamma för alla och liknar ett beslutstrÀd: algoritmen börjar med en "rot"-nod och trÀdet innehÄller noder som representerar antingen beslut eller ÄtgÀrder. Det finns dock nÄgra viktiga skillnader:

  • Noder returnerar nu ett av tre vĂ€rden: Lyckades (om jobbet Ă€r slutfört), Misslyckades (om det inte kan startas) eller Körs (om det fortfarande körs och det inte finns nĂ„got slutresultat).
  • Det finns inga fler beslutsnoder att vĂ€lja mellan tvĂ„ alternativ. IstĂ€llet Ă€r de dekorationsnoder, som har en barnnod. Om de lyckas, kör de sin enda underordnade nod.
  • Noder som utför Ă„tgĂ€rder returnerar ett körvĂ€rde för att representera de Ă„tgĂ€rder som utförs.

Denna lilla uppsÀttning noder kan kombineras för att skapa ett stort antal komplexa beteenden. LÄt oss förestÀlla oss HFSM-vakten frÄn föregÄende exempel som ett beteendetrÀd:

Hur man skapar en spel-AI: en guide för nybörjare

Med denna struktur bör det inte finnas nÄgon uppenbar övergÄng frÄn tomgÄngs-/patrullerande tillstÄnd till attackerande eller nÄgon annan stat. Om en fiende Àr synlig och karaktÀrens hÀlsa Àr lÄg, kommer avrÀttningen att stanna vid den flyende noden, oavsett vilken nod den tidigare utförde - patrullerande, tomgÄng, attackerande eller nÄgon annan.

Hur man skapar en spel-AI: en guide för nybörjare

BeteendetrĂ€d Ă€r komplexa – det finns mĂ„nga sĂ€tt att komponera dem, och att hitta rĂ€tt kombination av dekoratörer och sammansatta noder kan vara utmanande. Det finns ocksĂ„ frĂ„gor om hur ofta man ska kontrollera trĂ€det - vill vi gĂ„ igenom varje del av det eller bara nĂ€r ett av förutsĂ€ttningarna har Ă€ndrats? Hur lagrar vi tillstĂ„nd för noder - hur vet vi nĂ€r vi har varit vilande i 10 sekunder, eller hur vet vi vilka noder som kördes förra gĂ„ngen sĂ„ att vi kan bearbeta sekvensen korrekt?

Det Àr dÀrför det finns mÄnga implementeringar. Till exempel har vissa system ersatt dekoratornoder med inlinedekoratorer. De omvÀrderar trÀdet nÀr dekorationsförhÄllandena Àndras, hjÀlper till att ansluta noder och tillhandahÄller regelbundna uppdateringar.

Verktygsbaserat system

Vissa spel har mÄnga olika mekaniker. Det Àr önskvÀrt att de fÄr alla fördelar med enkla och allmÀnna övergÄngsregler, men inte nödvÀndigtvis i form av ett komplett beteendetrÀd. IstÀllet för att ha en tydlig uppsÀttning val eller ett trÀd med möjliga ÄtgÀrder Àr det lÀttare att undersöka alla ÄtgÀrder och vÀlja den mest lÀmpliga för tillfÀllet.

Det Utility-baserade systemet hjÀlper till med just detta. Detta Àr ett system dÀr agenten har en mÀngd olika ÄtgÀrder och vÀljer vilka som ska utföras baserat pÄ den relativa nyttan av var och en. DÀr nyttan Àr ett godtyckligt mÄtt pÄ hur viktigt eller önskvÀrt det Àr för agenten att utföra denna ÄtgÀrd.

Den berÀknade nyttan av en ÄtgÀrd baserat pÄ det aktuella tillstÄndet och miljön, agenten kan kontrollera och vÀlja det mest lÀmpliga andra tillstÄndet nÀr som helst. Detta liknar FSM, förutom dÀr övergÄngar bestÀms av en uppskattning för varje potentiellt tillstÄnd, inklusive det nuvarande. Observera att vi vÀljer den mest anvÀndbara ÄtgÀrden för att gÄ vidare (eller stanna om vi redan har slutfört den). För mer variation kan detta vara ett balanserat men slumpmÀssigt urval frÄn en liten lista.

Systemet tilldelar ett godtyckligt intervall av nyttovÀrden, till exempel frÄn 0 (helt oönskat) till 100 (helt önskvÀrt). Varje ÄtgÀrd har ett antal parametrar som pÄverkar berÀkningen av detta vÀrde. För att ÄtergÄ till vÄrt exempel pÄ vÄr vÄrdnadshavare:

Hur man skapar en spel-AI: en guide för nybörjare

ÖvergĂ„ngar mellan handlingar Ă€r tvetydiga - vilket tillstĂ„nd som helst kan följa vilket som helst annat. ÅtgĂ€rdsprioriteringar finns i de returnerade nyttovĂ€rdena. Om en fiende Ă€r synlig, och den fienden Ă€r stark, och karaktĂ€rens hĂ€lsa Ă€r lĂ„g, kommer bĂ„de Fly och FindingHelp att returnera höga vĂ€rden som inte Ă€r noll. I det hĂ€r fallet kommer FindingHelp alltid att vara högre. PĂ„ samma sĂ€tt ger icke-stridsaktiviteter aldrig mer Ă€n 50, sĂ„ de kommer alltid att vara lĂ€gre Ă€n stridsaktiviteter. Du mĂ„ste ta hĂ€nsyn till detta nĂ€r du skapar Ă„tgĂ€rder och berĂ€knar deras nytta.

I vÄrt exempel returnerar ÄtgÀrderna antingen ett fast konstant vÀrde eller ett av tvÄ fasta vÀrden. Ett mer realistiskt system skulle returnera en uppskattning frÄn ett kontinuerligt vÀrdeintervall. Till exempel, Flyt-ÄtgÀrden returnerar högre nyttovÀrden om agentens hÀlsa Àr lÄg, och Attack-ÄtgÀrden returnerar lÀgre nyttovÀrden om fienden Àr för stark. PÄ grund av detta har FlytÄtgÀrden företrÀde framför Attack i alla situationer dÀr agenten kÀnner att han inte har tillrÀckligt med hÀlsa för att besegra fienden. Detta gör att ÄtgÀrder kan prioriteras baserat pÄ ett valfritt antal kriterier, vilket gör detta tillvÀgagÄngssÀtt mer flexibelt och variabelt Àn ett beteendetrÀd eller FSM.

Varje ÄtgÀrd har mÄnga villkor för programberÀkning. De kan skrivas i skriptsprÄk eller som en serie matematiska formler. The Sims, som simulerar en karaktÀrs dagliga rutin, lÀgger till ett extra lager av berÀkningar - agenten fÄr en serie "motivationer" som pÄverkar nyttobetyg. Om en karaktÀr Àr hungrig kommer de att bli Ànnu hungrigare med tiden, och nyttovÀrdet för EatFood-ÄtgÀrden kommer att öka tills karaktÀren utför det, vilket minskar hungernivÄn och ÄterstÀller EatFood-vÀrdet till noll.

Idén med att vÀlja ÄtgÀrder baserat pÄ ett klassificeringssystem Àr ganska enkel, sÄ ett Utility-baserat system kan anvÀndas som en del av AI-beslutsprocesser, snarare Àn som en komplett ersÀttning för dem. BeslutstrÀdet kan begÀra en nyttoklassificering av tvÄ underordnade noder och vÀlja den högre. PÄ liknande sÀtt kan ett beteendetrÀd ha en sammansatt Utility-nod för att utvÀrdera nyttan av ÄtgÀrder för att bestÀmma vilket barn som ska utföras.

Rörelse och navigering

I de tidigare exemplen hade vi en plattform som vi flyttade till vĂ€nster eller höger, och en vakt som patrullerade eller attackerade. Men exakt hur hanterar vi agentrörelser över en tidsperiod? Hur stĂ€ller vi in ​​hastighet, hur undviker vi hinder och hur planerar vi en rutt nĂ€r det Ă€r svĂ„rare att ta sig till en destination Ă€n att bara röra oss i en rak linje? LĂ„t oss titta pĂ„ det hĂ€r.

УпраĐČĐ»Đ”ĐœĐžĐ”

I det inledande skedet kommer vi att anta att varje agent har ett hastighetsvÀrde, som inkluderar hur snabbt den rör sig och i vilken riktning. Det kan mÀtas i meter per sekund, kilometer per timme, pixlar per sekund, etc. NÀr vi Äterkallar Sense/Think/Act-loopen kan vi förestÀlla oss att Think-delen vÀljer en hastighet och Act-delen tillÀmpar den hastigheten pÄ agenten. Vanligtvis har spel ett fysiksystem som gör denna uppgift Ät dig, lÀr dig hastighetsvÀrdet för varje objekt och justerar det. DÀrför kan du lÀmna AI med en uppgift - att bestÀmma vilken hastighet agenten ska ha. Om du vet var agenten ska vara mÄste du flytta den i rÀtt riktning med en instÀlld hastighet. En mycket trivial ekvation:

önskad_resa = destination_position – agent_position

FörestÀll dig en 2D-vÀrld. Agenten Àr vid punkt (-2,-2), destinationen Àr nÄgonstans i nordost vid punkt (30, 20), och den erforderliga vÀgen för agenten att ta sig dit Àr (32, 22). LÄt oss sÀga att dessa positioner mÀts i meter - om vi tar agentens hastighet till 5 meter per sekund, sÄ kommer vi att skala vÄr förskjutningsvektor och fÄ en hastighet pÄ ungefÀr (4.12, 2.83). Med dessa parametrar skulle agenten anlÀnda till sin destination pÄ nÀstan 8 sekunder.

Du kan nÀr som helst rÀkna om vÀrdena. Om agenten var halvvÀgs till mÄlet skulle rörelsen vara halva lÀngden, men eftersom agentens maxhastighet Àr 5 m/s (vi bestÀmde detta ovan) blir hastigheten densamma. Detta fungerar Àven för rörliga mÄl, vilket gör att agenten kan göra smÄ Àndringar nÀr de rör sig.

Men vi vill ha mer variation – till exempel att lĂ„ngsamt öka hastigheten för att simulera en karaktĂ€r som gĂ„r frĂ„n stĂ„ende till löpande. Samma sak kan göras i slutet innan du stoppar. Dessa funktioner Ă€r kĂ€nda som styrbeteenden, som var och en har specifika namn: Sök, Fly, Ankomst, etc. Tanken Ă€r att accelerationskrafter kan appliceras pĂ„ agentens hastighet, baserat pĂ„ att jĂ€mföra agentens position och aktuella hastighet med destinationen i för att anvĂ€nda olika metoder för att förflytta sig till mĂ„let.

Varje beteende har ett lite olika syfte. Sök och ankomst Àr sÀtt att flytta en agent till en destination. Hinderundvikande och -separation justerar agentens rörelse för att undvika hinder pÄ vÀgen mot mÄlet. Anpassning och sammanhÄllning hÄller agenter i rörelse. Valfritt antal olika styrbeteenden kan summeras för att producera en enda vÀgvektor med hÀnsyn till alla faktorer. En agent som anvÀnder beteendena Ankomst, Separation och Hinderundvikande för att hÄlla sig borta frÄn vÀggar och andra agenter. Detta tillvÀgagÄngssÀtt fungerar bra pÄ öppna platser utan onödiga detaljer.

Under svĂ„rare förhĂ„llanden fungerar tillĂ€gg av olika beteenden sĂ€mre – till exempel kan en agent fastna i en vĂ€gg pĂ„ grund av en konflikt mellan Ankomst och Hinderundvikande. DĂ€rför mĂ„ste du övervĂ€ga alternativ som Ă€r mer komplexa Ă€n att bara lĂ€gga till alla vĂ€rden. SĂ€ttet Ă€r detta: istĂ€llet för att lĂ€gga ihop resultaten av varje beteende kan du övervĂ€ga rörelse i olika riktningar och vĂ€lja det bĂ€sta alternativet.

Men i en komplex miljö med ÄtervÀndsgrÀnder och val om vilken vÀg vi ska gÄ, kommer vi att behöva nÄgot Ànnu mer avancerat.

Att hitta ett sÀtt

Styrbeteenden Àr bra för enkel rörelse pÄ ett öppet omrÄde (fotbollsplan eller arena) dÀr att ta sig frÄn A till B Àr en rak vÀg med endast mindre omvÀgar runt hinder. För komplexa rutter behöver vi pathfinding, vilket Àr ett sÀtt att utforska vÀrlden och bestÀmma en rutt genom den.

Det enklaste Àr att applicera ett rutnÀt pÄ varje ruta bredvid agenten och utvÀrdera vilka av dem som fÄr flytta. Om en av dem Àr en destination, följ sedan rutten frÄn varje ruta till den föregÄende tills du nÄr början. Det hÀr Àr rutten. Annars upprepar du processen med andra rutor i nÀrheten tills du hittar din destination eller tills du fÄr slut pÄ rutor (vilket betyder att det inte finns nÄgon möjlig vÀg). Detta Àr vad som formellt kallas Breadth-First Search eller BFS (breadth-first search algorithm). Vid varje steg tittar han Ät alla hÄll (dÀrav bredd, "bredd"). Sökutrymmet Àr som en vÄgfront som rör sig tills den nÄr önskad plats - sökutrymmet expanderar vid varje steg tills slutpunkten ingÄr, varefter den kan spÄras tillbaka till början.

Hur man skapar en spel-AI: en guide för nybörjare

Som ett resultat kommer du att fÄ en lista med rutor lÀngs vilka den önskade rutten sammanstÀlls. Detta Àr sökvÀgen (dÀrav sökvÀg) - en lista över platser som agenten kommer att besöka nÀr han följer destinationen.

Med tanke pÄ att vi kÀnner till positionen för varje ruta i vÀrlden kan vi anvÀnda styrbeteenden för att förflytta oss lÀngs banan - frÄn nod 1 till nod 2, sedan frÄn nod 2 till nod 3, och sÄ vidare. Det enklaste alternativet Àr att gÄ mot mitten av nÀsta ruta, men ett Ànnu bÀttre alternativ Àr att stanna i mitten av kanten mellan nuvarande ruta och nÀsta. PÄ grund av detta kommer agenten att kunna skÀra hörn vid skarpa svÀngar.

BFS-algoritmen har ocksĂ„ nackdelar - den utforskar lika mĂ„nga rutor i "fel" riktning som i "rĂ€tt" riktning. Det Ă€r hĂ€r en mer komplex algoritm som kallas A* (A star) kommer in i bilden. Det fungerar pĂ„ samma sĂ€tt, men istĂ€llet för att blint undersöka grannruta (sedan grannar till grannar, sedan grannar till grannar till grannar och sĂ„ vidare), samlar den noderna till en lista och sorterar dem sĂ„ att nĂ€sta nod som undersöks alltid Ă€r den en som leder till den kortaste vĂ€gen. Noder sorteras baserat pĂ„ en heuristik som tar hĂ€nsyn till tvĂ„ saker – "kostnaden" för en hypotetisk rutt till det önskade torget (inklusive eventuella resekostnader) och en uppskattning av hur lĂ„ngt torget Ă€r frĂ„n destinationen (som förargar sökningen i rĂ€tt riktning).

Hur man skapar en spel-AI: en guide för nybörjare

Det hÀr exemplet visar att agenten utforskar en ruta i taget och varje gÄng vÀljer den intilliggande som Àr mest lovande. Den resulterande vÀgen Àr densamma som BFS, men fÀrre rutor övervÀgdes i processen - vilket har en stor inverkan pÄ spelets prestanda.

Rörelse utan rutnÀt

Men de flesta spel Àr inte upplagda pÄ ett rutnÀt, och det Àr ofta omöjligt att göra det utan att offra realism. Kompromisser behövs. Vilken storlek ska rutorna ha? För stora och de kommer inte att kunna representera smÄ korridorer eller svÀngar korrekt, för smÄ och det kommer att finnas för mÄnga rutor att söka efter, vilket i slutÀndan kommer att ta mycket tid.

Det första att förstÄ Àr att ett nÀt ger oss en graf över anslutna noder. A*- och BFS-algoritmerna fungerar faktiskt pÄ grafer och bryr sig inte om vÄrt mesh alls. Vi skulle kunna placera noder var som helst i spelvÀrlden: sÄ lÀnge det finns en koppling mellan tvÄ anslutna noder, sÄvÀl som mellan start- och slutpunkterna och Ätminstone en av noderna, kommer algoritmen att fungera lika bra som tidigare. Detta kallas ofta ett waypointsystem, eftersom varje nod representerar en betydande position i vÀrlden som kan vara en del av ett valfritt antal hypotetiska banor.

Hur man skapar en spel-AI: en guide för nybörjare
Exempel 1: en knut i varje ruta. Sökningen startar frÄn noden dÀr agenten finns och slutar vid noden för den önskade kvadraten.

Hur man skapar en spel-AI: en guide för nybörjare
Exempel 2: En mindre uppsÀttning noder (waypoints). Sökningen startar vid agentens ruta, gÄr igenom det antal noder som krÀvs och fortsÀtter sedan till destinationen.

Detta Àr ett helt flexibelt och kraftfullt system. Men viss försiktighet behövs för att bestÀmma var och hur en waypoint ska placeras, annars kanske agenter helt enkelt inte ser den nÀrmaste punkten och kommer inte att kunna starta vÀgen. Det skulle vara lÀttare om vi automatiskt kunde placera waypoints baserat pÄ vÀrldens geometri.

Det Àr hÀr navigeringsnÀtet eller navmesh (navigationsnÀt) visas. Detta Àr vanligtvis ett 2D-nÀt av trianglar som Àr överlagrat pÄ vÀrldens geometri - varhelst agenten tillÄts gÄ. Var och en av trianglarna i nÀtet blir en nod i grafen och har upp till tre intilliggande trianglar som blir intilliggande noder i grafen.

Den hÀr bilden Àr ett exempel frÄn Unity-motorn - den analyserade geometrin i vÀrlden och skapade ett navmesh (i skÀrmdumpen i ljusblÄtt). Varje polygon i ett navmesh Àr ett omrÄde dÀr en agent kan stÄ eller flytta frÄn en polygon till en annan polygon. I det hÀr exemplet Àr polygonerna mindre Àn vÄningarna de Àr placerade pÄ - detta görs för att ta hÀnsyn till storleken pÄ agenten, som kommer att strÀcka sig bortom dess nominella position.

Hur man skapar en spel-AI: en guide för nybörjare

Vi kan söka efter en rutt genom detta mesh, Äterigen med hjÀlp av A*-algoritmen. Detta kommer att ge oss en nÀstan perfekt rutt i vÀrlden, som tar hÀnsyn till all geometri och inte krÀver onödiga noder och skapande av waypoints.

Pathfinding Àr ett för brett Àmne för vilket ett avsnitt i en artikel inte rÀcker. Om du vill studera det mer i detalj, kommer detta att hjÀlpa Amit Patels hemsida.

planering

Vi har lĂ€rt oss med pathfinding att ibland rĂ€cker det inte att bara vĂ€lja en riktning och flytta – vi mĂ„ste vĂ€lja en rutt och göra nĂ„gra svĂ€ngar för att komma till vĂ„r önskade destination. Vi kan generalisera denna idĂ©: att uppnĂ„ ett mĂ„l Ă€r inte bara nĂ€sta steg, utan en hel sekvens dĂ€r du ibland behöver se framĂ„t flera steg för att ta reda pĂ„ vad det första ska vara. Detta kallas planering. Pathfinding kan ses som en av flera förlĂ€ngningar av planering. NĂ€r det gĂ€ller vĂ„r Sense/Think/Act-cykel Ă€r det hĂ€r som Think-delen planerar flera Act-delar för framtiden.

LÄt oss titta pÄ exemplet med brÀdspelet Magic: The Gathering. Vi gÄr först med följande uppsÀttning kort i vÄra hÀnder:

  • Swamp - Ger 1 svart mana (landkort).
  • Skog - ger 1 grön mana (landkort).
  • Fugitive Wizard - KrĂ€ver 1 blĂ„ mana för att kalla.
  • Elvish Mystic - KrĂ€ver 1 grön mana för att kalla.

Vi ignorerar de ÄterstÄende tre korten för att göra det lÀttare. Enligt reglerna fÄr en spelare spela 1 landkort per tur, han kan "knacka" pÄ detta kort för att extrahera mana frÄn det, och sedan kasta trollformler (inklusive kalla en varelse) enligt mÀngden mana. I den hÀr situationen vet den mÀnskliga spelaren att han ska spela Forest, trycka pÄ 1 grön mana och sedan kalla pÄ Elvish Mystic. Men hur kan spelets AI ta reda pÄ detta?

Enkel planering

Det triviala tillvÀgagÄngssÀttet Àr att prova varje ÄtgÀrd i tur och ordning tills det inte finns nÄgra lÀmpliga kvar. Genom att titta pÄ korten ser AI:n vad Swamp kan spela. Och han spelar det. Finns det nÄgra andra ÄtgÀrder kvar denna svÀng? Den kan inte tillkalla vare sig Elvish Mystic eller Fugitive Wizard, eftersom de krÀver grön respektive blÄ mana för att tillkalla dem, medan Swamp bara tillhandahÄller svart mana. Och han kommer inte lÀngre att kunna spela Forest, eftersom han redan har spelat Swamp. SÄledes följde spelet AI reglerna, men gjorde det dÄligt. Kan förbÀttras.

Planering kan hitta en lista över ÄtgÀrder som för spelet till önskat tillstÄnd. Precis som varje ruta pÄ en stig hade grannar (vid vÀgsökning), har varje ÄtgÀrd i en plan ocksÄ grannar eller efterföljare. Vi kan leta efter dessa ÄtgÀrder och efterföljande ÄtgÀrder tills vi nÄr önskat tillstÄnd.

I vÄrt exempel Àr det önskade resultatet "kalla en varelse om möjligt." I början av omgÄngen ser vi bara tvÄ möjliga handlingar tillÄtna enligt spelets regler:

1. Spela Swamp (resultat: Swamp i spelet)
2. Spela Skog (resultat: Skog i spelet)

Varje ÄtgÀrd som vidtas kan leda till ytterligare handlingar och stÀnga andra, igen beroende pÄ spelets regler. FörestÀll dig att vi spelade Swamp - detta tar bort Swamp som nÀsta steg (vi har redan spelat det), och detta tar ocksÄ bort Forest (eftersom du enligt reglerna kan spela ett landkort per tur). Efter detta lÀgger AI till att fÄ 1 svart mana som nÀsta steg eftersom det inte finns nÄgra andra alternativ. Om han gÄr vidare och vÀljer Tap the Swamp, kommer han att fÄ 1 enhet svart mana och kommer inte att kunna göra nÄgot med den.

1. Spela Swamp (resultat: Swamp i spelet)
1.1 "Tap" Swamp (resultat: Swamp "tapped", +1 enhet svart mana)
Inga ÄtgÀrder tillgÀngliga - END
2. Spela Skog (resultat: Skog i spelet)

Listan över ÄtgÀrder var kort, vi kom till en ÄtervÀndsgrÀnd. Vi upprepar processen för nÀsta steg. Vi spelar Forest, öppnar ÄtgÀrden "fÄ 1 grön mana", som i sin tur kommer att öppna den tredje ÄtgÀrden - kalla pÄ Elvish Mystic.

1. Spela Swamp (resultat: Swamp i spelet)
1.1 "Tap" Swamp (resultat: Swamp "tapped", +1 enhet svart mana)
Inga ÄtgÀrder tillgÀngliga - END
2. Spela Skog (resultat: Skog i spelet)
2.1 "Tapp" Forest (resultat: Skogen "tappas", +1 enhet grön mana)
2.1.1 Summon Elvish Mystic (resultat: Elvish Mystic i spel, -1 grön mana)
Inga ÄtgÀrder tillgÀngliga - END

Slutligen undersökte vi alla möjliga ÄtgÀrder och hittade en plan som kallar fram en varelse.

Detta Ă€r ett mycket förenklat exempel. Det Ă€r tillrĂ„dligt att vĂ€lja den bĂ€sta möjliga planen, snarare Ă€n bara vilken plan som helst som uppfyller vissa kriterier. Det Ă€r i allmĂ€nhet möjligt att utvĂ€rdera potentiella planer baserat pĂ„ resultatet eller den totala nyttan av deras genomförande. Du kan fĂ„ dig sjĂ€lv 1 poĂ€ng för att spela ett landkort och 3 poĂ€ng för att kalla fram en varelse. Att spela Swamp skulle vara en 1 poĂ€ng plan. Och att spela Skog → Tryck pĂ„ Skogen → kalla pĂ„ Elvish Mystic ger omedelbart 4 poĂ€ng.

SÄ fungerar planering i Magic: The Gathering, men samma logik gÀller i andra situationer. Till exempel att flytta en bonde för att göra plats för biskopen att röra sig i schack. Eller ta skydd bakom en vÀgg för att sÀkert fotografera i XCOM sÄ hÀr. I allmÀnhet förstÄr du idén.

FörbÀttrad planering

Ibland finns det för mÄnga potentiella ÄtgÀrder för att övervÀga alla möjliga alternativ. För att ÄtergÄ till exemplet med Magic: The Gathering: lÄt oss sÀga att i spelet och i din hand finns det flera land- och varelsekort - antalet möjliga kombinationer av drag kan vara i dussintals. Det finns flera lösningar pÄ problemet.

Den första metoden Àr kedja bakÄt. IstÀllet för att prova alla kombinationer Àr det bÀttre att börja med det slutliga resultatet och försöka hitta en direkt vÀg. IstÀllet för att gÄ frÄn trÀdets rot till ett specifikt blad, rör vi oss i motsatt riktning - frÄn bladet till roten. Denna metod Àr enklare och snabbare.

Om fienden har 1 hÀlsa kan du hitta planen "deal 1 or more damage". För att uppnÄ detta mÄste ett antal villkor vara uppfyllda:

1. Skador kan orsakas av en besvÀrjelse - den mÄste vara i handen.
2. För att besvÀrja behöver du mana.
3. För att fÄ mana mÄste du spela ett landkort.
4. För att spela ett landkort mÄste du ha det pÄ handen.

Ett annat sÀtt Àr bÀst-först-sökning. IstÀllet för att prova alla vÀgar vÀljer vi den lÀmpligaste. Oftast ger denna metod den optimala planen utan onödiga sökkostnader. A* Àr en form av bÀsta första sökning - genom att undersöka de mest lovande rutterna frÄn början kan den redan hitta den bÀsta vÀgen utan att behöva kontrollera andra alternativ.

Ett intressant och allt mer populÀrt bÀsta-första-sökalternativ Àr Monte Carlo Tree Search. IstÀllet för att gissa vilka planer som Àr bÀttre Àn andra nÀr man vÀljer varje efterföljande ÄtgÀrd, vÀljer algoritmen slumpmÀssiga efterföljare vid varje steg tills den nÄr slutet (nÀr planen resulterade i seger eller nederlag). Det slutliga resultatet anvÀnds sedan för att öka eller minska vikten av tidigare alternativ. Genom att upprepa denna process flera gÄnger i rad ger algoritmen en bra uppskattning av vad det bÀsta nÀsta draget Àr, Àven om situationen förÀndras (om fienden vidtar ÄtgÀrder för att störa spelaren).

Ingen berĂ€ttelse om planering i spel skulle vara komplett utan mĂ„lorienterad handlingsplanering eller GOAP (mĂ„lorienterad handlingsplanering). Detta Ă€r en mycket anvĂ€nd och diskuterad metod, men förutom nĂ„gra fĂ„ utmĂ€rkande detaljer Ă€r det i huvudsak den bakĂ„tkedjemetoden vi pratade om tidigare. Om mĂ„let var att "förstöra spelaren" och spelaren Ă€r bakom skydd, kan planen vara: förstöra med en granat → hĂ€mta den → kasta den.

Det finns vanligtvis flera mÄl, var och en med sin egen prioritet. Om det högsta prioriterade mÄlet inte kan fullföljas (ingen kombination av ÄtgÀrder skapar en "döda spelaren"-plan eftersom spelaren inte Àr synlig), kommer AI:n att falla tillbaka till lÀgre prioriterade mÄl.

TrÀning och anpassning

Vi har redan sagt att spel AI vanligtvis inte anvÀnder maskininlÀrning eftersom det inte Àr lÀmpligt för att hantera agenter i realtid. Men det betyder inte att du inte kan lÄna nÄgot frÄn detta omrÄde. Vi vill ha en motstÄndare i en skytt som vi kan lÀra oss nÄgot av. Ta till exempel reda pÄ de bÀsta positionerna pÄ kartan. Eller en motstÄndare i ett fightingspel som skulle blockera spelarens ofta anvÀnda kombinationsrörelser och motivera honom att anvÀnda andra. SÄ maskininlÀrning kan vara ganska anvÀndbar i sÄdana situationer.

Statistik och sannolikheter

Innan vi gÄr in pÄ komplexa exempel, lÄt oss se hur lÄngt vi kan gÄ genom att ta nÄgra enkla mÀtningar och anvÀnda dem för att fatta beslut. Till exempel realtidsstrategi - hur avgör vi om en spelare kan starta en attack under de första minuterna av spelet och vilket försvar för att förbereda sig mot detta? Vi kan studera en spelares tidigare erfarenheter för att förstÄ vilka framtida reaktioner kan vara. Till att börja med har vi inte sÄdana rÄdata, men vi kan samla in dem - varje gÄng AI:n spelar mot en mÀnniska kan den registrera tiden för den första attacken. Efter nÄgra sessioner kommer vi att fÄ ett snitt av den tid det tar för spelaren att anfalla i framtiden.

Det finns ocksÄ ett problem med genomsnittliga vÀrden: om en spelare rusade 20 gÄnger och spelade lÄngsamt 20 gÄnger, kommer de nödvÀndiga vÀrdena att vara nÄgonstans i mitten, och detta kommer inte att ge oss nÄgot anvÀndbart. En lösning Àr att begrÀnsa indata - de sista 20 bitarna kan tas med i berÀkningen.

Ett liknande tillvÀgagÄngssÀtt anvÀnds nÀr man uppskattar sannolikheten för vissa handlingar genom att anta att spelarens tidigare preferenser kommer att vara desamma i framtiden. Om en spelare attackerar oss fem gÄnger med eldboll, tvÄ gÄnger med blixt och en gÄng med nÀrstrid, Àr det uppenbart att han föredrar eldboll. LÄt oss extrapolera och se sannolikheten att anvÀnda olika vapen: eldklot=62,5%, blixt=25% och nÀrstrid=12,5%. VÄrt spel-AI mÄste förbereda sig för att skydda sig mot eld.

En annan intressant metod Àr att anvÀnda Naive Bayes Classifier för att studera stora mÀngder indata och klassificera situationen sÄ att AI:n reagerar pÄ önskat sÀtt. Bayesianska klassificerare Àr mest kÀnda för sin anvÀndning i spamfilter för e-post. DÀr undersöker de orden, jÀmför dem med var de orden har förekommit tidigare (i skrÀppost eller inte), och drar slutsatser om inkommande e-postmeddelanden. Vi kan göra samma sak Àven med fÀrre input. Baserat pÄ all anvÀndbar information som AI ser (som vilka fiendeenheter som skapas, eller vilka trollformler de anvÀnder, eller vilka tekniker de undersökte), och det slutliga resultatet (krig eller fred, rusa eller försvara, etc.) - vi kommer att vÀlja önskat AI-beteende.

Alla dessa trÀningsmetoder Àr tillrÀckliga, men det Àr tillrÄdligt att anvÀnda dem baserat pÄ testdata. AI:n kommer att lÀra sig att anpassa sig till de olika strategier som dina speltestare har anvÀnt. AI som anpassar sig till spelaren efter release kan bli för förutsÀgbar eller för svÄr att besegra.

VĂ€rdebaserad anpassning

Med tanke pÄ innehÄllet i vÄr spelvÀrld och reglerna kan vi Àndra uppsÀttningen av vÀrden som pÄverkar beslutsfattande, snarare Àn att bara anvÀnda indata. Vi gör sÄ hÀr:

  • LĂ„t AI:n samla in data om vĂ€rldens tillstĂ„nd och viktiga hĂ€ndelser under spelet (enligt ovan).
  • LĂ„t oss Ă€ndra nĂ„gra viktiga vĂ€rden baserat pĂ„ dessa data.
  • Vi implementerar vĂ„ra beslut baserat pĂ„ att bearbeta eller utvĂ€rdera dessa vĂ€rderingar.

En agent har till exempel flera rum att vÀlja mellan pÄ en förstapersonsskjutarkarta. Varje rum har sitt eget vÀrde, som avgör hur önskvÀrt det Àr att besöka. AI:n vÀljer slumpmÀssigt vilket rum den ska gÄ till baserat pÄ vÀrdet. Agenten kommer dÄ ihÄg vilket rum han dödades i och minskar dess vÀrde (sannolikheten att han kommer tillbaka dit). PÄ samma sÀtt för den omvÀnda situationen - om agenten förstör mÄnga motstÄndare, ökar rummets vÀrde.

Markov modell

Vad hĂ€nder om vi anvĂ€nde den insamlade informationen för att göra förutsĂ€gelser? Om vi ​​kommer ihĂ„g varje rum vi ser en spelare i under en viss tid, kommer vi att förutsĂ€ga vilket rum spelaren kan gĂ„ till. Genom att spĂ„ra och registrera spelarens rörelser över rum (vĂ€rden) kan vi förutsĂ€ga dem.

LÄt oss ta tre rum: röd, grön och blÄ. Och Àven observationerna som vi spelade in nÀr vi tittade pÄ spelsessionen:

Hur man skapar en spel-AI: en guide för nybörjare

Antalet observationer i varje rum Àr nÀstan lika stort - vi vet fortfarande inte var vi ska göra en bra plats för ett bakhÄll. Att samla in statistik kompliceras ocksÄ av Äteruppbyggnaden av spelare, som visas jÀmnt över hela kartan. Men uppgifterna om nÀsta rum de kommer in efter att ha dykt upp pÄ kartan Àr redan anvÀndbara.

Det kan ses att det gröna rummet passar spelarna – de flesta flyttar frĂ„n det röda rummet till det, varav 50 % Ă€r kvar dĂ€r lĂ€ngre. Det blĂ„ rummet, tvĂ€rtom, Ă€r inte populĂ€rt; nĂ€stan ingen gĂ„r till det, och om de gör det stannar de inte lĂ€nge.

Men uppgifterna sĂ€ger oss nĂ„got viktigare - nĂ€r en spelare Ă€r i ett blĂ„tt rum kommer nĂ€sta rum vi ser honom i att vara rött, inte grönt. Även om det gröna rummet Ă€r mer populĂ€rt Ă€n det röda rummet förĂ€ndras situationen om spelaren Ă€r i det blĂ„ rummet. NĂ€sta tillstĂ„nd (dvs rummet spelaren kommer att gĂ„ till) beror pĂ„ det tidigare tillstĂ„ndet (dvs rummet spelaren befinner sig i). Eftersom vi utforskar beroenden kommer vi att göra mer exakta förutsĂ€gelser Ă€n om vi helt enkelt rĂ€knade observationer oberoende av varandra.

Att förutsÀga ett framtida tillstÄnd baserat pÄ data frÄn ett tidigare tillstÄnd kallas en Markov-modell, och sÄdana exempel (med rum) kallas Markov-kedjor. Eftersom mönstren representerar sannolikheten för förÀndringar mellan pÄ varandra följande tillstÄnd, visas de visuellt som FSM med en sannolikhet runt varje övergÄng. Tidigare anvÀnde vi FSM för att representera beteendetillstÄndet som en agent var i, men detta koncept strÀcker sig till alla tillstÄnd, oavsett om det Àr associerat med agenten eller inte. I det hÀr fallet representerar staterna rummet som agenten upptar:

Hur man skapar en spel-AI: en guide för nybörjare

Detta Àr ett enkelt sÀtt att representera den relativa sannolikheten för tillstÄndsförÀndringar, vilket ger AI:n en viss förmÄga att förutsÀga nÀsta tillstÄnd. Du kan förutse flera steg framÄt.

Om en spelare Àr i green room Àr det 50 % chans att han stannar dÀr nÀsta gÄng han observeras. Men vad Àr chansen att han fortfarande kommer att vara dÀr Àven efter? Det finns inte bara en chans att spelaren stannade kvar i green room efter tvÄ observationer, utan det finns ocksÄ en chans att han lÀmnade och ÄtervÀnde. HÀr Àr den nya tabellen som tar hÀnsyn till de nya uppgifterna:

Hur man skapar en spel-AI: en guide för nybörjare

Den visar att chansen att se spelaren i det gröna rummet efter tvÄ observationer kommer att vara lika med 51 % - 21 % att han kommer frÄn det röda rummet, 5 % av dem att spelaren kommer att besöka det blÄ rummet mellan dem, och 25% som spelaren inte kommer att lÀmna green room.

Tabellen Àr helt enkelt ett visuellt verktyg - proceduren krÀver bara att man multiplicerar sannolikheterna vid varje steg. Det betyder att du kan se lÄngt in i framtiden med en varning: vi antar att chansen att komma in i ett rum helt beror pÄ det aktuella rummet. Detta kallas Markov Property - det framtida tillstÄndet beror bara pÄ nuet. Men detta Àr inte hundra procent korrekt. Spelare kan Àndra beslut beroende pÄ andra faktorer: hÀlsonivÄ eller mÀngd ammunition. Eftersom vi inte registrerar dessa vÀrden blir vÄra prognoser mindre exakta.

N-gram

Hur Àr det med exemplet med ett fightingspel och att förutsÀga spelarens kombinationsrörelser? Det samma! Men istÀllet för ett tillstÄnd eller en hÀndelse kommer vi att undersöka hela sekvensen som utgör en kombinationsstrik.

Ett sÀtt att göra detta Àr att lagra varje ingÄng (som Kick, Punch eller Block) i en buffert och skriva hela bufferten som en hÀndelse. SÄ spelaren trycker upprepade gÄnger pÄ Kick, Kick, Punch för att anvÀnda SuperDeathFist-attacken, AI-systemet lagrar alla ingÄngar i en buffert och kommer ihÄg de tre senaste som anvÀndes i varje steg.

Hur man skapar en spel-AI: en guide för nybörjare
(Raderna i fet stil Àr nÀr spelaren startar SuperDeathFist-attacken.)

AI:n kommer att se alla alternativ nÀr spelaren vÀljer Kick, följt av en annan Kick, och lÀgger sedan mÀrke till att nÀsta ingÄng alltid Àr Punch. Detta gör att agenten kan förutsÀga SuperDeathFists kombinationsrörelse och blockera den om möjligt.

Dessa hÀndelsesekvenser kallas N-gram, dÀr N Àr antalet lagrade element. I det föregÄende exemplet var det ett 3-gram (trigram), vilket betyder: de tvÄ första posterna anvÀnds för att förutsÀga den tredje. Följaktligen, i en 5-grams, förutsÀger de första fyra posterna den femte och sÄ vidare.

Designern mÄste vÀlja storleken pÄ N-gram noggrant. Ett mindre N krÀver mindre minne men lagrar ocksÄ mindre historik. Till exempel kommer en 2-grams (bigram) att spela in Kick, Kick eller Kick, Punch, men kommer inte att kunna lagra Kick, Kick, Punch, sÄ AI:n kommer inte att svara pÄ SuperDeathFist-kombon.

Å andra sidan krĂ€ver större antal mer minne och AI kommer att bli svĂ„rare att trĂ€na eftersom det kommer att finnas mĂ„nga fler möjliga alternativ. Om du hade tre möjliga ingĂ„ngar av Kick, Punch eller Block, och vi anvĂ€nde en 10-grams, skulle det vara cirka 60 tusen olika alternativ.

Bigrammodellen Àr en enkel Markov-kedja - varje tidigare tillstÄnd/nuvarande tillstÄndspar Àr ett bigram, och du kan förutsÀga det andra tillstÄndet baserat pÄ det första. De 3-grams och större N-grammen kan ocksÄ ses som Markov-kedjor, dÀr alla element (utom det sista i N-grammet) tillsammans bildar det första tillstÄndet och det sista elementet det andra. Fightingspelexemplet visar chansen att övergÄ frÄn Kick and Kick-tillstÄndet till Kick and Punch-tillstÄndet. Genom att behandla flera inmatningshistorikposter som en enda enhet omvandlar vi i huvudsak inmatningssekvensen till en del av hela tillstÄndet. Detta ger oss Markov-egenskapen, som gör att vi kan anvÀnda Markov-kedjor för att förutsÀga nÀsta ingÄng och gissa vilket kombinationsdrag som kommer att bli nÀsta.

Slutsats

Vi pratade om de vanligaste verktygen och tillvÀgagÄngssÀtten i utvecklingen av artificiell intelligens. Vi tittade ocksÄ pÄ i vilka situationer de behöver anvÀndas och dÀr de Àr sÀrskilt anvÀndbara.

Detta borde vara tillrÀckligt för att förstÄ grunderna i spel AI. Men det Àr naturligtvis inte alla metoder. Mindre populÀra, men inte mindre effektiva inkluderar:

  • optimeringsalgoritmer inklusive bergsklĂ€ttring, lutning och genetiska algoritmer
  • motstridiga sök-/schemalĂ€ggningsalgoritmer (minimax och alfa-beta beskĂ€rning)
  • klassificeringsmetoder (perceptroner, neurala nĂ€tverk och stödvektormaskiner)
  • system för bearbetningsagenters perception och minne
  • arkitektoniska tillvĂ€gagĂ„ngssĂ€tt för AI (hybridsystem, delmĂ€ngdsarkitekturer och andra sĂ€tt att överlappa AI-system)
  • animationsverktyg (planering och rörelsekoordinering)
  • prestandafaktorer (detaljnivĂ„, nĂ€r som helst och tidsdelningsalgoritmer)

Internetresurser om Àmnet:

1. GameDev.net har avsnitt med artiklar och handledning om AIOch forumet.
2. AiGameDev.com innehÄller mÄnga presentationer och artiklar om ett brett spektrum av Àmnen relaterade till spel AI-utveckling.
3. GDC-valvet innehÄller Àmnen frÄn GDC AI Summit, av vilka mÄnga Àr tillgÀngliga gratis.
4. AnvÀndbart material finns ocksÄ pÄ hemsidan AI Game Programmers Guild.
5. Tommy Thompson, AI-forskare och spelutvecklare, gör videor pÄ YouTube AI och spel med en förklaring och studie av AI i kommersiella spel.

Böcker om Àmnet:

1. Bokserien Game AI Pro Àr en samling korta artiklar som förklarar hur man implementerar specifika funktioner eller hur man löser specifika problem.

Game AI Pro: Collected Wisdom of Game AI Professionals
Game AI Pro 2: Collected Wisdom of Game AI Professionals
Game AI Pro 3: Collected Wisdom of Game AI Professionals

2. AI Game Programming Wisdom-serien Àr föregÄngaren till Game AI Pro-serien. Den innehÄller Àldre metoder, men nÀstan alla Àr aktuella Àven idag.

AI Game Programming Wisdom 1
AI Game Programming Wisdom 2
AI Game Programming Wisdom 3
AI Game Programming Wisdom 4

3. Artificiell intelligens: ett modernt tillvĂ€gagĂ„ngssĂ€tt Ă€r en av grundtexterna för alla som vill förstĂ„ det allmĂ€nna omrĂ„det artificiell intelligens. Det hĂ€r Ă€r inte en bok om spelutveckling – den lĂ€r ut grunderna i AI.

KĂ€lla: will.com

LĂ€gg en kommentar