Pelin tekoäly. Aleksi Vuorela IIO14S1. Tietorakenteet ja algoritmit harjoitustyö Joulukuu 2015

Samankaltaiset tiedostot
KODU. Lumijoen peruskoulu

Racket ohjelmointia II. Tiina Partanen 2015

Luento 2: Viivan toteutus

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

Matematiikan tukikurssi

Matematiikan tukikurssi

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

13 Lyhimmät painotetut polut

JOHDATUS TEKOÄLYYN TEEMU ROOS

JOHDATUS TEKOÄLYYN TEEMU ROOS

JOHDATUS TEKOÄLYYN TEEMU ROOS

JOHDATUS TEKOÄLYYN TEEMU ROOS

Algoritmit 1. Luento 9 Ti Timo Männikkö

Turingin koneen laajennuksia

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 9. lokakuuta 2016

Venekilpailu! Esteiden väistely ja hahmon ohjaaminen

Sudenkuoppia, yllätyksiä, pään vaivaa

Algoritmit 1. Luento 8 Ke Timo Männikkö

T Harjoitustyöluento

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Sukelluskeräily, Pelihahmon liikuttaminen. Tee uusi hahmo: Pelihahmo. Nimeä se. Testaa ikuisesti -silmukassa peräkkäisinä testeinä (jos) onko jokin

Aluksi Kahden muuttujan lineaarinen yhtälö

L9: Rayleigh testi. Laskuharjoitus

Harjoitussuunnitelma viikko 15 Sisäsyrjäpotku I

Harjoitussuunnitelma viikko 17 Kärkipotku I

Sukelluskeräily. Pelihahmon liikuttaminen. Aarre ja pisteet

Tehtävänanto oli ratkaista seuraavat määrätyt integraalit: b) 0 e x + 1

Matopeli C#:lla. Aram Abdulla Hassan. Ammattiopisto Tavastia. Opinnäytetyö

58131 Tietorakenteet (kevät 2009) Harjoitus 11, ratkaisuja (Topi Musto)

OHJ-2710 Peliohjelmointi. Syksy 2012 Timo Kellomäki

Alkuun HTML5 peliohjelmoinnissa

Sokkelon sisältö säilötään linkitetyille listalle ja tekstitiedostoon. Työ tehdään itsenäisesti yhden hengen ryhmissä. Ideoita voi vaihtaa koodia ei.

Harjoitussuunnitelma viikko 18 Kärkipotku II

Oikeasta tosi-epätosi -väittämästä saa pisteen, ja hyvästä perustelusta toisen.

Äärellisten automaattien ja säännöllisten lausekkeiden minimointi

Mitä on konvoluutio? Tutustu kuvankäsittelyyn

