Skriptikielten käyttö pelitekoälyssä Reima Halmetoja Helsinki 27.4.2008 HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos
HELSINGIN YLIOPISTO HELSINGFORS UNIVERSITET UNIVERSITY OF HELSINKI Tiedekunta/Osasto Fakultet/Sektion Faculty Laitos Institution Department Matemaattis-luonnontieteellinen Tekijä Författare Author Reima Halmetoja Työn nimi Arbetets titel Title Tietojenkäsittelytieteen laitos Skriptikielten käyttö pelitekoälyssä Oppiaine Läroämne Subject Tietojenkäsittelytiede Työn laji Arbetets art Level Aika Datum Month and year Sivumäärä Sidoantal Number of pages Tiivistelmä Referat Abstract 27.4.2008 16 sivua Tietojenkäsittelytieteen laitoksen Ohjelmistotuotanto ja tietokonepelit-seminaarin seminaariartikkeli. Artikkelissa käsitellään pelitekoälyä ja sen toteuttamista skriptikielillä. Avainsanat Nyckelord Keywords pelitekoäly, skriptikielet Säilytyspaikka Förvaringsställe Where deposited Muita tietoja övriga uppgifter Additional information
Sisältö ii 1 Johdanto 1 2 Pelitekoälystä 2 2.1 Pelitekoälyn määrittely.......................... 2 2.2 Kovakoodattu tekoäly.......................... 3 2.3 Tehovaatimukset pelitekoälylle...................... 3 3 Lyhyt johdatus skriptikieliin 4 4 Pelitekoälyä skriptikielillä 6 4.1 Tekoälyn skriptaaminen......................... 7 4.2 Triggerijärjestelmät............................ 8 5 Etuja ja haittoja 10 5.1 Skriptikielet ja tehokkuus........................ 10 5.2 Laajennettavuus ja ei-ohjelmoijien skriptaus.............. 12 5.3 Skriptikielen valinta............................ 13 6 Yhteenveto 13 Lähteet 15
1 Johdanto 1 Ensimmäisessä osiossa Pelitekoälystä määrittelemme, minkä tyyppisestä toiminnasta on kyse pelitekoälyä kehitettäessä (toteutustavasta riippumatta). Käymme myös läpi pinnallisesti kovakoodatun tekoälyn ideaa myöhempää vertailua varten. Tämän lisäksi tarkastelemme, minkä tyyppisiä tehovaatimuksia pelit asettavat tekoälylle. Tässä aineessa ei oleteta lukijalta erityistä tietämystä skriptikielistä (scripting language) tai skriptikielisten ohjelmien kirjoittamisesta. Tärkeimmät yleiset ominaisuudet skriptikielten osalta pyritään käymään läpi ymmärrettävyyden parantamiseksi osiossa Lyhyt johdatus skriptikieliin. Katsaus ei sellaisenaan ole kuitenkaan erityisen kattava, koska aiheesta on yksinäänkin helposti aineksia omaan artikkeliinsa. Kolmannessa osiossa tarkastelemme skriptaamalla toteutettavaa pelitekoälyä. Osiossa keskitytään pelissä olevien älykkäältä toiminnalta vaikuttavien tapahtumien tarkasteluun sekä käsitellään epäpelaajahahmojen tekoälyä ryhmätason sodankäyntiä kuvaavan pelin eräässä osassa. Viimeisessä osiossa pyritään tarkastelemaan skriptikielten etuja ja haittoja peliprojekteissa. Tarkastelussa pyritään ottamaan huomioon aiemmin käsiteltyjä tehovaatimuksia. Lisäksi katsotaan, minkä tyyppisiin projekteihin skriptikielen implementointi voi tarjota etuja. Yleisesti tässä seminaariaineessa pyritään käsittelemään skriptikielien ja tekoälyn perusteita johdattaen lukijaa aihepiiriin. Yksittäisiin skriptikieliin, peleihin tai toteutuksiin ei tarkemmin keskitytä, joskin esimerkkejä kustakin pyritään antamaan. Skriptikielistä kiinnostuneelle eräs tarkastelemisen arvoinen peli voi olla amerikkalaisen Epic Gamesin Unreal-peli ja sen jatko-osat, joissa käytetystä skriptikielestä löytyy dokumentaatiota wiki-muodossa [Unr07]. Alkuperäisen pelin skriptikielellä toteutetut tekoälyvastukset tulivat aikanaan tunnetuiksi skaalautuvuudestaan ja taktisista kyvyistään [Toz02].
2 Pelitekoälystä 2 Osiossa käymme läpi muutamia aineessa käytettäviä peruskäsitteitä, kuten pelitekoälyn määritelmää. Lisäksi tutustumme tapaan, jolla tekoäly on perinteisesti liitetty osaksi pelejä. Osion lopuksi katsastamme, miten rajattu tietokoneiden ja pelikonsolien laskentateho vaikuttaa pelitekoälyyn. 2.1 Pelitekoälyn määrittely Mitä pelitekoäly oikeastaan on? Halutaanko itsenäisesti omia strategioitaan ja pelityylejään muodostava älykäs tietokonevastustaja vai ennalta ohjelmoitu kone, joka suorittaa tiettyjä operaatioita niille ennalta määrätyissä olosuhteissa. Tässä artikkelissa pelitekoäly määritellään tavalla, jota pääasiallisesti käytettäneen alan kirjallisuudessa [Mil06]. Tekoäly voidaan jakaa Russelin ja Norvigin tapaan seuraavanlaiseen nelikenttään: Systeemit, jotka ajattelevat kuin ihmiset Systeemit, jotka toimivat kuin ihmiset Systeemit, jotka ajattelevat rationaalisesti Systeemit, jotka toimivat rationaalisesti Kuva 1: Tekoälyn nelikenttä [RuN03]. Keskitymme näistä systeemeihin, jotka toimivat rationaalisesti. Pelitekoälyä ajateltaessa tärkeintä lienee lopputulos, jossa tekoälyn toiminta vaikuttaa pelaajan kannalta järkevältä. Tästä näkökulmasta tarkasteltuna termi tekoäly voi olla hieman harhaanjohtava. Termeinä agenttien suunnittelu tai käyttäytymisen mallintaminen voivatkin kuvastaa ongelmakenttää paremmin [Toz02]. Sana agentti tulee esiintymään aineessa myöhemminkin. Yksinkertaisesti sillä tarkoitetaan oliota, joka toimii pelin ympäristössä ja on vuorovaikutuksessa sen kanssa. Vaikka pelitekoälyn tavoite on usein aiemmin mainitun oloinen, voivat lopputulokset erota suurestikin. Esimerkiksi pelaajan näkökulmasta kuvatuissa ampumispeleissä (FPS rst-person shooter), saattaa pelitekoäly olla niin vakuuttava, että pelaa-
3 ja voi luulla hahmon liikuttajan olevan verkkoyhteyden kautta pelaava ihminen. Tämäntyyppinen lopputulos ei kuitenkaan useimmiten ole tavoitteena pelitekoälyä suunniteltaessa. On kuitenkin mainittava, että ihmisen toiminnalta vaikuttavaa pelitapaa on yritetty kehittää muun muassa osana tieteellistä tutkimusta [LaD01]. On myös tärkeää käsittää, että pelitekoäly on riippuvainen asiayhteydestään [Toz02]. Esimerkiksi tietyssä FPS-pelissä erinomainen tekoälyvastustaja voi toiseen FPSpeliin siirrettynä olla erittäin huono, johtuen pelien erityyppisistä aseistuksista, taktiikoista, kenttäsuunnittelusta jne., vaikka ohjelmakoodi sellaisenaan toimisi myös jälkimmäisessä pelissä. 2.2 Kovakoodattu tekoäly Perinteinen tapa pelitekoälyn toteuttamiseen on niin sanottu kovakoodattu tekoäly (hard-coded articial intelligence). Yksinkertaisimmillaan tämä voi tarkoittaa esimerkiksi Pac-Man-pelissä tehtyä painotettua satunnaisuutta, jonka perusteella Pac-Manin vastustajat valitsevat kulkusuuntansa saavuttuaan peliareenalla olevaan risteyskohtaan [Mil06]. Kovakoodatuksi tekoälyn tässä tapauksessa tekee se, että se on ohjelmoitu samalla ohjelmointikielellä kuin muut osat pelistä ja on sellaisenaan kiinteä osa pelin ohjelmakoodia. Kovakoodattu tekoäly sopii toteutustapana hyvin tekoälykomponentteihin, joita käytetään usein uudelleen. Esimerkki paljon uudelleenkäytettävästä komponentista on tekoälyhahmojen liikkumisalgoritmit. Suhteellisen yksinkertaisilla liikkumisalgoritmeilla voidaan toteuttaa useita tekoälyhahmojen liikkumistapoja, kuten hahmon seuraaminen, pakeneminen, väistäminen jne. [Mil06], jotka ovat edelleen sovellettavissa moniin tarkoituksiin. Laskentatehon kannalta myös laskennallisesti vaativat algoritmit on hyvä toteuttaa kovakoodattuina palaamme aiheeseen myöhemmin. 2.3 Tehovaatimukset pelitekoälylle Moderneille peleille on ominaista näyttävä 3d-graikka, jonkinasteisesti mallinnettu fysiikka ja muut runsaasti konetehoa vaativat ominaisuudet. Tästä johtuen pelin
4 tekoäly voi usein varata vain pienen osan peliin käytettävästä laskentatehosta. Yksistään pelin graikan pyörittäminen vaatii usein yli 50% prosessorin tehosta [Her03]. Monissa peleissä noin 20% prosessorin kapasiteetista voidaan varata kaikkeen pelin tekoälyn vaatimaan laskentaan [Mil06], joskin tämä voi vaihdella riippuen pelin tapahtumista, pelistä yleisesti ja pelin alustasta (pc, konsoli jne.) Tehovaatimukset asettavat pelitekoälylle merkittävän haasteen. Hyvää pelitekoälyä suunniteltaessa lienee siis hyvä ottaa huomioon käytössä oleva koneteho ja pyrkiä mahdollisimman tehokkaisiin ratkaisuihin kuhunkin ongelmaan. Optimointi- ja toteutustavoista riippumatta pelitekoälyssä esiintyy ongelmia, kuten reitinetsintä, joita ei voida ratkaista ilman merkittävää prosessoriresurssien käyttöä [Toz02]. 3 Lyhyt johdatus skriptikieliin Skriptikieli tai komentosarjakieli on ohjelmointikieli, joka on luotu yksinkertaistamaan monimutkaista tehtävää jollekin tietylle ohjelmalle [Ber02]. Itse peliohjelma voidaan puolestaan kirjoittaa jollain tavanomaisella ohjelmointikielellä, kuten C, C++ tai Java. Skriptikieltä käytetään siis valitulla ohjelmointikielellä kirjoitetun ohjelman yhteydessä jonkin sille soveltuvan tehtävän ratkaisemista varten. Skriptikielen rakenne koostuu tavanomaisesti kahdesta osasta: kielestä ja tulkista (scripting engine, virtual machine tai interpreter) [Ber02]. Kielellä määritellään syntaksi, jota ohjelmoija käyttää ohjatakseen tietokonetta suorittamaan jotakin tiettyjä operaatioita. Skriptikielet voivat muistuttaa hyvinkin paljon muita ohjelmointikieliä syntaksiltaan, jolloin skriptikielellä kirjoitettu koodi voi näyttää paljon esimerkiksi Javalta, C++:lta, tms. Joissakin skriptikielissä kirjoitettua ohjelmakoodia eli skriptiä (script) suoritetaan sellaisenaan tulkin avulla. Useimmissa peleissä käytetyissä skriptikielissä, mukaan lukien esimerkiksi Lua, TLC, Quake-peliä varten suunniteltu Quake-C, tai Unrealpelisarjan UnrealScript, kirjoitettu skripti käännetään tavukoodiksi ennen sen suorittamista [Mil06]. Skriptille joudutaan tällöin tekemään muutamia toimenpiteitä tavukoodiksi kääntämistä varten.
5 Ensimmäinen vaihe skriptin muuntamiseksi tavukoodiksi on skriptin selaus eli leksikaalinen analyysi. Tässä vaiheessa etsitään skriptin tekstistä erilliset elementit, kuten operaatiot, varatut sanat, merkkijonot jne. Esimerkkinä skriptissä voi olla seuraava merkkijono apu = 12; joka voidaan jakaa tekstialkioihin seuraavasti apu (teksti) <väli> (tulostumaton merkki) = (sijoitusmerkki) <väli> (tulostumaton merkki) 12 (kokonaisluku) ; (lauseen lopetusmerkki) Tekstialkiot syötetään edelleen jäsentäjälle. Jäsentäjä tuottaa kääntäjää varten abstraktiksi syntaksipuuksi tai syntaksipuuksi kutsutun tietorakenteen, joka kuvaa lähdekoodin syntaktista rakennetta [ALSU07]. Aiemmin teksitialkioiksi muuntamamme esimerkki voidaan muuntaa seuraavalla tavalla kuvattavaksi syntaksipuuksi: lauseke = apu 12 Kuva 2: Yksinkertainen syntaksipuu.
6 Abstrakti syntaksipuu lähetetään edelleen koodin generoijalle, joka muuntaa sen tavukoodiksi [ALSU07]. Tavukoodia voidaan tämän jälkeen suorittaa skriptikielen tulkilla [Ber02]. Koko prosessi skriptistä tulkattavaksi tavukoodiksi voidaan kuvata alla esitetyllä tavalla: kääntäjä selaus skripti jäsentäminen tavukoodi tavukoodin generointi ajonaikainen tulkki Kuva 3: Muunnos ihmisen kirjoittamasta skriptistä ajettavaan tavukoodiin. Käännösvaiheen jälkeen kielen tulkki suorittaa tavukoodiksi käännettyä ohjelmaa. Tavukoodiksi käännettävät skriptikielet muistuttavat siis hieman Javaa, jossa myös käännetään lähdekielinen ohjelma virtuaalikoneella pyöritettäväksi tavukoodiksi. Pienenä erona Javassa kuitenkin virtuaalikone edelleen kääntää tavukoodin konekieliseksi juuri ennen sen ajamista (ns. just-in-time compiling). Tätä tekniikkaa käytetään kuitenkin harvemmin skriptikielissä [Mil06]. Tällaisenaan tulkattavat skriptikielet eroavat merkittävästi esimerkiksi C-ohjelmointikielestä, jossa ohjelmakoodi käännetään usein suoraan konekieleksi. 4 Pelitekoälyä skriptikielillä Pelien kehittäjillä on monenlaisia vaihtoehtoja pelitekoälyn kehittämiseen skriptikielten avulla. Tarkastelemme esimerkkiä pelistä, jossa on käytetty skriptaamista taktisen tason tekoälytoiminnan toteuttamiseen. Lisäksi tutustumme triggerijärjestelmiin, yksinkertaiseen skriptikielillä toteutettavaksi soveltuvaan tekniikkaan.
4.1 Tekoälyn skriptaaminen 7 Tarkastellaan esimerkkiä vuonna 2006 tuotannossa olleesta, joskin mainitsemattomasta pelistä, joka käyttää hyväkseen tekoälyn skriptausta [Mil06]. Eräässä pelin osassa sotilasryhmän tarkoituksena on vallata huone. Pelin suunnittelussa keskityttiin siihen, että huoneen valtaaminen tapahtuisi amerikkalaisen sotilasohjeistuksen mukaan. Ohjeistuksessa yksi ryhmän sotilaista heittää huoneen oviaukosta käsikranaatin. Ensimmäinen sotilaista menee huoneeseen ja liikkuu seinää myöten huoneen nurkkaan. Toinen sotilas liikkuu huoneen toisella puolella olevaan nurkkaan. Kaksi jäljellä olevaa sotilasta liikkuvat oviaukon sisäpuolelle suojaamaan muuta ryhmää. Tarkastellaan valtaamisessa käytettyjä skriptejä: Liiku sijaintiin oven ulkopuolella Heitä kranaatti ovesta Liiku lähellä olevaan kulmaan huoneessa Suojaa oviaukon sisäpuoli Näitä toimintoja koordinoidaan edelleen ylemmän tason skriptillä. Skriptien onnistunutta suorittamista varten tarvitaan tietoa siitä, mitkä ovat oviaukkoa lähinnä olevat huoneen nurkat. Esimerkkipelissä huoneiden nurkat, oviaukon sijainti sekä odotuspaikat oven ulko- ja sisäpuolella oli selvitetty etukäteen. Koska huoneen valtaamista varten olennaiset sijainnit ovat tiedossa ennen skriptien ajamista, voidaan samaa menetelmää käyttää huoneen valtaamiseen sen muodosta riippumatta. Huone voi tällöin olla esimerkiksi viisi- tai kuusikulmainen, kunhan olennaiset pisteet oviaukon lähistöllä, sekä sitä lähimpänä olevat huoneen nurkat ovat tiedossa. Pisteiden selvittäminen voidaan tehdä etukäteen, kuten tässä esimerkissä, tai se voidaan suorittaa osana koordinointiin käytettävää ylemmän tason skriptiä. Tilanteissa, joissa ryhmän koko on aiempaa esimerkkiä pienempi (alle neljä), käytetään edelleen samoja toimintaan vaikuttavia skriptejä. Ainoa asia, joka muuttuu, on skriptien koordinoimiseen käytettävä ylemmän tason skripti. Esimerkiksi kolmen hahmon valtauksessa vain yksi hahmoista jäisi suojaamaan oviaukkoa (kahden aikaisemman mennessä huoneen nurkkiin).
8 Kuva 4: Huoneen vyöryttäminen neljällä hahmolla ryhmätason sotapelissä [Mil06]. Pelissä saatiin aikaan monimutkaiselta taktiselta kuviolta vaikuttava toiminta muutaman skriptin avulla. Skriptien käyttö tämän tyyppisiä tarkoituksia varten voikin olla hyvä ratkaisu, koska niiden avulla voidaan yksinkertaistaa monimutkaisempaa päätöksentekoprosessia. Esimerkin skriptit olivat myös melko hyvin uudelleenkäytettäviä, ja esimerkiksi vajaan ryhmän toimintaa ohjatessa ei jouduta kirjoittamaan kaikkea ryhmän toimintaa ohjaavia skriptejä uudelleen. Vaikkakin esimerkkipelissä toteutettiin skriptien avulla suhteellisen monimutkaista toimintaa, voidaan vastaavan tyyppisesti kirjoittaa yksinkertaisemmillekin tekoälyhahmojen toiminnoille sopivia skriptejä, kuten pelaajan hahmoa kohti ampumista, lääkepakkausten käyttöä jne. 4.2 Triggerijärjestelmät Triggerijärjestelmiä (trigger system) voidaan pitää yksinkertaisena tapana saada agentit toimimaan vuorovaikutuksessa muun pelimaailman kanssa. Triggerijärjestelmällä on kaksi pääasiallista tarkoitusta pelissä: pitää kirjaa pelimaailmassa olevista
9 tapahtumista, joiden kanssa agentti voi olla vuorovaikutussuhteessa, ja minimoida prosessointitarve, jota käytetään agenttien vuorovaikutukseen näiden tapahtumien kanssa. Triggeri (trigger) voi olla mikä tahansa agenttiin vaikuttava ärsyke pelissä, kuten ampumisen äänen kuuleminen, johonkin paikkaan saapuminen, tietty vahingoittumisen taso, jne. Edelleen kullekin agentille voidaan määritellä, mitkä triggerit vaikuttavat niihin [Ork02]. Katsastetaan esimerkkejä ärsykkeistä. FPS-pelissä pelaajan hahmo saattaa laukaista hälytyksen, joka toimii triggerinä. Esimerkissä kaikki hälytyksen kuulevat tekoälyhahmot pyrkivät triggerin kutsuman skriptin ohjaamana liikkumaan hälytyksen suuntaan. Toisena esimerkkinä tekoälyhahmo saattaa nähdä pelaajan hahmon ampuvan itseään kohti, jolloin tekoälyhahmo liikkuu jonkin suojan taakse. Suojan takaa tekoälyhahmo pyrkii heittämään käsikranaatteja pelaajan hahmoa kohti. Tässä voi olla kyseessä kaksi triggeriä: ensimmäinen on pelaajan hahmon havaitseminen, jonka seurauksena tekoälyhahmolle suoritetaan skripti, joka liikuttaa tekoälyhahmon aiemmin määriteltyyn suojapaikkaan. Toinen kytkimistä voi olla suojan takana oleminen, jonka seurauksena suoretaan skripti, jossa tekoälyhahmo vaihtaa käytössä olevan aseensa epäsuorasti heitettäviin kranaatteihin. Aiemmin mainitun tyyppistä käyttäytymistä voidaan saada aikaan myös ilman triggerijärjestelmää. Tämä voidaan toteuttaa suorittamalla kyselyjä (polling) tapahtumille kutakin agenttia kohden. Kyselyihin perustuva toteutustapa on ongelmallinen, koska kaikkien tapahtumien ja agenttien läpi käymiseen tarvitaan runsaasti prosessoriaikaa. Laskennan vaativuus kyselytoteutukselle on luokkaa O(n 2 )[Ork02]. Yleistetyssä triggerijärjestelmässä triggeri merkitään aktiiviseksi siihen liittyvät tapahtuman sattuessa. Jokaisessa triggerijärjestelmän syklissä käydään läpi kaikkien agenttien lista. Tässä ajetaan testejä, joiden avulla selvitetään, onko kyseinen agentti kiinnostunut mistään tällä hetkellä aktiiviseksi merkitystä triggereistä. Agentit puolestaan suorittavat prosessointia riippuen siitä, kuinka moni triggeri kyseistä agenttia kiinnostaa. Triggerijärjestelmä on mielenkiintoinen tekoälyratkaisu. Suhteellisen yksinkertaisella ärsykkeisiin reagoimisella voidaan aikaansaada illuusio siitä, että esimerkiksi tekoälypelaajat pystyvät monimutkaiseen taktiseen toimintaan (kuten suojaan hakeutumiseen ja siitä kranaattien heittelyyn) tai interaktioon pelimaail-
10 man kanssa (jääkaapille saapuva vartija juo maitoa kaapista). Sellaisenaan se sopii erinomaisesti pelitekoälyn tarkoitukseen: rationaaliselta vaikuttavan toiminnan aikaansaamiseen. Skriptaaminen voi puolestaan olla hyvä tapa toteuttaa triggerijärjestelmä, koska kieli itsessään voidaan määritellä kuvaamaan hyvin pelin tapahtumia. Kenttien suunnittelussa voidaan muokata triggerien skriptejä, ja liittää niitä pelikenttiin vaikuttamatta muun pelin ohjelmakoodiin. Jos pelissä käytettävä skriptikieli on suunniteltu sillä tavalla, että sen käyttämiseen ei tarvita erikoista ohjelmointitaitoa, voivat myös ohjelmointiin osallistumattomat kenttäsuunnittelijat luoda uusia triggereitä mielenkiintoisia pelitapahtumia varten. Mainitaan edelleen, että johdannossa esitelty Unreal-peli ja sen jatko-osat käyttävät hyväkseen triggerijärjestelmää pelien tekoälyn toteutuksessa [Unr07]. 5 Etuja ja haittoja Osiossa pyritään luomaan kriittinen katsaus skriptikielten käyttöön pelitekoälyä toteutettaessa. Tarkastelemme tekoälyn skriptikielellä toteuttamisen hyötyjä ja haittoja muun muassa laajennettavuuden, tehovaatimusten ja pelin myynti-iän kannalta. 5.1 Skriptikielet ja tehokkuus Tulkattavana kielenä skriptikielellä kirjoitetut ohjelman osat ovat huomattavasti hitaampia kuin konekieliset ohjelmat. Unreal-pelissä käytetyn UnrealScript-kielen nopeus on arvioitu noin 20 kertaa hitaammaksi kuin konekielisen ohjelman [Swe98]. Ero on erittäin merkittävä. Toisaalta on otettava huomioon, mihin pelin osiin skriptaamista käytetään. Pelin kriittisimmät osat ovat Unreal-pelissä toteutettu tehokkaammalla ohjelmointikielellä. Eräs tapa minimoida kalliiden skriptien suoritukseen tarvittavaa laskentatehoa on pyrkiä kirjoittamaan skriptejä, joita ei tarvitse suorittaa kaiken aikaa [Swe98].
11 Skriptikielen optimoinnilla voidaan saada aikaan hyviä parannuksia tehokkuudessa. Parhaimmillaan koodin pituutta voidaan lyhentää jopa 50%:lla optimoimalla generoitua tavukoodia [Her03]. Skriptikielinen ohjelman osa tulee silti olemaan huomattavan hidas, vaikka skriptikieli saataisiin parhaimmassa tapauksessa esimerkiksi vain 10 kertaa hitaammaksi kuin muu pelissä käytetty ohjelmakoodi. Useissa peleissä tarvitaan esimerkiksi reitinetsintäalgoritmeja, joiden avulla pyritään löytämään pelissä olevalle oliolle lyhin mahdollinen tie jostain pisteestä toiseen määriteltyyn pisteeseen. Reitinetsintäalgoritmeja on olemassa useita (esim. Dijkstran algoritmi tai A*), mutta niille on yleistä suurehkot laskentatehovaatimukset. Reitinetsintäalgoritmien ja muiden vastaavien laskennallisesti vaativien tekoälyalgoritmien toteuttaminen skriptikielellä lisää edelleen tarvittavaa laskentatehoa. Laskentatehoa tarvitaan enemmän, koska algoritmin skriptikielinen toteutus on auttamatta hitaampi, kuin esimerkiksi C- tai C++-kielinen toteutus. Eräs mielenkiintoinen tulkattaviin skriptikieliin liittyvä ominaisuus liittyy olennaisesti tehovaatimuksiin. Tulkattavilla skriptikielillä voidaan ajaa jotain tiettyä skriptiä, kun resurssit sallivat sen. Tilanteessa, jossa konetehoa vaaditaan muualle, kuten ruudun päivittämiseen, voidaan skriptin tulkkaaminen keskeyttää. Kun konetehoa on jälleen vapaana, voidaan saman skriptin tulkkaamista jatkaa siitä, mihin jäätiin. Tällä voidaan hillitä tulkattavien skriptikielten suurempaa tehon kulutusta, koska skriptien suorittamista voidaan mahdollisuuksien mukaan ajoittaa tilanteisiin, jossa konetehoa on enemmän vapaana. Aiempi tulkkaamisen keskeyttäminen voidaan edelleen yhdistää milloin vain -algoritmeiksi (anytime algorithms) tekoälytekniikkaan, joka voidaan integroida skriptikielen tulkkiin [Mil06]. Ajatus milloin vain -algoritmeissa on siinä, että algoritmin tulosta voidaan kysyä, ennen kuin algoritmi on lopullisesti suoritettu loppuun. Tarkastellaan esimerkkiä, jossa reitinetsinnällä pyritään löytämään hahmolle reitti kahden pisteen välillä. Jos reitinetsintäalgoritmi on toteutettu milloin vain -algoritmina, voidaan hahmon liikuttaminen pelimaailmassa aloittaa ennen kuin algoritmi on selvittänyt lopullisen reitin. Tämä on mahdollista kysymällä algoritmilta välituloksena tuotettua pistettä lähtö- ja maalipisteiden välillä, jota kohti hahmoa liikutetaan.
5.2 Laajennettavuus ja ei-ohjelmoijien skriptaus 12 Hyvin valitulla ja suunnitellulla skriptikielellä ohjelmoijat eivät välttämättä ole ainoita mahdollisia skriptien kirjoittajia. Skriptien kirjoittamiseen voivat osallistua esimerkiksi kenttien suunnittelijat tai pelin loppukäyttäjät. Mielenkiintoisesti useimmiten skriptien kirjoittajat eivät olekaan ohjelmoijia, vaan pelin suunnittelijoita [Poi02]. Tämä liittynee pelintekomalliin, jossa perinteisellä ohjelmointikielellä toteutettu pelikone erotetaan skriptikielillä toteutetusta pelin sisällöstä. Pelin sisällön erottaminen pelikoneesta on erityisesti suurissa peliprojekteissa esiintyvä tarve [Mil06]. Pelin suunnittelijat keskittyvät kehittämään sisältöä peliin helpommin omaksuttavalla skriptikielellä jättäen pelikoneen kehityksen siitä vastaaville ohjelmoijille. Skriptaamisen mahdollistaminen pelin loppukäyttäjille, eli pelaajille voi olla taloudellisesti kannattava ratkaisu. Tämä siitä syystä että se skriptaamisen mahdollistaminen voi synnyttää pelin ympärille ns. modauskulttuurin, jossa pelaajat muokkaavat osia pelistä muiden pelaajien käytettäviksi. Käytännössä tämä voi tarkoittaa pelin kehittäjän kannalta ilmaista lisäsisältöä pelille, joka voi edelleen vaikuttaa positiivisesti pelin myynti-ikään. Hyvän skriptikielen kehittäminen erityisesti ei-ohjelmoijia silmällä pitäen voi olla vaikeaa. Skriptikielen tulee tarjota mahdollisimman paljon ohjelmointimahdollisuuksia, mutta toisaalta kielen oppimisen tulee olla nopeaa. Eräs tapa helpottaa skriptikielen käyttämistä on tarjota skriptien kirjoittajille kirjasto hyvin dokumentoituja toimintoja, joita käytetään usein pelissä [Poi02]. Esimerkiksi peliä varten kehitetyn skriptikielen kirjastossa voi olla valmiiksi kirjoitettuna pelihahmojen liikkumiseen käytettäviä skriptejä. Tässä tapauksessa skriptin kirjoittaja joutuu pikemmin koordinoimaan liikkumiseen käytettävien skriptien kutsumista, kuin ohjelmoimaan itse liikkumiseen tarvittavia algoritmeja. Laajennettavuuden kääntöpuoli voi ilmetä väliohjelmistoja tekeville tekoälykehittäjille. Toisaalta peliin saatetaan haluta ostaa valmis tekoälyratkaisu. Väliohjelmistojen kehittäjillä on harvemmin mahdollisuutta vaikuttaa peleissä käytettäviin skriptikieliin, joten kehittäjän tekoälysysteemi on yleisimmin varminta ohjelmoida samaan
13 tapaan kuin esimerkiksi fysiikkamoottorit, so. jollain tehokkaalla ohjelmointikielellä. Tällöin tekoäly voidaan rinnastaa fysiikkamoottorin tyyppiseksi osaksi pelikonetta. Pelien kehittäjät voivat kuitenkin haluta tekoälysysteemiin laajennettavuutta ja käyttäjien muuntelumahdollisuuksia, jotka skriptikielet voivat tarjota. Lopputuloksena voi olla, että skriptausmahdollisuus joudutaan keinotekoisesti lisäämään muuten kauniisti suunniteltuun tekoälysysteemiin tai se on voitu toteuttaa toisella skriptikielellä kuin muu pelin mahdollinen skriptaus. 5.3 Skriptikielen valinta Peliin käytettäväksi skriptikieleksi on olemassa useita vaihtoehtoja. Tehdäänkö oma, juuri peliin soveltuva kieli vai valitaanko jokin valmis kieli, kuten Lua, Tcl, Python jne. Monet pelit käyttävät nimenomaan juuri niitä varten suunniteltua skriptikieltä, kuten aiemmin mainittu Unreal-pelin UnrealScript (jonka muunneltua versiota myös pelisarjan myöhemmät pelit käyttävät). Kutakin pelia varten räätälöity skriptikieli noudattaa näkökulmaa, jonka mukaan skriptikielen pääasiallinen tarkoitus on yksinkertaistaa jonkin ongelman ratkaisua. Oman kielen kirjoittaminen voi kuitenkin olla melko vaativa tehtävä, erityisesti jos kieltä ei suunnitella riittävän huolellisesti, ottaen huomioon myös sille tulevaisuudessa esiintyvät vaatimukset. Tämän tyyppisiä vaatimuksia voi kokemattoman kehittäjän olla vaikea ennakoida, ja niiden lisäksi on skriptikieli suunniteltava mahdollisesti myös ohjelmointia taitamattomien pelaajien ja pelisuunnttelijoiden käytettäväksi. Joidenkin pelinkehittäjien mukaan ainakaan omaa jäsentäjää skriptikielelle ei kannata kirjoittaa, vaan on järkevämpää käyttää apuna kääntäjätyökaluja, kuten lex ja yac [BrD02]. 6 Yhteenveto Pelitekoälyssä pyritään luomaan pelaajalle illuusio siitä, että pelin hahmot toimivat rationaalisesti. Kyse ei ole siitä, että pyritään huijaamaan pelaaja luulemaan pelaavansa ihmisiä vastaan.
14 Useimmat peleissä käytettävät skriptikielet ovat tulkattavia kieliä. Tämäntyyppisissä kielissä kirjoitettu skripti tulee selata ymmärrettäviksi tekstialkioiksi. Tekstialkiot jäsennetään edelleen loogiseen muotoon syntaksipuuksi. Syntaksipuu muunnetaan tavukoodiksi, jota skriptikielen tulkki suorittaa. Skriptikieliä käytetään jollain muulla kielellä ohjelmoidun pelin yhteydessä suorittamalla tulkilla tilanteeseen sopiva, usein tavukoodina oleva skripti. Skriptikieliä voidaan käyttää monipuolisesti erilaisten tekoälyratkaisujen toteutustapana. Aineessa tarkastelimme monimutkaiselta vaikuttavan ryhmätason sotilaspelissä esiintyvän huoneiden valtaamista neljän yksinkertaisen skriptin ajamisen yhdistelmänä. Lisäksi kävimme käsitteiden tasolla läpi triggerijärjestelmää, jonka avulla pelissä toimivat tekoälyhahmot voivat olla yhteydessä pelimaailman tapahtumiin ilman jatkuvaa kyselyiden tarvetta. Pelinäkökulmasta skriptikielen mukaan ottaminen tai pois jättäminen ei ole itsestään selvä ratkaisu. Toisaalta skriptikielet tarjoavat tiettyjä etuja, kuitenkin mahdollisesti monimutkaistaen peliä kokonaisuuden tasolla ja lisäämällä pelin tehovaatimuksia. Oman käsitykseni mukaan on tärkeää nähdä, että skriptikielten käyttö tai käyttämättä jättäminen pelitekoälyssä ovat valintoja, jotka liittyvät pelin arkkitehtuuriin, eivät sen käyttämiin algoritmeihin. Tällöin siis pelitekoälyssä tarvittavat algoritmit ovat samoja riippumatta siitä, toteutetaanko ne kovakoodattuina tai liitetäänkö ne peliin skriptikielen avulla. Skriptikielen mukaan ottaminen, valinta ja muut vastaavat ratkaisut lienee parasta tehdä tapauskohtaisesti kutakin peliä suunniteltaessa. Tekoälyn toteutustapana skriptikielet soveltuvat esimerkiksi peleihin, joissa tekoäly halutaan erottaa pelikoneesta osaksi pelin sisältöä, jota pelisuunnittelijat ja harrastelijat voivat muokata. Toisaalta vaativaa laskentaa suorittavat tekoälyalgoritmit, kuten reitinetsintäalgoritmit voi olla järkevämpää toteuttaa skriptaamistakin hyväksi käyttävissä projekteissa kovakoodattuna huomattavasti paremman tehokkuuden varmistamiseksi. Näitä tehokkaammin toteutettuja algoritmeja voidaan edelleen käyttää kirjastojen avulla skriptikielellä toteutettavissa tekoälykomponenteissa.
Lähteet ALSU07 Ber02 BrD02 15 Aho, A., Lam, M., Sethi, R., Ullman, J. Compilers: principles, techniques & tools, second edition. Addison-Wesley 2007. Berger, L. Scripting: overview and code generation. AI game programming wisdom, sivut 505-515, Cengage Delmar Learning 2002. Brockington, M., Darrah, M. How not to implement a basic scripting language. AI game programming wisdom, sivut 549-554, Cengage Delmar Learning 2002. Her03 Herz, A. Optimized script execution. AI game programming wisdom 2, sivut 517-523, Cengage Delmar Learning 2003. LaD01 Mil06 MLAKS04 Ork02 Poi02 RuN03 Laird, J., Duchi, J. Creating human-like synthetic characters with multiple skill levels: A case study using the soar quakebot. AAAI Spring Symposium on Articial Intelligence and Computer Games, sivut 54-58, 2001. Millington, I. Articial intelligence for games. Elsevier Science & Technology Books 2006. Magerko, B., Laird, J., Assanie, M., Kerfoot, A., Stokes, D. AI characters and directors for interactive computer games. Proceedings of the 2004 Innovative Applications of Articial Intelligence Conference, AAAI Press 2004. Orkin, J. A general-purpose trigger system. AI game programming wisdom, sivut 48-54, Cengage Delmar Learning 2002. Poiker, F. Creating scripting languages for nonprogrammers. AI game programming wisdom, sivut 520-529, Cengage Delmar Learning 2002. Russell, S., Norvig, P., Articial intelligence: a modern approach. Prentice Hall 2003.
16 Sco02 Scott, B. The illusion of intelligence. AI game programming wisdom, sivut 16-20, Cengage Delmar Learning 2002. Swe98 Sweeney, T. UnrealScript language reference. http://unreal.epicgames.com/unrealscript.htm Toz02 Tozour, P. The evolution of game AI. AI game programming wisdom, sivut 3-15, Cengage Delmar Learning 2002. Unr07 Unreal wiki: the Unreal engine documentation site. http://wiki.beyondunreal.com/wiki/