Labyrintti. Pelihahmon toiminta. Piirrä pelihahmo (älä piirrä esim. sivusta, ettei hahmon tarvitse

A TIETORAKENTEET JA ALGORITMIT

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Jypelin käyttöohjeet» Miten voin liittää törmäyksiin tapahtumia?

S09 04 Kohteiden tunnistaminen 3D datasta

Matematiikan tukikurssi

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. tammikuuta 2012

13/20: Kierrätys kannattaa koodaamisessakin

Matematiikan tukikurssi

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. FT Ari Viinikainen

Matriisit ovat matlabin perustietotyyppejä. Yksinkertaisimmillaan voimme esitellä ja tallentaa 1x1 vektorin seuraavasti: >> a = 9.81 a = 9.

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

Tasohyppelypeli. Piirrä grafiikat. Toteuta pelihahmon putoaminen ja alustalle jääminen:

15. Ohjelmoinnin tekniikkaa 15.1

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 5. marraskuuta 2015

Pelimatematiikka ja ohjelmointi ATMOS, Mikkeli

Tiina Partanen. Koodaamassa Matikantunnilla

15. Ohjelmoinnin tekniikkaa 15.1

1. Otetaan perusjoukoksi X := {0, 1, 2, 3, 4, 5, 6, 7}. Piirrä seuraaville kolmelle joukolle Venn-diagrammi ja asettele alkiot siihen.

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

Älysopimusten kehittäminen. Sopimus suuntautunut ohjelmointi

Taso 1. Yhden pelaajan pallokontrollitemput SORMILYÖNTI HIHALYÖNTI

Kommunikaatio Visa Linkiö. MS-E2142 Optimointiopin seminaari: Peliteoria ja tekoäly

Harjoitussuunnitelma viikko 14 Potkaiseminen II

Luku 7. Verkkoalgoritmit. 7.1 Määritelmiä

Matematiikan tukikurssi, kurssikerta 3

Johdatus tekoälyn taustalla olevaan matematiikkaan

MS-A0204 Differentiaali- ja integraalilaskenta 2 (ELEC2) Luento 7: Pienimmän neliösumman menetelmä ja Newtonin menetelmä.

MAB3 - Harjoitustehtävien ratkaisut:

Board Game Lab. 7 Pelimekaniikat ja -systeemit. Materiaalit CC-BY 4.0 Mikko Lampi

A* Reitinhaku Aloittelijoille

= 2 L L. f (x)dx. coshx dx = 1 L. sinhx nπ. sin. sin L + 2 L. a n. L 2 + n 2 cos. tehdään approksimoinnissa virhe, jota voidaan arvioida integraalin

Matematiikan tukikurssi, kurssikerta 4

MAB3 - Harjoitustehtävien ratkaisut:

T Harjoitustyöluento

Insinöörimatematiikka D

Algoritmit 1. Luento 1 Ti Timo Männikkö

Implementation of Selected Metaheuristics to the Travelling Salesman Problem (valmiin työn esittely)

Peilaus pisteen ja suoran suhteen Pythonin Turtle moduulilla

Matematiikan tukikurssi

Pong-peli, vaihe Koordinaatistosta. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 2/7. Tämän vaiheen aikana

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit - syksy

Esimerkkejä polynomisista ja ei-polynomisista ongelmista

Yhtälön oikealla puolella on säteen neliö, joten r. = 5 eli r = ± 5. Koska säde on positiivinen, niin r = 5.

Kertausta: avaruuden R n vektoreiden pistetulo

Algoritmit 2. Luento 6 To Timo Männikkö

UML -mallinnus TILAKAAVIO

Python-ohjelmointi Harjoitus 2

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Ohjelmistojen mallintaminen olioiden elinkaaret - tilakaavio Harri Laine 1

Kontrollilaitteet. Arsenaali

Käy vastaamassa kyselyyn kurssin pedanet-sivulla (TÄRKEÄ ensi vuotta ajatellen) Kurssin suorittaminen ja arviointi: vähintään 50 tehtävää tehtynä

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Ohjelmoinnin perusteet Y Python

Avainsanat: peli, matematiikka, polynomi, yhteen- ja vähennyslasku, kertolasku

Luento 6: Tulostusprimitiivien toteutus

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

Harjoitustyön testaus. Juha Taina

6.4. Järjestyssuhteet

Kahoot - kyselytyökalu

Yleistä vektoreista GeoGebralla

Transkriptio:

Pelin tekoäly Aleksi Vuorela IIO14S1 Tietorakenteet ja algoritmit harjoitustyö Joulukuu 2015 Ohjelmistotekniikan koulutusohjelma Tekniikan ja liikenteen ala

1 1 Johdanto Harjoitustyön aiheena oli tutustua pelin tekoälyn toteuttamiseen vaadittaviin tietorakenteisiin ja algoritmeihin. Tein olio-ohjelmointi 2 kurrsin harjoitustyönä oman pelin C++ ohjelmointikielellä ja toteutin tekoälyn tähän peliin. Pelini on ylhäältäpäin kuvattu toimintapeli tai käytännössä ammuntapeli jonka kenttä rakentuu tiilistä. Tarkemmin tekemäni peli on käsitelty olio-ohjelmointi 2 kurssin harjoitustyöni dokumentaatiossa: http://student.labranet.jamk.fi/~h8346/cpp/harkkatyo/olio2harjoitustyo.html Tekoäly oli siis tarkoitus tehdä pelin vihollisille eli zombeille, jotka yrittävät tietysti tappaa pelaajan. Lähdin miettimään pelini kannalta kaikista tärkeimpiä ominaisuuksia mitä tekoälyltä halusin ja kolme keskeistä asiaa nousi pinnalle. Kaikista tärkein asia oli, että vihollisilla olisi erilaisia tiloja, joiden välillä siirrytään vihollisen havaintojen perusteella. Vihollinen käyttäytyisi tietysti eri tavalla riippuen siitä, missä tilassa se on. Tähän ratkaisuksi löytyi finite state machine eli äärellinen tilakone niminen tekniikka. Toinen keskeinen asia pelini kannalta oli se, että viholliset eivät näkisi pelaajaa pelikentän seinien läpi. Tähän avuksi löytyi Bresenhamin algoritmi. Viimeinen asia oli jo kurssilta tutuksi tullut lyhimmän reitin etsiminen eli etsitään lyhin reitti vihollisen sijainnista pelaajan luokse. Tähän käytin A*-algoritmia. Näillä tekniikoilla sain aikaiseksi pelini vihollisille simppelin tekoälyn ja seuraavissa luvuissa käsittelen kunkin kyseisistä tekniikoista sekä selitän, kuinka ohjelmoin ne C++ ohjelmointikielellä.

2 2 Finite state machine Finite state machine on yksi eniten käytetyistä tekoälytekniikoista peleissä. Tilakone koostuu äärellisestä määrästä tiloja, joiden välillä on tilasiirtymiä. Pelien tekoälyssä käytetään termiä agentti oliosta, joka tekee havaintoja pelimaailmasta ja suorittaa itsenäisesti niistä riippuvia toimintoja. Kun jatkossa käytän termiä agentti, se tarkoittaa siis pelin vihollista eli zombia. Pelissäni tilasiirtymät aiheutuvat agentin havainnoista. Agentin käyttäytyminen määräytyy tilakoneen tilan mukaan. Tilakoneessani on kolme eri tilaa: normal, alert ja evasion. Normal-tila on oletustila, josta kaikki agentit aloittavat. Tässä tilassa agentti vain seisoskelee paikallaan odotellen jostain havainnosta aiheutuvaa tilasiirtymää. Alert-tilaan siirrytään, kun agentti havaitsee pelaajan. Havaitsemiseen on kaksi ehtoa: pelaajan on ensinnäkin oltava näköetäisyydellä, ja toiseksi näköyhteyttä ei voi estää mikään, esimerkiksi seinä. Tämä näköyhteyden testaaminen tehdään Bresenhamin algoritmilla, josta lisää myöhemmässä luvussa. Mikäli pelaaja on tarpeeksi lähellä ja mikään ei estä näkemistä, siirrytään alert-tilaan. Tässä tilassa agentti yrittää jatkuvasti päästä pelaajan lähelle hyökkäys etäisyydelle. Mikäli agentti on tarpeeksi lähellä pelaajaa, se hyökkää ja pelaaja menettää terveyspisteitä. Evasion-tilaan siirrytään silloin, jos alert-tilan aikana agentti menettää näköyhteyden pelaajaan, esimerkiksi kun pelaaja piiloutuu seinän taakse tai pääsee liian kauas pakoon. Tässä tilassa aluksi kirjataan ylös pelaajan viimeisin tunnettu sijainti ja mennään sinne. Viimeisimmän sijainnin ympäriltä etsitään pelaajaa jonkin aikaa, ja mikäli pelaajaa ei löydetä, siirrytään normal-tilaan. Jos pelaaja löydetään, palataan takaisin alert-tilaan. Seuraavalla sivulla on kuvassa 1 esitetty tilakaavio, joka havainnollistaa tiloja ja siirtymiä niiden välillä.

3 Kuva 1. Tilakaavio. Tilakoneen toteuttamiseen on monia vaihtoehtoja, mutta tämän homman kannalta parhaaksi vaihtoehdoksi katsoin stack-based finite state machinen eli pinorakenteeseen pohjautuvan äärellisen tilakoneen. Pino tietorakenne on jo kurssilta tuttu käsite, ja tässä sitä pystyi hyödyntämään nerokkaasti käytännössä. Pinon päällimmäisenä on siis sen hetkinen aktiivinen tila, jonka perusteella tehdään jotain toimintoja. Kun tilasiirtymä tapahtuu, esimerkiksi normal- ja alert-tilan välillä, lyödään uusi tila (alert) pinon päällimmäiseksi, jolloin siitä tulee sen hetkinen aktiivinen tila. Jos halutaan siirtyä aikaisempaan tilaan, esimerkiksi ollaan evasiontilassa ja löydetään pelaaja, voidaan pinon päällimäinen tila (evasion) heittää pois, jolloin edellinen tila (alert) tulee taas aktiiviseksi. Pino rakenteen avulla tilojen hallinta saadaan siis hyvin simppeliksi ja vain yksi tila voi olla aktiivinen kerrallaan, mikä on koko finite state machinen idea!

4 Toteutus C++:lla Sitten koko homman varsinaiseen toteutukseen C++:lla. En nyt lähde kaikkea koodia avaamaan tässä tarkasti, sillä tämä ei ole ohjelmoinnin kurssi, vain keskeiset asiat finite state machinen toiminnan kannalta. Kuva 2. Keskeiset funktiot ja muuttujat. Kuvassa 2 esitellään Enemy header-tiedostossa olevien keskeisten funktioiden ja muuttujien nimet sekä kommentit siitä, mitä ne tekevät. Kuvan ylimmässä kohdassa näkyvät siis tilakoneen eri tilat tallennettuna enum luokkaan nimeltä State. Updatefunktiota kutsutaan jokaisella framella, joka siis päivittää agenttia kokoajan. Tämä on varmasti finite state machinen toiminnan kannalta kaikkein tärkein funktio, joten katsotaan sen toteutusta tarkemmin seuraavalla sivulla. Seuraavaksi tulevat eri tiloille ominaiset funktiot eli idle, attack ja search. Idlefunktiota kutsutaan kun aktiivinen tila on normal, attackia kun tila on alert ja searchia kun tila on evasion. Funktio getcurrentstate kertoo sen hetkisen aktiivisen tilan. Viimeisenä on pino nimeltä statestack, jonne siis tilat tallennetaan ja pinon päällimmäinen elementti on sen hetkinen aktiivinen tila. Kuten huomataan, C++:ssa on pino tietorakenne jo valmiiksi toteutettu standardikirjastossa, joten sitä ei onneksi tarvitse itse koodata.

5 Kuva 3. Update-funktio. Sitten update-funktiosta tarkemmin. Se tsekkaa aina aluksi etäisyyden pelaajan ja agentin välillä sekä piirtää viivan Bresenhamin algoritmilla, jonka avulla testataan ettei mikään ole estämässä näköyhteyttä pelaajaan, tämän toteutuksesta seuraavassa luvussa. Seuraavaksi tulee switch-rakenne, jossa aluksi katsotaan mikä tila on tällä hetkellä aktiivinen getcurrentstate-funktiolla. Aktiivisen tilan perusteella kutsutaan joko idle-, attack- tai search-funktiota. Esimerkiksi jos aktiivinen tila on normal, kutsutaan idle-funktiota joka näyttää seuraavalta. Kuva 4. Idle-funktio.

6 Idle-funktiossa aluksi katsotaan, onko pelaaja näköetäisyydellä ja nähdäänkö häntä (eli mikään ei estä näköyhteyttä, checklos niminen funktio). Mikäli nämä ehdot toteutuvat, pelaaja on nähty, jolloin pinoon statestack pusketaan päällimmäiseksi elementiksi alert-tila. Nyt kun seuraavalla framella update-funktio pyörähtää alusta taas, agentin tilaksi muuttuu alert ja kutsutaan attack-funktiota. Jos taas ehdot eivät toteudu, eli pelaaja on liian kaukana tai seinän takana, agentti ei tee mitään muuta kuin seisoskelee paikallaan sillä tekoäly on (vielä) hyvin simppeli ja tyhmä. Kuten aiemmin totesin, finite state machinet ovat yksi eniten käytetyistä tekoälytekniikoista peleissä, ja niiden avulla saadaan aikaiseksi hyvinkin monimutkaisia kokonaisuuksia. Alla olevassa kuvassa 5 on esitelty vanhan klassikko pelin Quaken (1996) Shambler hirviön tilakone, joka on toteutettu täysin samalla tavalla, mutta siinä on lisäksi käytetty alemman tason tilakoneita, eli Attack State ja Melee Attack jakautuvat alitiloihin. Kuva 5. Quaken Shambler hirviön tilakone.

7 3 Bresenhamin algoritmi Toinen keskeinen asia pelini kannalta oli se, että agentit eivät näkisi pelaajaa pelikentän seinien läpi. Tähän avuksi löytyi Bresenhamin algoritmi. Homman ideana on siis piirtää jana pelaajan ja agentin välille Bresenhamin algoritmin avulla ja katsoa, ettei mikään janan pisteistä osu esteeseen, kuten seinään. Janaa ei kannata piirtää tavallisen suoran yhtälön y = kx + b mukaan, koska laskemisessa tarvitaan silloin runsaasti prosessoriaikaa vieviä kertolaskuja. DDA-algoritmi käyttää kertolaskujen tilalla yhteenlaskuja. DDA-algotimin heikkous on kuitenkin siinä, että sitä käytettäessä joudutaan tekemään jatkuvasti pyöristyksiä. Parempi vaihtoehto janan piirtämiseksi on Bresenhamin algoritmi, joka käyttää pelkästään kokonaislukuaritmetiikkaa. Algoritmi on vanha, vuodelta 1962 peräisin, mutta sitä käytetetään yhä paljon grafiikkaohjelmoinnissa vaikka monia uusia, moderneja algoritmejä on kehitetty, sillä se on nopea ja yksinkertainen. Sitä voidaankin pitää grafiikkaohjelmoinnin alkeisoperaationa. Algoritmin perusideana on iteroida janan x- ja y-komponenteista pidempää ja korottaa sopivin välein piirtokorkeutta. Sopiva väli ei ole kokonaisluku, joten murtolukua simuloidaan virhemuuttujan avulla. Enempää on varmaan turha selittää, sillä se menee enemmän matematiikan puolelle, mutta yksinkertaistettuna lasketaan kokonaislukujen jakolaskua dy/dx. Algoritmi löytyy valmiiksi toteutettuna netistä joka ikiselle ohjelmointikielelle, ja pienellä soveltamisella sain sen omaan peliinikin toimimaan. Kooditasolla janan piirtämistä on varmaan turha alkaa tarkemmin käymään läpi, mutta oleellinen pointti on tekemäni checklos (check line of sight) funktio.

8 Kuva 6. Check line of sight funktio. Bresenhamin algoritmilla siis lasketaan omassa funktiossaan janan kaikkien pisteiden koordinaatit, ja ne tallennetaan vektoriin nimeltä points. For-loopissa käydään sitten jokainen janan pisteistä läpi, ja katsotaan levelin toucheswall-funktiolla, osuuko mikään janan pisteistä pelikentän seiniin. Tämän tuloksena siis tiedetään, onko näköyhteyden tiellä seinää estämässä. Bresenhamin algoritmi toimii hyvin line of sightin toteuttamiseen simppeleissä, ylhäältäpäin kuvatuissa peleissä, mutta esimerkiksi 3D-peleissä tarvitaan hyvinkin monimutkaisia menetelmiä line of sightin toteuttamiseen. 4 A*-algoritmi A*-algoritmi on kaikkein suosituin lyhimmän reitin hakualgoritmi pelien tekoälyssä. Se yhdistää kurssilta tutuksi tulleen Dijkstran algoritmin sekä greedy best-first searchin parhaimmat puolet, joka johtaa parhaimpaan tulokseen kun etsitään lyhintä reittiä yhteen kohteeseen. Dijkstran algoritmi toimii hyvin lyhimmän reitin löytämiseen, mutta kuluttaa turhaan resursseja etsiessään reitin kaikkiin mahdollisiin solmuihin, myös sellaisiin, jotka eivät vaikuta lupaavilta lyhimmän reitin kannalta päämäärään. Greedy best-first search taas toimii siten, että tehdään funktio, joka laskee jatkuvasti kuinka kaukana päämäärästä ollaan, ja priorisoidaan niitä reittejä, jotka ovat lähempänä päämäärää. Tämä on kaikista nopein tapa, jos kentässä ei ole mitään esteitä, kuten seiniä. Ongelma tässä tulee tietysti siinä, jos reitillä vastaan tulee jokin este ja joudutaan lähteä etsimään kiertotietä.

9 A*-algoritmi käyttää hyödykseen näitä molempia: Dijkstran tapaa laskea lyhin reitti lähtösolmusta ja greedy best-first searchin tapaa priorisoida reittejä, jotka ovat lähimpänä päämäärää. Kuva 7. Dijkstra vs greedy best-first vs A*.

10 Kuten kuvasta 7 nähdään hyvin, A* etsii lyhintä reittiä aluksi vain siltä alueelta, joka on lähimpänä päämäärää ja laskee lyhimmän reitin lähtösolmusta päämäärään. Haku aluetta kasvatetaan kauemmaksi päämäärästä, jos reittiä ei löydetä lähialueelta esteen takia, mutta kaikissa mahdollisissa solmuissa ei käydä turhaan, kuten Dijkstran algoritmissa, joten lyhin reitti löydetään paljon nopeammin. Valitettavasti en kerennyt vielä toteuttaa peliini A*-algoritmia C++:lla, sillä sen koodaamisessa on melkoinen työ. Se on kyllä hyvin jo vauhdissa, mutta kooditasolla on tullut törmättyä ongelmallisiin tilanteisiin. 5 Yhteenveto Aluksi harjoitustyön piti käsitellä pelkästään finite state machineja, mutta asia oli hyvin mielenkiintoista ja tuli innostuttua vähän liikaa, tunteja vierähti melkoisesti. Paljon enemmän aikaahan tässä meni asioiden toteuttamiseen kooditasolla omaan peliini kuin algoritmien toimintaan perehtymiseen. Aion varmasti saada peliini A*- algoritmin toimintakuntoon vapaa-ajallani ja tulen parantelemaan tekoälyä uusilla ominaisuuksilla. Minulla on jo paljon ideoita, esimerkiksi: kun vihollinen huomaa pelaajan, se hälyttää myös muut lähialueella olevat viholliset, vihollinen kuulisi askelten äänistä jos pelaaja lähestyy takaapäin tai jos se kuulisi ammuskelua lähettyvillä, ennalta-arvattavuuden parantamista, uusia tiloja, kokonaan uudenlaisia, uniikkeja tekoälyjä eri tyyppisille vihollisille kuten pomo taisteluille. Tulen päivittelemään peliäni GitHubiin aina kun saan siihen jotain uutta esittely kuntoon. Lopuksi laitan vielä linkin videoon, josta näkee tekoälyn toiminnassa pelissäni (videon toimivuus testattu vain Chromella): http://student.labranet.jamk.fi/~h8346/cpp/harkkatyo/liitteet/video.mp4

11 Lähteet 1. Tekoäly tietokonepeleissä. Tampereen teknillisen yliopiston luentokalvot. Viitattu 4.12.2015. Http://www.cs.tut.fi/~peliohj/tekoaly.pdf. 2. Bevilacqua, F. 2013. Finite-State Machines: Theory and Implementation. Artikkeli sivustolla Tuts+. Viitattu 4.12.2015. Http://gamedevelopment.tutsplus.com/tutorials/finite-state-machinestheory-and-implementation--gamedev-11867. 3. Nystrom, R. 2014. Game Programming Patterns. Genever Benning. 4. Bresenhamin algoritmi. Artikkeli Wikipediassa. Viitattu 4.12.2015. Https://fi.wikipedia.org/wiki/Bresenhamin_algoritmi. 5. Savioja, L. 2007. Viivan toteutus. TKK:n luentokalvot. Viitattu 4.12.2015. Http://www.tml.tkk.fi/Opinnot/T- 111.4300/2007/lectures/tg2c_viivantoteutus.pdf. 6. Introduction to A*. Artikkeli sivustolla Red Blob Games. Http://www.redblobgames.com/pathfinding/a-star/introduction.html. Liitteet Https://github.com/vuoale/GHOST.git Lähdekoodit ovat luettavissa varmaan helpommin GitHub repostani kuin että alkaisin koodeja tähän raporttiin laittamaan. Keskeiset koodit tekoälyn kannalta löytyvät GHOST kansion alta tiedostoista Enemy.cpp ja Enemy.h.