120
SVEUČILIŠTE U ZAGREBU FAKULTET ORGANIZACIJE I INFORMATIKE V A R A Ž D I N Marko Alerić Agentni pristup u računalnim igrama DIPLOMSKI RAD Varaždin, 2016.

Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

SVEUČILIŠTE U ZAGREBU

FAKULTET ORGANIZACIJE I INFORMATIKE

V A R A Ž D I N

Marko Alerić

Agentni pristup u računalnim igrama

DIPLOMSKI RAD

Varaždin, 2016.

Page 2: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

SVEUČILIŠTE U ZAGREBU

FAKULTET ORGANIZACIJE I INFORMATIKE

V A R A Ž D I N

Marko Alerić,

Redoviti student

Broj indeksa: 43578/14-R

Studij: Informacijsko i programsko inženjerstvo

Diplomski studij

Agentni pristup u računalnim igrama

DIPLOMSKI RAD

Mentor: Doc. dr. sc. Markus Schatten

Varaždin, rujan 2016.

Page 3: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

I

Sadržaj

1. Uvod ..................................................................................................................... 1

2. Agenti u računalnim igrama ................................................................................. 2

2.1. Agenti u igrama ................................................................................................ 2

2.2. Umjetna inteligencija ........................................................................................ 3

2.3. Primjeri igara sa umjetnom inteligencijom kroz povijest ................................. 3

2.3.1. Početak umjetne inteligencije u igrama ...................................................... 4

2.3.2. Creatures ..................................................................................................... 4

2.3.3. The Sims ..................................................................................................... 4

2.3.4. Black & White ............................................................................................ 5

2.3.5. Halo ............................................................................................................ 6

2.3.6. F.E.A.R. ...................................................................................................... 7

3. Umjetna inteligencija u igrama ............................................................................ 8

3.1. Model umjetne inteligencije u igrama .............................................................. 9

3.2. Kretanje ............................................................................................................ 9

3.3. Automati ......................................................................................................... 11

3.4. Hijerarhijski automati ..................................................................................... 13

3.5. Stabla odlučivanja ........................................................................................... 16

3.5.1. Odluke ...................................................................................................... 17

3.6. Stabla ponašanja ............................................................................................. 19

3.6.1. Uvjeti ........................................................................................................ 19

3.6.2. Akcije ....................................................................................................... 19

3.6.3. Kompoziti ................................................................................................. 20

3.6.4. Dekoratori ................................................................................................. 21

3.6.5. Primjer stabla ponašanja ........................................................................... 21

3.7. Navigacija ....................................................................................................... 24

3.7.1. Algoritmi traženja putanje ........................................................................ 26

3.8. Tehnike učenja ................................................................................................ 28

3.8.1. Osnove učenja .......................................................................................... 28

3.8.2. Učenje pomoću stabla odlučivanja ........................................................... 29

3.8.3. Ostale tehnike učenja ................................................................................ 29

4. Plan implementacije ........................................................................................... 31

4.1. Unity ............................................................................................................... 31

4.2. Opis igre ......................................................................................................... 33

4.2.1. Neprijatelji pomoću automata .................................................................. 34

4.2.2. Neprijatelji sa formacijama ...................................................................... 36

Page 4: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

II

4.2.3. Neprijatelji pomoću stabla ponašanja ....................................................... 37

5. Implementacija ................................................................................................... 40

5.1. Kreiranje projekta ........................................................................................... 40

5.2. Kretnje agenata ............................................................................................... 40

5.2.1. Agent Behaviour ....................................................................................... 40

5.2.2. Agent ........................................................................................................ 42

5.2.3. Kretanje igrača .......................................................................................... 44

5.2.4. Naganjanje i izbjegavanje ......................................................................... 45

5.2.5. Dostizanje na poziciju i napuštanje pozicije ............................................ 47

5.2.6. Suočavanje ................................................................................................ 49

5.2.7. Lutanje ...................................................................................................... 51

5.2.8. Suočavanje prema naprijed ....................................................................... 53

5.2.9. Izbjegavanje zidova .................................................................................. 53

5.2.10. Izbjegavanje agenata .............................................................................. 54

5.3. Donošenje odluka pomoću automata .............................................................. 56

5.3.1. Osnovna arhitektura .................................................................................. 56

5.3.2. Definiranje osnovnih uvjeta ..................................................................... 57

5.3.3. Implementacija stanja ............................................................................... 59

5.4. Donošenje odluka pomoću stabla ponašanja .................................................. 67

5.4.1. Implementacija osnovnih klasa ................................................................ 67

5.4.2. Implementacija kompozita ....................................................................... 69

5.4.3. Implementacija dekoratora ....................................................................... 71

5.4.4. Implementacija uvjeta .............................................................................. 74

5.4.5. Implementacija akcija ............................................................................... 77

5.5. Formacije agenata ........................................................................................... 83

5.5.1. Upravljanje formacijom ............................................................................ 83

5.5.2. Vrste formacija ......................................................................................... 86

5.6. Slaganje neprijatelja unutar Unity alata .......................................................... 91

5.6.1. Kreiranje osnovnih sučelja ....................................................................... 92

5.6.2. Kreiranje osnovne klase neprijatelja ........................................................ 93

5.6.3. Izgled osnovne strukture neprijatelja ........................................................ 95

5.6.4. Kreiranje neprijatelja „Healerbot“ ........................................................... 95

5.6.5. Kreiranje neprijatelja „Fighterbot“ .......................................................... 98

5.6.6. Kreiranje neprijatelja „Formation Fighterbot“ ........................................ 99

5.6.7. Kreiranje neprijatelja „Flybot Healer“ .................................................. 101

5.6.8. Kreiranje neprijatelja „Flybot Attacker“ ................................................ 103

5.7. Dodatne komponente .................................................................................... 105

Page 5: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

III

6. Testiranje .......................................................................................................... 107

7. Zaključak .......................................................................................................... 113

8. Literatura .......................................................................................................... 114

9. Prilozi ............................................................................................................... 115

Page 6: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

1

1. Uvod

U ovom radu upoznat ćemo se sa agentima u računalnim igrama, te o suvremenim

načinima implementacije. Tržište video igara je jedno od najvećih tržišta koje se u posljednjih

10-ak godina znatno proširilo. Prema riječima Gallaghera (Entertainment Software Assotiation,

2013), niti jedan sektor nije iskusio toliki rast poput računalne industrije i industrije video igara.

Isti dokument (Entertainment Software Assotiation, 2013) iz 2013 godine prikazuje podatak

koji navodi da 58% američke populacije igra video igre, te da prosječno američko kućanstvo

sadrži najmanje jednu platformu na kojoj je moguće pokrenuti igre. Za usporedbu iz istraživanja

za 2016 godine, u dokumentu (Entertainment Software Assotiation, 2016, p. 3) navode kako

63% američke populacije redovno igra video igre, čime je lako uočljiv porast od 5% u samo 3

godine, koji ujedno i opravdava porast i vrijednost samog tržišta video igara.

Razvoj video igara (engl. video game development) je proces razvoja i proizvodnje igre

kojeg izvodi programer (engl. game developer). U procesu razvoja igre obično sudjeluje veći

broj osoba, dok je u novije vrijeme čest slučaj razvoja u kojima sudjeluje samo jedna ili manji

broj osoba. Razvojni programi i alati u kojima se izrađuju mobilne igre često se ne razlikuju od

onih u kojima se izrađuju igre namijenjene ostalim platformama.

Prilikom implementacije igre u procesu razvoja igre, programeri se susreću sa raznim

dijelovima koji zasebno odvojeno nemaju funkcionalnu svrhu, već su dio veće cjeline koji

međusobno funkcioniraju i čine igru. Ti dijelovi uključuju razne multimedijske sadržaje poput

zvučnih efekata, glazbe, slike, 3d modele, te zatim sustav fizike, niz raznih sustava od kojih je

umjetna inteligencija (engl. AI) jedan od njih.

Područje umjetne inteligencije je područje gdje se najlakše i najbolje uočavaju agenti u

računalnim igrama. Upravo u tom području se postižu efekti neovisnih agenata koji u igri

predstavljaju neprijatelje ili suradnike koji su često „pametni“ i služe određenoj svrsi. U

nastavku rada ćemo vidjeti koliko su zapravo ti agenti u igrama pametni i zašto većina umjetne

inteligencije u igrama je samo prividna.

Page 7: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

2

2. Agenti u računalnim igrama

Kao što je u uvodnom dijelu navedeno, upotreba agenata u računalnim igrama se

najčešće prepoznaje kod upotrebe umjetne inteligencije u igrama. Umjetna inteligencija u

igrama podliježe svim pravilima koji su uvjet kako bi određeni entitet u igri mogli zvati

agentom. Odnosno, korištenjem umjetne inteligencije u igrama kreiraju se likovi koji su

neovisni, samostalni (samostalno donose odluke), te reagiraju na određene podražaje.

U procesu razvoja igre, razvoj umjetne inteligencije i agenata spada u kategoriju

programiranja. Na slici 2.1 možemo vidjeti okvirni slijed procesa izrade igre koji započinje

analizom a završava testiranjem.

Slika 2-1: Proces nastajanja scenarija igre (Emalgam, 2010)

2.1. Agenti u igrama

Agenti su računalni sustavi koji su u stanju samostalno djelovati u skladu s ciljevima

korisnika ili vlasnika, pri čemu samostalno određuju načine ostvarenja cilja.

Za razliku od umjetne inteligencije u kojoj se žele oponašati situacije iz stvarnog svijeta,

agenti su tu da izvršavaju samo jednostavne operacije za koje su namijenjeni. Kod agenata nije

potrebno riješiti sve probleme umjetne inteligencije već samo potreban dio.

Page 8: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

3

Autor (Millington & Funge, 2009, p. 11) navodi kako se agenti u igrama temelje na

kreiranju autonomnih likova koji imaju mogućnost primanja informacija iz podataka igre,

odlučivanja koju akciju donijeti temeljem te informacije, te na samom kraju i izvršiti odabranu

akciju. Taj pristup je obično poznat pod nazivom odozdo prema gore (engl. bottom-up).

Suprotnost tome su igre koje ne koriste pristup agenata, odnosno koriste pristup odozgo

prema dolje (engl. top- down), gdje jedan sustav sa vrha upravlja svim entitetima u igri. Primjer

takve igre je igra Grand Theft Auto 3, u kojem je promet i simulacija pješaka kreiran na takav

način (Millington & Funge, 2009, p. 11).

Ta dva pristupa se zapravo u većini igara kombiniraju. Pristup odozdo prema gore se ne

mora koristiti u mnogim igrama, ali u većini igara sa umjetnom inteligencijom se često koristi.

Pristup odozgo prema dolje se koristi u gotovo svakoj igri, bilo da se radi o osnovnom

upravljanju tijeka igre, ili o stvaranju neprijatelja, taj pristup se često koristi. U praktičnom

primjeru ovog rada, pristup odozgo prema dolje se koristi za stvaranje određenog broja

neprijatelja unutar vremenskog raspona. Nakon što je lik kreiran, on je potpuno neovisan o

komponenti koja ga je stvorila.

2.2. Umjetna inteligencija

Kao što navodi autor Steve Rabin (DeLoura, 2001), većina programera se drži

jednostavne tehnike umjetne inteligencije koja radi dobro. Naime, akademska zajednica koja

proučava „pravu“ umjetnu inteligenciju ima različit cilj od programera koji programiraju

umjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na

koji je problem riješen, dok cilj programera je izgled finalnog proizvoda.

Idealni primjer umjetne inteligencije je taj koji koristi agente, odnosno pristup odozdo

prema gore, koji mogu percipirati okolinu i samostalno donijeti odluke. U idućem poglavlju

opisane su tehnike na osnovu kojih se to najčešće postiže.

2.3. Primjeri igara sa umjetnom inteligencijom kroz povijest

Igre sa umjetnom inteligencijom počele su već od 70-tih godina prošlog stoljeća. U

nastavku su navedene neke od poznatijih igara koje su imale veći utjecaj razvijanju današnjih

algoritama umjetne inteligencije. Mnogi od tih algoritama korištenih kroz prošlost su dovoljno

dobri da se i dan danas aktivno koriste.

Page 9: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

4

2.3.1. Početak umjetne inteligencije u igrama

Jedna od prvih igara koja je označavala početak razvoja umjetne inteligencije je igra

Pong. To je jedna od prvih igara koja je bila objavljena 1972. godine. U toj igri računalo i igrač

kontroliraju reket sprječavajući da im loptica dođe do ruba ekrana. Upravo takav način

jednostavnog upravljanja raketom gore-dolje na temelju pozicije loptice značilo je početak

razvoja umjetne inteligencije u igrama (Rabin, 2002, p. 3).

Pac-man igra iz 1976. godine koristi nešto složeniji oblik umjetne inteligencije. Za

umjetnu inteligenciju koriste se automati. Svaki od duhova u igri zapravo je individualan i

ponaša se različito od drugih. Autor igre navodi kako je to napravljeno da bi se izbjegla

monotonost igre (Madhav, 2014, p. 194).

2.3.2. Creatures

Creatures je igra iz 1996. godine u kojoj korisnik „leže“ određene životinje i uči ih kako

da se ponašaju. Te životinje mogu pričati, hraniti se i štititi. To je prva popularna aplikacija koja

koristi strojno učenje u interaktivnoj simulaciji. Koristi neuronske mreže kako bi životinje

mogle učiti (J. Champandard, 2007).

2.3.3. The Sims

The Sims igra je nastala 2000. godine. Radi se o igri koja prikazuje svakodnevne životne

aktivnosti obitelji unutar kuće i predgrađu. Igrač ima mogućnost kreiranja i izgradnje vlastite

kuće, uređivanje, postavljanje namještaja i opreme, te upravljanje likovima. Umjetna

inteligencija u ovoj igri funkcionira tako da se koristi pametna okolina. Okolina ukazuje što sve

nudi, dok lik prema svojim potrebama odlučuje i dolazi do traženih objekata. Tako npr. okolina

ukazuje gdje se nalazi hladnjak s hranom do kojeg lik dolazi kada postane gladan (Rabin, 2002,

p. 22).

Page 10: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

5

Slika 2-2: The Sims igra (J. Champandard, 2007)

2.3.4. Black & White

Black & White igra je nastala 2001. godine te je jedan od najznačajnijih primjera

korištenja umjetne inteligencije u igrama. Radi se o igri u kojoj igrač vlada na otoku koji je

nastanjen sa raznim plemenima. Uključuje elemente simulacije umjetne inteligencije i

strategije. Tijekom igranja, fokusirana je interakcija sa velikim čudovištima koja mogu učiti iz

primjera, na osnovu svojih akcija dobivaju povratnu informaciju u obliku nagrade ili kazne.

Koriste arhitekturu inteligencije poznatu kao BDI model, model uvjerenja, želja i intencija.

Koriste i strojno učenje pomoću stabla odlučivanja i neuronskih mreža koje daju uspješan

rezultat.

Page 11: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

6

Slika 2-3: Black & White igra (J. Champandard, 2007)

2.3.5. Halo

Halo igra je nastala 2001. godine, dok njen nastavak Halo 2 je nastao 2004. godine. Radi

se o pucačini iz prvog lica gdje se igrač bori protiv raznih vanzemaljaca. Neprijatelji mogu

koristiti zaklone jako pametno i pokrivati jedni druge. Kada timski vođa neprijatelja izgubi

život, ostatak tima se povlači. Posebno se ističe korištenje stabla ponašanja, pogotovo u drugom

nastavku, nakon čega su mnogi odlučili slijediti njihov primjer (J. Champandard, 2007).

Slika 2-4: Halo igra (J. Champandard, 2007)

Page 12: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

7

2.3.6. F.E.A.R.

F.E.A.R. (First Encounter Assault Recon) je pucačina iz prvog lica u kojoj igrač

preživljava protiv nadnaravnih pojava i vojske kloniranih vojnika.

U igri se koristi planiranje kako bi generirali razna ponašanja. Korištena tehnologija i

danas služi kao referenca u mnogim studijima. Neprijatelji su u mogućnosti koristiti okolinu na

pametan način, pronalaze zaklone iza stolova, ruše police sa knjigama, otvaraju vrata, ulijeću

kroz prozor i sl. Vojnici su grupirani u posade te koriste grupne taktike, pokrivaju jedni druge

i sl. (J. Champandard, 2007).

Slika 2-5: F.E.A.R igra (J. Champandard, 2007)

Page 13: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

8

3. Umjetna inteligencija u igrama

(Madhav, 2014) navodi, u tradicionalnoj računalnoj znanosti, mnoga istraživanja o

umjetnoj inteligenciji teže prema kompleksnoj formi umjetne inteligencije, uključujući

genetičke algoritme i neuronske mreže. Takvi kompleksni algoritmi imaju ograničenu upotrebu

u video igrama. Razlog tome je što kompleksni algoritmi iskorištavaju puno računalnih resursa

i zahtijevaju puno vremena.

U igrama, u svakoj sekundi, točnije u svakom frameu (jedna od više slika u sekundi) se

izvrši velik broj funkcija, poput ispisivanja grafike, razne kalkulacije i sl. Većina igara može

dozvoliti samo jedan manji dio vremena unutar jednog framea za umjetnu inteligenciju. Na taj

način korištenje kompleksnih algoritama se ne može uzeti u obzir. Drugi razlog je taj što su su

kompleksni algoritmi često nepotrebni jer problemi u igrama su jako dobro definirani i

određeni, te se željeno ponašanje može ostvariti pomoću znatno jednostavnijih metoda.

Kroz prošlost koristili su se razni oblici umjetne inteligencije. Najjednostavniji oblik

umjetne inteligencije je „hard-kodirani“ oblik. Idući korak koji je slijedio u umjetnoj

inteligenciji je nasumičnost. Bilo da se radi od „hard-kodiranom“ obliku inteligencije ili nekom

naprednijem, nasumičnost je ključna kod rješavanja problema determinističnosti.

Idući, i najčešći način koji se koristio kroz povijest je taj u kojem se AI ponašanja

definiraju kao kombinacije pravila automata (engl. state machines) sa nasumičnim varijacijama.

Ali različite igre zahtijevaju različite metode, tako igre poput šaha zahtijevaju stablo

odlučivanja za donošenje idućeg poteza. S tim da igre tog tipa imaju luksuz donošenja odluka

od par sekundi (a ne jedan dio framea), što se u igri predočava kao razmišljanje neprijatelja

(Hocine and Gouaich, 2011), i omogućava kreatorima da iskoriste nešto zahtjevniji algoritam.

Prema (Blanchet, 2012) najčešće AI metodologije koje se koriste za ostvarivanje

umjetne inteligencije su:

Stabla odlučivanja

Stabla ponašanja

Konačni automati

Hijerarhija naredbi

Pathfinding (A*)

Analiza terena

Page 14: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

9

Flocking

Načini ostvarivanja umjetne inteligencije i metodologije svakog dana unaprjeđuju.

3.1. Model umjetne inteligencije u igrama

Kao što navodi (Ian Millington, 2009) umjetnu inteligenciju u igrama možemo

strukturirati na određene cjeline: kretnje (engl. movement), odlučivanje (engl. decision making)

i strategija. Prve dvije skupine se odnosne na osnovna svojstva samostalnog lika (engl.

character), dok strategija obuhvaća cjelinu veću od samog agenta i uzima i druge u obzir.

Slika 3-1: AI model za igre (Ian Milington, 2009)

Bitno je napomenuti da svaka igra nema potrebu za svim razinama umjetne inteligencije,

već neke igre zahtijevaju samo jednu razinu. Igre poput šaha zahtijevaju samo razinu strategije,

dok većina igara uopće ne zahtijevaju tu razinu.

3.2. Kretanje

Prema Slika 3-1, model AI u igrama, prva i početna kategorija koja se navodi je

kategorija kretnji likova, odnosno agenata u igri. Kretnje agenta u igri se mogu ostvariti na više

načina. Jedan od novih popularnijih načina implementacije te razine u igrama je pomoću

ponašanja upravljanjem (engl. Steering Behaviour) kojeg je osmislio Craig Reynolds. Craig

Reynolds je ujedno kreator tzv. flocking algoritma koji simulira ponašanje skupine određenih

Page 15: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

10

životinja poput jata ptica, skupine riba, krdo stoke i sl. (Reynolds, 2011). Prednost korištenja

ovog algoritma je ta što ostvaruje neovisnost agenta i načina njegovog kretanja. Isti agent

funkcionira ispravno ukoliko mu postavimo ponašanje traženja, ponašanje lutanja ili neko

drugo ponašanje. Agent zadržava sva svoja svojstva poput brzine kretanja, brzine okretanja,

akceleracije, interaktivnost sa drugim elementima, jedina promjena je rezultat u kojem se agent

različito kreće.

Ponašanje upravljanjem je dinamički algoritam kretanja. Prvo ubrzava u pravom smjeru,

zatim kad dospije do tražene pozicije ubrzava na suprotnu stranu i tako kruži oko tražene

pozicije dok mu se ubrzanje ne smanji toliko da se pozicionira i ostane na traženoj poziciji (Ian

Millington, 2009).

Neki od poznatijih ponašanja upravljanjem su:

Naganjanje (engl. pursue)

Izbjegavanje (engl. evade)

Traženje (engl. seek)

Bježanje (engl. flee)

Dostizanje na poziciju (engl. arrive)

Napuštanje pozicije (engl. leave)

Lutanje (engl. wander)

Suočavanje (engl. face)

Izbjegavanje prepreka (engl. obstacle avoidance)

Izbjegavanje zidova (engl. wall avoidance)

Praćenje putanje (engl. path following)

Slika 3-2: Algoritam lutanja (wander) (Reynolds, 2011)

Neke od navedenih ponašanja prikazat ćemo i u samoj implementaciji u nastavku rada.

Page 16: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

11

Pošto ponašanje agenata ovisi o jednoj varijabli, tzv. “steering” kojeg svako ponašanje

vraća i prosljeđuje agentu, koji zahvaljujući toj varijabli, izvršava određeni pokret. Takva vrsta

implementacije ujedno ograničava agenta na korištenje samo jednog ponašanja. Tu problem

nastaje ako postoji više ponašanja, na primjer želimo izbjegavati zidove i tražiti neprijatelja u

isto vrijeme. Kojem od tih ponašanja dati prednost, i kojeg prihvatiti, jer oba ponašanja će

agentu dati određenu vrijednost na osnovu koje će izvršiti pokret. Kako bi jednom agentu

dodijelili više ponašanja, potrebno je iskoristit neki od prigodnih algoritama za spajanje

ponašanja upravljanjem (engl. combining steering behaviour). U tu svrhu se najčešće koriste

algoritmi:

stapanjem po težini (engl. weight blending)

prioriteti

cijev ponašanja upravljanjem (engl. steering pipeline)

Ti algoritmi omogućuju postavljanje određene važnosti, tj. određuju prioritet za

ponašanja, te na osnovu toga agenti mogu koristiti više ponašanja istovremeno.

Naime, kada koristimo više ponašanja zajedno sa nekim od prethodno navedenim

algoritmima, postoji mogućnost da se naš agent neće ponašati onako kako očekujemo. Ukoliko

koristimo prioritete zajedno sa ponašanjem lutanja koji ima veći prioritet od ponašanja

izbjegavanja zidova, logično je zaključiti da će naš agent često pokušati prolaziti kroz zid. Stvar

se još više može zakomplicirati ukoliko koristimo još više ponašanja. Iz tog razloga je potrebno

dobro odabrati koji od tih algoritama koristimo i na koji način.

3.3. Automati

Konačni automati (engl. Final State Machines) su savršen model za reprezentaciju

umjetne inteligencije za ponašanje temeljeno na stanjima (engl. state-based behaviour).

Konačni automati se sastoje od stanja, prijelaza i uvjeta. Uvijek postoji jedno početno stanje iz

kojeg je moguće doći u neko drugo stanje ukoliko su uvjeti ispunjeni (Reynolds, 2011, p. 193).

Mnogi autori navode automate kao jedan od bitnijih modela za reprezentaciju umjetne

inteligencije, tako (McShaffry & Graham, 2013, p. 619) navode primjer prikazan na Slika 3-3

koji ilustrira automat za čuvara u igri. Čuvar u igri patrolira i ukoliko uoči da je igrač blizu onda

ga napada. Ukoliko igrač pobjegne u trenutku dok ga čuvar napada, čuvar će nastaviti

patrolirati. Ukoliko pak igrač napadne čuvara, čuvar se povlači i bježi.

Page 17: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

12

Slika 3-3: Autiomat za čuvara (McShaffry & Graham, 2013, p. 618)

Slika 3-4 prikazuje osnovni primjer konačnih automata koji je kao što navodi (Madhav,

2014) kreiran za špijunsku igru. Agent, odnosno neprijatelj patrolira po mapi sve dok ne

pronađe igrača ili dok ne umre. Ukoliko ga igrač ubije, prelazi u stanje smrti.

Slika 3-4: Osnovni automat za stealth igru (Madhav, 2014, p. 193)

Ovaj osnovni primjer ima mnogo nedostataka. Što ako u stanju napadanja, igrač pobjegne od

neprijatelja, nije se moguće vratiti u prethodno stanje. Nešto kompleksniji i bolji automat je

moguće vidjeti na slici ispod.

Page 18: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

13

Slika 3-5: Kompleksniji automat za stealth igru (Madhav, 2014, p. 194)

Na Slika 3-5 je vidljivo kako je stanje smrti (Death) prikazano nešto drugačije. Razlog tome je

što iz bilo kojeg stanja je moguće doći u stanje smrti. Način na koji je to moguće ostvariti u

objektno orijentiranom programskom jeziku je zapravo jednostavan, definiramo osnovno stanje

koja ima predefiniran prijelaz u stanje smrti, ostala stanja jednostavno nasljeđuju i proširuju

vlastitom implementacijom definirano stanje.

3.4. Hijerarhijski automati

Autor (Millington & Funge, 2009) navodi kako konačni automati mogu biti poboljšani

na više načina. Jedan od njih su hijerarhijski automati.

Jedan od poznatijih problema zbog kojeg se koristi ovaj mehanizam je poznat pod

nazivom alarmno ponašanje (engl. alarm behaviour). Naime, ukoliko u igri imamo agenta

robota sa svojim stanjima, koji patrolira po mapi i čisti otpad. Zamislimo situaciju u kojoj

robotu nestane baterije, trebao bi hitno ići na punjenje, i tek onda nastaviti gdje je stao, ili

ukoliko nastane požar pokraj mjesta gdje se puni, preživljavanje bi trebalo imati prioritet nad

punjenjem u tom trenutku.

Navedeni primjer bi se mogao napraviti unutar standardnih automata, s tim da bi

implementacija bila znatno kompliciranija i kreirano stanje se ne bi moglo iskoristit za druge

Page 19: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

14

robote koji imaju slično ali drugačije ponašanje. Prethodni primjer možemo vidjeti na slici

ispod.

Slika 3-6: Alarmno ponašanje pomoću klasičnih automata (Millington & Funge, 2009, p. 319)

Implementacije stanja robota pomoću hijerarhijskih konačnih automata je znatno bolje

rješenje. Na Slika 3-7 moguće je vidjeti prikaz automata. Osnovni automat ostaje

nepromijenjen, ali je dio stanja pod nazivom „Clean up“ koji je povezan sa stanjem „Get power“

unutar kojeg robot puni baterije.

Page 20: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

15

Slika 3-7: Hijerarhijski automati (Millington & Funge, 2009, p. 319)

Stanja u hijerarhijskim automatima funkcioniraju tako da stanja imaju prioritete.

Podržani su prijelazi između nivoa hijerarhije u kojima stanje sa većim prioritetom može

prekinuti izvođenje trenutnog automata, izvršiti potrebno, i vratiti se u prethodno stanje gdje je

stalo.

Page 21: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

16

3.5. Stabla odlučivanja

Stabla odlučivanja (engl. Decision Tree) su jedan od jednostavnijih mehanizama za rad

sa problemima odlučivanja. Značajke stabla odlučivanja su brzina i jednostavnost

implementacije. Zahvaljujući tome, jedna su od korištenijih tehnika danas. Njihova upotreba se

intenzivno koristi za mehanizme vezane uz kontrolu likova, poput animacija (Millington &

Funge, 2009, p. 295).

Stablo odlučivanja je sastavljeno od niza povezanih odluka. Početna odluka se nalazi u

korijenu. Za svaku odluku, počevši od korijena, jedna od nadolazećih opcija je odabrana.

Slika 3-8: Algoritam lutanja (engl. wander) (Millington & Funge, 2009)

Svaka odluka unutar stabla odlučivanja je bazirana na osnovu znanja agenta. Pošto se

stabla odlučivanja koriste kao brzi i jednostavni mehanizam odlučivanja, agenti se često

referenciraju direktno na globalno stanje igre, umjesto posjedovanja reprezentacije vlastitog

znanja.

Svaki list u stablu odlučivanja je akcija koja je izvedena odmah u trenutku kada

algoritam dođe do te akcije.

Page 22: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

17

3.5.1. Odluke

Odluke u stablu su jednostavne. Obično provjeravaju jednu vrijednost i ne posjeduju

provjeravanje poput I ili ILI uvjeta. Razlog zbog kojeg je stablo odlučivanja efikasno je zbog

toga što su odluke jako jednostavne i izvršavaju samo jedno testiranje unutar jedne odluke.

Kada je potrebno spajanja više odluka, potrebno je strukturirati odluke u samom stablu.

Na Slika 3-9 možemo vidjeti uvjet I, odnosno ako su A i B uvjeti istiniti onda izvrši

akciju 1, inače izvrši akciju 2.

Slika 3-9: Stablo odlučivanja sa I uvjetom ) (Millington & Funge, 2009)

Na Slika 3-10 možemo vidjeti uvjet koji predstavlja ILI uvjet, odnosno ako je A ILI B

uvjet istinit onda izvrši akciju 1, inače izvrši akciju 2.

Slika 3-10: Stablo odlučivanja sa ILI uvjetom ) (Millington & Funge, 2009)

Odluke u stablu odlučivanja ne moraju nužno posjedovati binarni uvjet. Uvjeti se mogu

implementirati tako da vraćaju više vrijednosti. Primjer takvog stabla je moguće vidjeti na Slika

3-11.

Page 23: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

18

Slika 3-11: Plitko stablo odlučivanja sa 4 grane

Takav način implementacije donosi i neke kompleksnosti zbog čega se više preferiraju

binarne odluke, koje se mogu i dodatno optimizirati. Na Slika 3-12 vidimo jednako binarno

stablo, samo uz različit tip odluke.

Slika 3-12: Duboko binarno stablo odlučivanja

Page 24: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

19

3.6. Stabla ponašanja

Stabla ponašanja (engl. Behaviour Tree) su postala popularan mehanizam za izradu

umjetne inteligencije likova. Halo 2, napravljena 2004. godine je prva veća igra koja za koju je

detaljno opisano korištenje stabla ponašanja. Zahvaljujući tome, mnoge igre su to slijedile.

Stablo ponašanja na neki način objedinjuje prethodno često korištene tehnike poput

hijerarhijskih automata, planiranja, izvršavanja akcija. Prednost ove tehnike je što objedinjuje

navedene tehnike na način koji je lagano razumjeti i iskoristiti za osobe koje ne programiraju.

Za razliku od automata, glavni dio stabla ponašanja je zadatak (engl. task). Zadatak

može biti jako jednostavan, poput izvršavanja animacije ili provjeravanje varijable. Zadaci se

sastavljaju unutar pod-stabla i predstavljaju kompleksniju akciju. Njihova struktura im daje

slobodu da ne zadaci međusobno nisu ovisi o tome na koji način su implementirani.

Zadaci se mogu podijeliti na više tipova zadataka. Postoje:

Akcije

Uvjeti

Kompoziti

Dekoratori

3.6.1. Uvjeti

Uvjeti testiraju određeno svojstvo u igri. Uvjet može testirati udaljenost traženog

objekta, testirati vidljivost traženog objekta, testirati vlastito stanje, i slično. Svaki od tih

zadataka implementiran je u vlastitoj klasi, kako bi bio iskoristiv. Svaki uvjet vraća uspješan

status ukoliko je uvjet ispunjen, u suprotnom vraća neuspjeh.

3.6.2. Akcije

Akcije mijenjaju stanje igre. Akcije mogu biti akcije za animaciju, za pomicanje agenta,

odnosno lika, za promjenu ponašanja, primjerice liku se može automatski puniti health ukoliko

odmara, zatim akcije za puštanje zvučnog zapisa, za interakciju sa dijalogom, te mnogi drugi.

Poput uvjeta, svaki od zadataka ima vlastitu implementaciju, i igre često imaju velik

broj akcija. Za razliku od uvjeta, većinu vremena, akcije će vratiti uspješan rezultat. U

suprotnom, treba razmisliti o korištenju uvjeta prije akcije.

Page 25: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

20

Akcije i uvjeti su jako slični stanjima i prijelazima kod automata i temelje se na sličnoj

tehnici. Ta dva tipa zadataka se mogu kombinirati zajedno bez ovisnosti o ostatku stabla. Oba

tipa, uvjeti i akcije, nalaze se na listovima stabla.

Jedan čest oblik akcija je akcija čekanja. Navedena akcija jednostavno zadržava stanje

stabla u stanju izvršavanja, i nastavlja dalje tek kada je isteklo definirano vrijeme čekanja.

3.6.3. Kompoziti

Stablo se većinom grana pomoću kompozita. Kompoziti koriste i sadrže kolekciju

zadaka. Njihovo ponašanje i rezultat ovisi ponašanju njihove djece, odnosno zadataka koje

sadrže.

Popularni oblici kompozita su sekvenca i selekcija. Oba tipa kompozita pokreću

izvođenje svojih zadataka u redoslijedu. Sekvenca funkcionira tako da nastavlja izvedbu idućeg

zadatka ukoliko je prethodni zadatak vratio uspješan rezultat, inače prekida s radom i vraća

neuspješan rezultat. Selekcija funkcionira na suprotan način, prolazi kroz svu djecu, odnosno

zadatke i vraća uspješan rezultat ako je barem jedan od zadataka uspješan, inače vraća

neuspješan rezultat.

Na Slika 3-13 može se vidjeti jednostavan primjer sekvence. Stablo ponašanja će prvo

pozvati korijenski zadatak, odnosno sekvencu, koja prvo provjerava dali je neprijatelj vidljiv,

te ukoliko je uvjet uspješan, agent će se okrenuti i pobjeći.

Slika 3-13: Primjer sekvence u stablu ponašanja (Millington & Funge, 2009, p. 336)

Na Slika 3-14 stablo ponašanja će pozvati korijenski zadatak selekciju. Selekcija će prvo

pozvati napad na igrača, i ukoliko je uspješan, selekcija je gotova, u suprotnom ide na idući

zadatak.

Page 26: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

21

Slika 3-14: Primjer selekcije u stablu ponašanja (Millington & Funge, 2009, p. 336)

Osim navedenih kompozita, postoji kompozit poznat pod nazivom „Parallel“ a odnosi

se na paralelno izvođenje zadataka. Paralelni kompozit je sličan sekvenci. Izvodi set djece sve

dok jedan od njih ne vrati neuspješan rezultat. Razlika od sekvence je ta što set djece izvodi

paralelno, odnosno istovremeno.

3.6.4. Dekoratori

Naziv dekorator je uzet iz uzoraka dizajna kod objektno orijentiranog programiranja. U

kontekstu stabla odlučivanja, dekoratori su zadaci koji imaju samo jedno dijete kao zadatak.

Možemo ih zamisliti kao kompozite sa samo jednim zadatkom.

Razlika dekoratora i kompozita je ta što kompoziti na neki način modificiraju način

izvođenja djeteta. Jedan oblik dekoratora je u kojem odlučuju dali dopustiti izvođenje djeteta

ili ne, takav oblik poznat je pod nazivom „filteri“. Ukoliko ne dopuste izvršavanje djeteta,

vraćaju neuspjeh. Drugi oblik dekoratora je taj gdje se limitira broj izvođenja djeteta, poznat

pod nazivom „limit“. Zatim dekorator može izvršavati dijete u while petlji sve dok dijete ne

vrati uspješan rezultat, taj dekorator je poznat pod nazivom „until fail“. Također jedan od

poznatijih dekoratora je dekorator koji vraća suprotnu vrijednost od vrijednosti koje vrati dijete.

Pa tako ukoliko se dijete uspješno izvrši, dekorator će vratiti neuspjeh, takav dekorator je poznat

pod nazivom „inverter“.

3.6.5. Primjer stabla ponašanja

Jednostavni primjer stabla ponašanja je vidljiv na slici ispod. Kreirano stablo ponašanje

kombinira sekvencu i selekciju. Prvo se izvodi sekvenca koja ima samo jedno dijete, a to je

selekcija. Selekcija će prvo pozvati prvo dijete, uvjet u kojem provjerava dali su vrata otvorena.

Page 27: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

22

Ukoliko su vrata otvorena, stablo vraća uspjeh i završava s radom. Ukoliko vrata nisu otvorena,

selekcija ide na iduće dijete, sekvencu. Unutar sekvence lik dolazi do vrata i otvara vrata.

Slika 3-15: Primjer stablu ponašanja (Millington & Funge, 2009, p. 339)

Stabla ponašanja se mogu spremiti na takav način da njihova pod stabla se iskoriste više

puta. Primjer jednog od često korištenih pod stabala je prikazan na Slika 3-16. Pod stablo će se

izvršavati sve dok selekcija vraća uspjeh. Unutar sekvence prvo se provjerava vidljivost

neprijatelja, te ukoliko je neprijatelj vidljiv, suočava se sa njim. Ukoliko pak neprijatelj nije

vidljiv, neprijatelj ide na posljednju poznatu poziciju na kojoj je bio neprijatelj. Ovo pod stablo

ponašanja je učestalo za špijunske igre.

Page 28: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

23

Slika 3-16: Primjer pod stabla u stablu ponašanja (Millington & Funge, 2009, p. 368)

Page 29: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

24

3.7. Navigacija

Kako bi se likovi u igri uspješno mogli snalaziti na nekoj mapi, u nekom prostoru,

potrebno je koristiti neki od algoritama traženja putanje (engl. Pathfinding). Važno je znati da

se ti algoritmi trebaju koristiti samo ukoliko je zbilja potrebna navigacija jer inače uzalud troše

puno resursa. U nekim igrama je dovoljno koristiti algoritme kretanja uz kombinaciju sa

ponašanjem izbjegavanja zidova i prepreka.

Najveći problem koji nastaje korištenjem direktnih algoritama kretanja je taj što likovi

često ne mogu savladati kompleksnije prepreke, pa kao rezultat zapnu za određeni zid, ili pak

pokušavaju ići nemogućnom putanjom do cilja. Algoritmi traženja putanje u potpunosti

rješavaju taj problem.

Slika 3-17: Graf putanje za igru Rat Race (McShaffry & Graham, 2013, p. 637)

Svijet je pojednostavljen pomoću grafa sa čvorovima, ili pak sa mrežom sa rubovima

kroz koju prolazi algoritam traženja putanje između dvije točke tog grafa. Graf ili mreža

predstavljaju prohodni teren. Čvor na grafu predstavlja točku do koje agent mora doći. Kod

većine grafova agent može putovati slobodno između bilo koja dva čvora na grafu koji su

povezani lukom (McShaffry & Graham, 2013, p. 637).

Page 30: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

25

Također, svjetovi se mogu reprezentirati na više načina. Neki od načina su pomoću

rešetke, odnosno koordinatne mreže (engl. Grid). Ovakav oblik strukture je jako jednostavno

implementirati i vizualizirati. Drugi način predstavljanja svijeta je pomoću Dirichletovih

domena, ili poznatim još po nazivom Voroniievi poligoni u dvodimenzionalnom prostoru, koji

dijeli svijet u regije. Svijet možemo predstaviti i pomoću točaka vidljivosti.

Slika 3-18: Reprezentacija svijeta pomoću rešetke (Palacios, 2016, p. 54)

Slika 3-19: Točke vidljivosti u nivou igre (Rabin, 2002, p. 164)

Page 31: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

26

3.7.1. Algoritmi traženja putanje

Neki od poznatih algoritama traženja putanje su Dijkstrin algoritam traženja nakraće

putanje, DFS (Deep-First-Search) algoritam, A* algoritam traženja najbolje putanje. Algoritmi

traženja putanje se obično baziraju na određenom grafu koji predstavlja prostor u igri, i sastoji

se od čvorova i težina.

Slika 3-20: Težinski graf (Millington & Funge, 2009, p. 200)

Dijkstrin algoritam je jedan od algoritama koji se može koristiti za pronalazak najkraćeg

puta unutar igre. Originalno algoritam nije zamišljen za korištenje unutar igara, stoga ima i veći

broj nedostataka. Algoritam uzima samo jedan od niza mogućih putanja kao najbolji put, te

ostale putanje odbacuje. Zbog tog načina funkcioniranja, većinom se koristi kao dodatni

algoritam a ne glavni. Glava svrha mu je zapravo taktička analiza terena jer je znatno

jednostavniji od glavnih algoritama za traženje putanje.

Glavni algoritam traženja putanje je A* (izgovara sa na engleskom A star). A* je

algoritam koji je jednostavno implementirati, jako je učinkovit te postoji velik niz optimizacija

koje se mogu primijeniti. Većina ostalih algoritama traženja putanje je zapravo varijacija A*

algoritma. Za razliku od Dijkstrovog algoritma, A* je dizajniran za traženje putanje od točke

do točke, a ne za rješavanje najkraće putanje u problemu teorije grafova.

A* algoritam funkcionira tako da analizira svaki čvor grafa i postavlja tri vrijednosti.

Prva vrijednost se odnosi na ukupnu cijenu do tog čvora koristeći trenutnu putanju. Ta

vrijednost se naziva cilj (engl. goal) i označava se sa g. Druga vrijednost je preostala cijena od

Page 32: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

27

trenutnog čvora do cilja (g), i naziva se heurističkom vrijednošću te se označava se sa h. Treća

vrijednost je preostala cijena od početka putanje do cilja, što je zapravo vrijednost g + h. Treća

vrijednost se označava sa f, i naziva se pogodnost (engl. fitness). Cilj korištenja tih triju

vrijednosti je da vode evidenciju uspjeha trenutnog napretka.

Kod početka proces A* algoritma, prvo se uzima čvor najbliži lokaciji lika.

Page 33: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

28

3.8. Tehnike učenja

Tehnike učenja je područje često poznato i po nazivu strojno učenje (engl. Machine

Learning). Kroz povijest, strojno učenje je bilo problematično zbog resursa. Većina ranih

pokušaja strojnog učenja su rezultirali neigrivim igrama, ili pak sa lošom inteligencijom.

Strojno učenje je uspješno primijenjeno u igrama ali u ograničenim pod domenama poput

odabranih putanja kod trkaćih igara, također koriste se često kao tehnike za postizanje

određenog balansa u igri.

Najčešće se tehnike učenja koriste kako bi se agenti mogli prilagoditi svakom igraču,

učenje njihovih trikova i tehnika, tako da im predstavljaju izazov. Često agenti uče iz okoline

te to iskorištavaju na najbolji način (Millington & Funge, 2009, p. 579).

3.8.1. Osnove učenja

Postoji širok spektar tehnika korištenih za učenje, od jednostavnih do kompleksnih

poput neuronskih mreža. Tehnike učenja se mogu klasificirati u dvije skupine koje se odnose

na to kada je učenje nastalo i koji efekt izaziva u ponašanju.

Postoji online i offline učenje. Online učenje omogućuje da se agent prilagodi dinamički

na stil igranja omogućujući izazovniju igru. Nažalost dolazi sa puno problema, nemogućnosti

testiranja, pošto igra nikada nije ista. Češće se koristi offline učenje koje nastaje između

pojedinih razina unutar igre, ili pak u samom studiju dok igra još nije plasirana na tržište.

Učenje unutarnjeg ponašanjem (engl. Intra Behavior Learning) je najjednostavniji način

učenja koji mijenja mali dio ponašanja agenta, odnosno likova u igri. Ne mijenjaju cijelu

kvalitetu ponašanja već je na određeni način podešavaju. Jako su jednostavni za kontroliranje i

testiranje. Mogu se koristiti za prilagođavanja gađanja mete sa podešavanjem sile, za učenje

najbolje rute na određenom nivou, za učenje mjesta koja služe za zaklon, ili pak za učenje

najboljeg načina naganjanja i bježanja od igrača.

Učenje među ponašanjem (engl. Inter Behavior Learning) je učenje gdje likovi uče samo

ponašanje. Ukoliko lik ima potrebu naučiti najbolji način za ubijanje neprijatelja, na primjer,

može mu postaviti zamku iza prigodnog ugla. Likovi uče od nule kako djelovati unutar igre

kako bi predstavljali izazov čak i za najbolje igrače. Takva vrsta umjetne inteligencije je skoro

čista fantazija, navodi (Millington & Funge, 2009, p. 581). Kreiranje niza ponašanja, osnovnog

Page 34: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

29

sustava kretanja, alata za donošenje odluka, te odluke na visokoj razini su znatno jednostavnije

i brže za implementirati, koje zatim mogu biti podešene pomoću učenja unutarnjeg ponašanja.

3.8.2. Učenje pomoću stabla odlučivanja

U poglavlju 3.5 navedena su stabla odlučivanja koji se sastoji od niza odluka koji

definiraju akcije temeljene na određenim podacima. Stablo odlučivanja efikasno može biti

naučeno, odnosno konstruirano dinamički od seta podataka i akcija, zatim se koristi na

normalan način kako bi likovi donosili tehnike tijekom igranja.

Postoji više algoritama kako stablo odlučivanja može učiti koje se koriste za

klasifikaciju, predviđanje i statističku analizu. Algoritmi koji se koriste u igrama su bazirani na

Quinlanovom ID3 algoritmu.

ID3 (Inductive Decision tree algorithm 3, Iterative Dichotomizer 3) je jednostavan za

implementirati i relativno efikasan kao algoritam učenja. Kod implementacije koristi dvije vrste

podataka, jedan za same čvorove i odluke, drugi za primjere učenja. Funkcionira tako da prvo

kreira jedan list, kojem dodjeljuje set primjera. Zatim dijeli taj list tako da primjere podijeli u

dvije grupe, ovisno o odabranim atributima tako da čine najefikasnije stablo. Proces je

rekurzivan i radi sve dok stablo nije kreirano. Kreira se sve dok kreirano stablo nije u

mogućnosti donijeti određene akcije, u tom trenutku dodatno grananje nije potrebno

(Millington & Funge, 2009, p. 613–614).

3.8.3. Ostale tehnike učenja

Među ostalim tehnikama učenja često se koristi tehnika predviđanja akcija pomoću N-

Gram prediktor algoritma. Predviđanje akcija je dobar način poboljšavanja izazova, od

nasumične selekcije do selekcija temeljenom na prethodnim djelima. Algoritam sadrži set

vjerojatnosti za donošenje odluke (koja je obično pokret), zajedno sa kombinacijom izbora iz

prethodnih pokreta (Palacios, 2016, p. 208).

Naivni Bayesovi klasifikatori (engl. Naïve Bayes classifiers) su tehnike predviđanja

koje se koriste za klasifikaciju, tj. dodjeljivanje oznaka raznim instancama problema. Koristi se

kod seta vjerojatnosti, gdje je Bayesov teorem neovisan o samim vrijednostima koje analiziran.

Jedan od ključnih prednosti je njegova skalabilnost (Millington & Funge, 2009, p. 608).

Umjetne neuronske mreže, ili kratko neuronske mreže su biološki inspiriran algoritam.

Imaju široku primjenu u aplikacijama. U igrama se koriste u području učenja, u nešto rjeđoj

Page 35: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

30

upotrebi zato što su kompleksni i zahtjevni. Kao što navodi autor (Millington & Funge, 2009,

p. 676) često projekti koji koriste neuronske mreže, završe na kraju bez njih, iako njihova

primjena svakako postoji. Mogu se primijeniti na različite načine, posebno za tehnike

klasifikacije, što im je ujedno i primarna snaga.

Page 36: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

31

4. Plan implementacije

Implementaciju umjetne inteligencije izvršiti će se Unity alatu. Prvo su prikazane

implementacije samih klasa i njihov opis u Unity alatu, te su ukomponirane u sami projekt na

temelju opisa igre. Projekt, odnosno igra u kojoj ćemo prikazati implementaciju umjetne

inteligencije je igra pod nazivom Botornot. Prva, početna verzija Botornot igre je započeta

2015. godine na Infogamer natjecanju u Zagrebu.

Programski dio igre će biti prikazan i opisan, s naglaskom na agente i umjetnu

inteligenciju, dok ostali dijelovi koji nisu tema ovog rada biti će izostavljeni. Razlog odabira

projekta Botornot je postojanost niza različitih resursa koji su slobodni za korištenje, među

kojima su 3D modeli, zvučni efekti, sučelje, te stil i pravila igranja.

4.1. Unity

Unity je višeplatformski game engine, odnosno sustav za kreiranje i razvoj video igara

razvijen od tvrtke Unity Techologies. Razvoj na alatu započeli su Davit Helgason, Nicolas

Francis te Joachim Ante 2001. godine, da bi prva verzija izašla 2005 godine. Unity je već od

2008 godine pružao podršku za mobilne uređaje, odnosno za Appleov iPhone uredaj, te 2010.

godine u verziji 3.0 za Android uređaje.

Unity poput većine game enginea, sastoji se od različitih pomagala koja ubrzavaju i

znatno pomažu u razvoju igre. Trenutno podržava sve popularne platforme, u kojima se ubrajaju

računala, mobilni uređaji, igrače konzole, te web preglednici.

Razlog biranja tog alata je njegova jednostavnost te dostupnost svima. Unity je

besplatan svim individualnima, te poduzećima koje ima godišnju dobit manju od 100 tisuća

američkih dolara, u suprotnom, trebaju platiti licencu. Na slici 4.1, moguće je vidjeti sučelje

Unity alata.

Unity se dijeli na dva osnovna dijela. Na projekt i njegove komponente, i na scenu i

komponente scene. Scena u Unitiju je obično jedan nivo koji se izrađuje, i njegove dijelove je

moguće vidjeti u hijerarhiji ili u pogledu scene. Inspektor služi da prikaže od kojih se

komponenti i skripti određeni objekt sastoji. U inspektoru ´će biti prikazane većina naših klasa,

kojima ´ćemo mijenjat javne parametre. Klase koje su vidljive u Inspektor prozoru moraju

naslijediti klasu MonoBehaviour, te time postaju komponenta GameObject-a (objekt u igri).

Page 37: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

32

Uspoređujući to sa MVC modelom, možemo reći da MonoBehaviour pripada u View

komponenti tog modela.

Slika 4-1: Izgled Unity sučelja (Unity Technologies, 2016)

Page 38: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

33

4.2. Opis igre

Igra Botornot je igra u kojoj je glavni lik virus koji pokušava zaraziti računalo, ali

antivirusi u računalu mu to onemogućavaju. Radnja same igre je u 3d prostoru, gdje je virus

prikazan sa 3d modelom koji posjeduje određene sposobnosti kojima ubija neprijatelje,

odnosno antiviruse. Antivirusi su također prikazani sa 3d modelom i štite određene komponente

na prostoru u kojem se nalaze.

Slika 4-2: Komponente unutar igre

Način na koji se neprijatelji stvaraju na mapi je predefiniran. Neprijatelji se mogu

stvoriti iz 4 različite pozicije, od kojeg su dvije namijenjene za neprijatelje koji liječe, a

preostale dvije za neprijatelje koji napadaju igrača. Neprijatelji se stvaraju u valovima. U

svakom valu unutar određenog intervala kreiraju se neprijatelji, tek kada su svi neprijatelji

poraženi, kreće idući val.

Kako bi igru učinili zanimljivijom i izazovnijom, ubacit ćemo nešto naprednije

neprijatelje koji su zapravo agenti. Neprijatelje ćemo nazvati HealerBot i FighterBot koji rade

točno ono kao što im samo ime ukazuje. Uz njih Flybot Healer koji također može liječiti

komponente, i FlyBot Attacker koji napada igrača.

Ukoliko razmotrimo tipove neprijatelja koji liječe komponente, može se uočiti

problematika sa kojom se susrećemo. Pošto postoje 4 komponente unutar scene, neprijatelj

mora odlučiti koju komponentu prvu liječiti.

Page 39: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

34

Zatim, neprijatelji koji napadaju igrača mogu napadati unutar određene formacije, ili

pak mogu napadati igrača na način „hit and run“, gdje čim napadnu igrača pobjegnu.

Neprijatelj također može kružiti po mapi ukoliko mu je životna energija, odnosno „health“

nizak i rjeđe napadati igrača. Ukoliko je neprijatelj dovoljno pametan, može pokušati odvući

pozornost na sebe dok drugi neprijatelji dovrše liječenje komponente.

Postoji neograničen niz mogućnosti koje je moguće isplanirati za naše neprijatelje i igru. U

tablici ispod su navedeni osnovni tipovi neprijatelja i njihove funkcije.

Neprijatelj Glavna svrha Algoritam

HealerBot Lječenje komponente Automati

FighterBot Napadanje igrača Automati

Formation FighterBot Napadanje igrača Automati uz formacije

FlyBot Healer Lječenje komponente Stablo ponašanja

FlyBotAttacker Napadanje igrača Stablo ponašanja

Tablica 1. Vrsta neprijatelja uz svrhu i algoritam implementacije

4.2.1. Neprijatelji pomoću automata

U tablici (vidi Tablica 1) možemo vidjeti da imamo dva tipa neprijatelja koji koriste

automate, točnije neprijatelji Healerbot i Fighterbot.

Healerbot neprijatelj kao što je već navedeno, liječi komponente. Tu je očito stanje

lječenja, odnosno „State Healing“. Zatim, osim toga, prije nego što liječi komponentu, potrebno

ju je zapravo odabrati i doći do nje. Način biranja komponente je implementiran na način takav

da se računa postotak za svaku komponentu, zatim se generira nasumičan broj unutar ukupnog

raspona i odabere se komponenta koja je unutar nasumično odabranog raspona (rasponi se za

svaku komponentu kumulativno dodjeljuju). Postotak biranja komponente računa se na osnovu

udaljenosti agenta od komponente, i na osnovu izliječenosti komponente. Iduće stanje unutar

kojeg koristimo navedeni algoritam i putujemo do komponente je stanje dostizanja do

komponente, odnosno „State Arrive To Component“ . Te stanje smrti, odnosno „State Death“.

Page 40: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

35

Slika 4-3: Automat za HealBot-a

Na prethodnoj slici vidimo da je uvjet za liječenje komponente ispunjen tek kada je

neprijatelj na poziciji za liječenje. Ponovno traženje i dolazak na drugu komponentu izvršava

se nakon što istekne vrijeme potrebno za liječenje.

Drugi neprijatelj, Fighterbot napada igrača, gdje je uočljivo stanje napada, odnosno

„State Attack“. Zbog jednostavnosti te implementacije, nije potrebno implementirati dodatno

stanje u kojem igrač dolazi do igrača, no moguće je. Osim tog stanja neprijatelj također ima

stanje smrti, odnosno „State Death“. Ovaj neprijatelj ima jako jednostavnu primjenu, razlog je

taj što unutar stanja napada koristi drugu komponentu koja javlja samom stanju ukoliko je

neprijatelj unutar kolizije sa igračem, te u tom slučaju igraču se oduzima snaga. Stanje napada

cijelo vrijeme ima uključeno ponašanje naganjanja, tako da cijelo vrijeme prati i naganja igrača.

Slika 4-4: Automat za FighterBot-a

Page 41: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

36

4.2.2. Neprijatelji sa formacijama

Formacije su jedno jako zanimljivo područje kod video igara i imaju široku primjenu.

U našoj igri implementirat ćemo jednostavnu kružnu formaciju. Napadače, odnosno

Fighterbote ćemo ubaciti unutar formacije tako da svi zajedno formiraju krug. Neprijatelji

unutar formacije stižu do igrača, okružuju ga i napadaju, gdje im se ujedno smanjuje radijus

kruga kojeg čine. Na taj način igraču zadaju više udaraca od jednom i znatno mu smanjuju

snagu.

Navedena implementacija zahtjeva višu razinu stanja, odnosno automata. Osim

neprijatelja, sama formacija ima svoje stanje. Formacija prvo treba provjeriti dali je minimalni

broj agenata prisutan kako bi mogla funkcionirati, što prikazujemo stanjem formiranja

formacije, odnosno „State forming formation“. Zatim stanje napadanja, gdje dolazimo do

igrača, i napadamo igrača ukoliko je igrač u središtu kruga, stanje pod nazivom „State

Circular Formation Attack“. Te stanje obrane, gdje se agenti udaljuju od igrača (povećavaju

radijus) na određenoj udaljenosti prije nego što napadnu opet. To stanje se naziva „State

Circular Formation Defense“. Na slici ispod moguće je vidjeti stanja formacije.

Slika 4-5: Automat za kružnu formaciju

Zatim neprijatelji koji su unutar formacije imaju slična stanja kao i obični Fighterbot

neprijatelj, prikazani na slici ispod.

Page 42: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

37

Slika 4-6: Automat za FighterBot-a unutar formacije

4.2.3. Neprijatelji pomoću stabla ponašanja

U tablici (vidi Tablica 1) navedena su dva tipa neprijatelja koji koriste stablo ponašanja.

Flybot Healer koji je zadužen za liječenje komponenti, te Flybot Attacker koji je zadužen za

napadanje igrača. Razlog uzimanja stabla ponašanje je taj što pomoću njega jako jednostavno

slažemo neprijatelja po želji. Jednom kada imamo skup zadataka i uvjeta, jednostavno je složiti

stablo koje predstavlja ponašanje agenta.

Flybot Healer je neprijatelj kojem je primarna svrha liječiti komponente. Za razliku od

običnih neprijatelja koji liječe komponente, Flybot Healer provjerava svoju udaljenost od

igrača, te ukoliko je igrač blizu, bježi na određenu udaljenost te tek onda traži komponente koje

je potrebno liječiti. Stablo ponašanja za ovog neprijatelja je vidljivo na slici ispod.

http://editor.behavior3.com/#/editor

Page 43: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

38

Slika 4-7: Stablo ponašanja za Flybot Healer-a

Flybot Attacker je neprijatelj koji ima glavnu svrhu napasti igrača. Za razliku od

prethodnih napadača, Flybot Attacker igrača napada na način takav da čim uspješno zada udarac

igraču, odmah se odmakne od igrača. Stablo ponašanja nasumično odlučuje i bira između

napadanja, bježanja i lutanja. Bježanje će se uspješno izvesti ukoliko igrač ima jako veliku

životnu energiju ili ukoliko sam neprijatelj ima nisku životnu energiju. Na slici ispod je moguće

vidjeti stablo ponašanja za navedenog neprijatelja. Moguće je uočiti da su nasumične selekcije

i nasumične sekvence označene sa prefiksom „?“. Za slučaj kada nasumična sekvenca odabere

smjer izbjegavanja (treće pod stablo), prvo će se izvesti sekvenca koja će biti uspješna samo

ukoliko je jedan od uvjeta istinit. Prvi uvjet provjerava vlastitu energiju dok drugi provjerava

energiju neprijatelja. Ukoliko oba uvjeta nisu zadovoljena, odnosno ukoliko igrač ima malu

životnu energiju, a neprijatelj visoku, nema razloga bježanju, te se pod stablo obustavlja. Tu

Page 44: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

39

također vidimo da je zadatak „Stop Evade“ drugo dijete selektora koje će se u svakom slučaju

izvest, na taj način osiguramo da neprijatelj završi treći ogranak stabla bez da bježi od

neprijatelja.

Slika 4-8: Stablo ponašanja za Flybot Attacker-a

Page 45: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

40

5. Implementacija

U ovom poglavlju prikazana je implementacija prema prethodno navedenom planu.

Korišteni programski jezik je C#, i UnityEngine biblioteka u kojoj se nalaze osnovne klase i

metode za rad u Unity sustavu. Većina klasa nasljeđuje klasu MonoBehaviour iz UnityEngine

biblioteke koja označava da je naša klasa zapravo komponenta u Unitiju.

5.1. Kreiranje projekta

Na samom početku, u projekt smo ubacili sve potrebne resurse, modele pomoću kojih

ćemo graditi agente.

5.2. Kretnje agenata

Kako bi agenta pokrenuli, prvo ćemo implementirati njegove kretnje. Za našeg agenta,

potrebne su dvije osnovne klase:

AgentBehaviur

Agent

Te pomoćna klasa Steering.

Steering klasa nam služi za prijenos informacija o kretnji koju agent treba poduzeti. Sastoji se

od linearnog smjera kretanja, te od rotacije.

1. using UnityEngine;

2. using System.Collections;

3. public class Steering

4. {

5. public float angular;

6. public Vector3 linear;

7. public Steering() {

8. angular = 0.0 f;

9. linear = new Vector3();

10. }

11. }

5.2.1. Agent Behaviour

Agent Behaviour klasa je klasa koju je osnova za sva ponašanja koja su implementirana

u nastavku.

Page 46: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

41

Većina naših ponašanja koristi određeni objekt o kojem ovise, pa tako ponašanje 'traži'

zahtjeva objekt kojeg moramo tražiti, dok ponašanje 'bježanje' zahtjeva objekt od kojeg moramo

pobjeći. Zbog toga imamo javni objekt pod nazivom target. Objekt tipa Agent nam služi kao

referenca na agenta koji koristi to ponašanje. Na osovi tog objekta, ponašanje može pročitati

parametre agenta, ograničiti maksimalnu brzinu te najvažnije, poslati agentu objekt tipa

Steering koji sadrži smjer kretanja i orijentaciju koju agent treba pratiti.

1. using UnityEngine;

2. using System.Collections;

3. public class AgentBehaviour: MonoBehaviour

4. {

5. public GameObject target;

6. protected Agent agent;

7. public virtual void Awake() {

8. agent = gameObject.GetComponent < Agent > ();

9. }

10. public virtual void Update() {

11. agent.SetSteering(GetSteering());

12. }

13. public virtual Steering GetSteering() {

14. return new Steering();

15. }

16. }

U implementaciji koristimo tri virtualne metode: Awake, Update i GetSteering.

Awake i Update metode su metode koje poziva Unity, odnosno MonoBehavior klasa. Awake

metoda se izvršava samo jednom na samom početku te u njoj vršimo dohvaćanje komponente

Agent, Update metoda se izvršava unutar svakog framea, odnosno preko 30 puta u sekundi

gdje agentu prosljeđujemo Steering objekt. GetSteering je metoda koja koja za ostala

ponašanja ima najveći značaj jer unutar te metode će biti implementirano ponašanje.

U drugom poglavlju u kojem su opisani algoritmi kretanja agenta, navedeni su

problemi i ograničenje korištenja samo jednog ponašanja. U tu svrhu, ažurirat ćemo Update

metodu sa metodom ispod.

1. public float weight = 1.0 f;

2. // ostatak koda …

3.

4. public virtual void Update() {

5. if (agent.useBlendWeight) {

6. agent.SetSteering(GetSteering(), weight);

Page 47: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

42

7. }

8. else {

9. agent.SetSteering(GetSteering());

10. }

11. }

Može se uočiti da je u ovoj implementaciji iskorišten uzorak dizajna pod nazivom

Template Method.

5.2.2. Agent

Agent klasa je glavna komponenta koja iskorištava ponašanja i pokreće agenta. U klasi

su implementirana svojstva koja uključuju agentove sposobnosti poput brzine i akceleracije,

koja se definiraju u Unitijevom sučelju, te varijable koje pohranjuju agentovu rotaciju,

orijentaciju, vektor sile kretanja, te objekt Steering.

1. using UnityEngine;

2. using System.Collections;

3. public class Agent: MonoBehaviour

4. {

5. public float maxSpeed;

6. public float maxAccel;

7. public float orientation;

8. public float maxRotation;

9. public float maxAngularAccel;

10. public float rotation;

11. public Vector3 velocity;

12. protected Steering steering;

13. void Start() {

14. velocity = Vector3.zero;

15. steering = new Steering();

16. }

17. public void SetSteering(Steering steering) {

18. this.steering = steering;

19. }

20. }

Glavni dio implementacije prikazan je u nastavku. Unutar Update metode vrši se

pomak agenta prema izračunatoj sili kretanja i rotira se agent prema izračunatoj orijentaciji.

1. public virtual void Update() {

2. Vector3 displacement = velocity * Time.deltaTime;

Page 48: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

43

3. orientation += rotation * Time.deltaTime;

// limitiranje vrijednosti orjentacijeu na skup (0 – 360)

4. if (orientation < 0.0 f) orientation += 360.0 f;

5. else if (orientation > 360.0 f) orientation -= 360.0 f;

6. transform.Translate(displacement, Space.World);

7. transform.rotation = new Quaternion();

8. transform.Rotate(Vector3.up, orientation);

9. }

Kako bi iskoristili silu kretanja i orijentaciju, potrebno ih je izračunati na osnovu

proslijeđenog objekta Steering. Izračun se vrši u metodi LateUpdate koja se izvršava također

jednako kao i Update metoda, samo u drugom redoslijedu, odnosno izvršava se odmah nakon

Update metode.

1. public virtual void LateUpdate() {

2. velocity += steering.linear * Time.deltaTime;

3. rotation += steering.angular * Time.deltaTime;

4. if (velocity.magnitude > maxSpeed) {

5. velocity.Normalize();

6. velocity = velocity * maxSpeed;

7. }

8. if (steering.angular == 0.0 f) {

9. rotation = 0.0 f;

10. }

11. if (steering.linear.sqrMagnitude == 0.0 f) {

12. velocity = Vector3.zero;

13. }

14. steering = new Steering();

15. }

Glavni dio implementacije agenta je gotov. No kao što je navedeno u implementaciji

AgentBehavior, problem je ukoliko želimo koristiti više ponašanja istovremeno. Kako bi

agent omogućio više ponašanja od jednom, potrebno je definirati novu metodu za postavljanje

kretnji. U našoj implementaciji, koristimo težine ponašanja kako bi iskoristili više ponašanja i

dali veću prednost onim ponašanjima koja smatramo važnijim.

1. public bool useBlendWeight;

2.

3. // ostatak koda …

4.

5. public void SetSteering(Steering steering, float weight) {

Page 49: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

44

6. this.steering.linear += (weight * steering.linear);

7. this.steering.angular += (weight * steering.angular);

8. }

5.2.3. Kretanje igrača

Možemo reći da je glavni lik agent koji je pod utjecajem igrača koji igra igru. Stoga

ćemo za kontrolu glavnog lika kreirati klasu AgentPlayer. Navedena klasa nasljeđuje klasičnog

neprijatelja, samo unutar metode „Update“, dohvaća ulazne informacije sa tipkovnice i na

osnovu toga računa smjer kretanja i pomiče igrača. Rotacija se zasniva na smjeru kretanja miša,

računa se objekt tipa „Quaterion“ koji predstavlja rotaciju, na osnovu pozicije na podu u koju

pokazuje miš.

1. public class AgentPlayer: Agent {

2. public LayerMask MaskForTurning;

3. Rigidbody rb;

4. protected override void Start() {

5. base.Start();

6. rb = GetComponent < Rigidbody > ();

7. }

8. public override void Update() {

9. velocity.x = Input.GetAxis("Horizontal");

10. velocity.z = Input.GetAxis("Vertical");

11. velocity *= maxSpeed;

12. Vector3 translation = velocity * Time.deltaTime;

13. transform.Translate(translation, Space.World);

14. Quaternion quatOrient = GetTurningQuaterion(150 f, MaskForTurning);

15. rb.MoveRotation(quatOrient);

16. orientation = transform.rotation.eulerAngles.y;

17. }

18. public override void LateUpdate() {

19. SetAnimationSpeed(velocity.magnitude);

20. return;

21. }

22. public Quaternion GetTurningQuaterion(float camRayLength, LayerMask floorMask) {

23. Quaternion newRotation = Quaternion.identity;

24. Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition);

25. RaycastHit floorHit;

26. if (Physics.Raycast(camRay, out floorHit, camRayLength, floorMask)) {

27. Vector3 playerToMouse = floorHit.point - transform.position;

28. playerToMouse.y = 0 f;

29. newRotation = Quaternion.LookRotation(playerToMouse);

Page 50: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

45

30. }

31. return newRotation;

32. }

33. }

5.2.4. Naganjanje i izbjegavanje

Naganjanje i izbjegavanja su jedan od često korištenih ponašanja u mnogim igrama, pa

tako u i u poznatoj Pacman igri se mogu lako uočiti. Navedena ponašanja imaju objekt kojeg

naganjaju ili proganjaju, te u obzir uzimaju i smjer njihovog trenutnog kretanja.

Kako bi napravili naganjanje, tj. 'pursue' i izbjegavanje 'evade', prvo ćemo napraviti

traženje 'seek' i bježanje 'flee'.

Klasa Seek implementira svoje ponašanje u virtualnoj metodi GetSteering u kojoj na

osnovu traženog, tj. target objekta računa smjer kretanja koji ovisi o akceleraciji agenta.

1. public class Seek: AgentBehaviour {

2. public override Steering GetSteering() {

3. Steering steering = new Steering();

4. steering.linear = target.transform.position - transform.position;

5. steering.linear.Normalize();

6. steering.linear = steering.linear * agent.maxAccel;

7. return steering;

8. }

9. }

Klasa Flee radi na identičan način, samo rezultat smjera kretanja je suprotan, računa

razliku vektora trenutne pozicije i pozicije traženog objekta, te kao rezultat dobiva smjer

suprotan smjeru traženog objekta.

1. public class Flee: AgentBehaviour {

2. public override Steering GetSteering() {

3. Steering steering = new Steering();

4. steering.linear = transform.position - target.transform.position;

5. steering.linear.Normalize();

6. steering.linear = steering.linear * agent.maxAccel;

7. return steering;

8. }

9. }

Nakon što imamo osnovu za ponašanja naganjanjem i izbjegavanje možemo kreirati

klasu Pursue. Unutar klase se nalazi varijabla koju možemo podesiti a to je maxPrediction, na

Page 51: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

46

osnovu te varijable definiramo maksimalu udaljenost u kojoj agenti mogu predvidjeti kretanje

traženog objekta.

1. public class Pursue: Seek {

2. public float maxPrediction;

3. private GameObject targetAux;

4. private Agent targetAgent;

5. }

Varijable targetAux i targetAgent pohranjuju izvorni objekt kojeg naganjamo i

njegovu instancu Agent. Originalni objekt target zamjenjujemo novim, praznim objektom.

1. public override void Awake() {

2. base.Awake();

3. targetAgent = target.GetComponent < Agent > ();

4. targetAux = target;

5. target = new GameObject();

6. }

Unutar OnDestroy metode objekt target, koji je novo kreirani prazni objekt uništavamo

iz razloga što se koristi samo u ovom ponašanju i može se slobodno izbrisati kada se izbriše

trenutno ponašanje. OnDestroy metoda je metoda koja je automatski poziva od Unitija kada

naznačimo brisanje objekta, pa tako kada brišemo ponašanje sa našeg agenta, automatski će se

izbrisati i prazni target objekt.

1. void OnDestroy() {

2. Destroy(target);

3. }

Svrha praznog target objekta je napokon vidljiva u GetSteering metodi. Prvo se računa

smjer kretanja traženog objekta, zatim udaljenost, brzina, te na osnovu toga definiramo

varijablu prediction. Naš prazni objekt postavljamo na istu poziciju na kojoj se nalazi pravi

traženi objekt, s tim da mu pomjerimo poziciju u smjeru kretanja objekta s obzirom na

prediction. Zatim vraćamo rezultat iz osnovne klase Seek koja vraća smjer kretanja prema target

objektu, koji je u ovom slučaju pomjereni prazni objekt.

1. public override Steering GetSteering() {

2. Vector3 direction = targetAux.transform.position - transform.position;

3. float distance = direction.magnitude;

4. float speed = agent.velocity.magnitude;

5. float prediction;

6. if (speed <= distance / maxPrediction) prediction = maxPrediction;

Page 52: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

47

7. else prediction = distance / speed;

8. target.transform.position = targetAux.transform.position;

9. target.transform.position += targetAgent.velocity * prediction;

10. return base.GetSteering();

11. }

Za ponašanje izbjegavanjem, kreirat ćemo Evade klasu unutar koje je sve identično kao

i u Pursue klasi, osim klase koju nasljeđuje.

1. public class Evade: Flee { 2. 3. // isto kao u klasi Pursue 4. }

5.2.5. Dostizanje na poziciju i napuštanje pozicije

Dostizanje na poziciju i napuštanje pozicije su implementirani redom u klasama, Arrive

i Leave.

Unutar Arrive klase koristimo više javnih varijabli. Varijabla targetRadius predstavlja

ciljani radijus od središta traženog objekta. Varijabla slowRadius predstavlja radijus unutar

kojeg agent usporava, te je vrijednost ove varijable veća od prethodne.

1. public class Arrive: AgentBehaviour {

2. public float targetRadius;

3. public float slowRadius;

4. public float timeToTarget = 0.1 f;

5. }

Slično naganjanju, dostizanje na poziciju također računa smjer prema traženom objektu.

Na početku se računa brzina s obzirom na udaljenost od objekta i na varijable slowRadius i

targetRadius. Zatim u nastavku računa potrebnu silu kretanja gdje se uzima u obzir akceleracija

i trenutna agentova sila kretanja.

1. public override Steering GetSteering() {

2. Steering steering = new Steering();

3. Vector3 direction = target.transform.position - transform.position;

4. float distance = direction.magnitude;

5. float targetSpeed;

6. if (distance < targetRadius) return steering;

7. if (distance > slowRadius) targetSpeed = agent.maxSpeed;

8. else targetSpeed = agent.maxSpeed * distance / slowRadius;

9. Vector3 desiredVelocity = direction;

Page 53: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

48

10. desiredVelocity.Normalize();

11. desiredVelocity *= targetSpeed;

12. steering.linear = desiredVelocity - agent.velocity;

13. steering.linear /= timeToTarget;

14. if (steering.linear.magnitude > agent.maxAccel) {

15. steering.linear.Normalize();

16. steering.linear *= agent.maxAccel;

17. }

18. return steering;

19. }

Implementacija Leave klase je slična Arrive klasi, te umjesto targetRadius i slowRadius

imamo espaceRadius i dangerRadius.

6. public class Arrive: AgentBehaviour {

7. public float escapeRadius;

8. public float dangerRadius;

9. public float timeToTarget = 0.1 f;

10. }

Metoda GetSteering je jako slična kao kod klase Arrive. Razlika je samo u prvom dijelu

koda gdje se računa brzina kretanja na osnovu prethodno definiranih radijusa, te u definiranom

smjeru kretanja. Drugi dio koda nakon linije 9 je identičan.

1. public override Steering GetSteering() {

2. Steering steering = new Steering();

3. Vector3 direction = transform.position - target.transform.position;

4. float distance = direction.magnitude;

5. if (distance > dangerRadius) return steering;

6. float reduce;

7. if (distance < escapeRadius) reduce = 0 f;

8. else reduce = distance / dangerRadius * agent.maxSpeed;

9. float targetSpeed = agent.maxSpeed - reduce;

10. Vector3 desiredVelocity = direction;

11. desiredVelocity.Normalize();

12. desiredVelocity *= targetSpeed;

13. steering.linear = desiredVelocity - agent.velocity;

14. steering.linear /= timeToTarget;

15. if (steering.linear.magnitude > agent.maxAccel) {

16. steering.linear.Normalize();

17. steering.linear *= agent.maxAccel;

18. }

19. return steering;

Page 54: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

49

20. }

Na Slika 5-1 možemo vidjeti vizualni prikaz navedenih radijusa i ponašanje dostizanja

na poziciju i napuštanje pozicije.

Slika 5-1: Dostizanje na poziciju i napuštanje pozicije (Palacios, 2016, p. 11)

5.2.6. Suočavanje

Ponašanje suočavanje, odnosno Face je ponašanje u kojem našeg agenta rotiramo u

smjeru traženog objekta. Prije nego što implementiramo klasu Face unutar AgentBehaviour

klase dodajemo novu metodu MapToRage. Metoda jednostavno pomaže za pronalazak smjera

rotacije.

1. public float MapToRange(float rotation) {

2. rotation %= 360.0 f;

3. if (Mathf.Abs(rotation) > 180.0 f) {

4. if (rotation < 0.0 f) rotation += 360.0 f;

5. else rotation -= 360.0 f;

6. }

7. return rotation;

8. }

Također prije implementacije suočavanja, implementirat ćemo osnovno ponašanje

usklađivanja, odnosno klasa Allign. Klasa koristi jednake principe kao i Arrive samo za rotaciju.

Page 55: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

50

Klasa na osnovu trenutne orijentacije traženog agenta računa razliku i željenu brzinu dostizanja

rotacije kako bi se uskladila s orijentacijom traženog objekta.

1. public class Align: AgentBehaviour {

2. public float targetRadius;

3. public float slowRadius;

4. public float timeToTarget = 0.1 f;

5. public override Steering GetSteering() {

6. Steering steering = new Steering();

7. float targetOrientation = target.GetComponent < Agent > ().orientation;

8. float rotation = targetOrientation - agent.orientation;

9. rotation = MapToRange(rotation);

10. float rotationSize = Mathf.Abs(rotation);

11. if (rotationSize < targetRadius) return steering;

12. float targetRotation;

13. if (rotationSize > slowRadius) targetRotation = agent.maxRotation;

14. else targetRotation = agent.maxRotation * rotationSize / slowRadius;

15. targetRotation *= rotation / rotationSize;

16. steering.angular = targetRotation - agent.rotation;

17. steering.angular /= timeToTarget;

18. float angularAccel = Mathf.Abs(steering.angular);

19. if (angularAccel > agent.maxAngularAccel) {

20. steering.angular /= angularAccel;

21. steering.angular *= agent.maxAngularAccel;

22. }

23. return steering;

24. }

25. }

Napokon možemo impelentirati klasu suočavanja, tj. klasu Face. Klasa nasljeđuje

prethodno kreiranu klasu Allign i definira dodatnu varijablu targetAux. Poput ponašanja

naganjanja, targerAux varijabla pohranjuje pravi traženi objekt, dok target varijabla kreira

prazni objekt kojeg u GetSteering metodi prosljeđuje klasi Allign.

1. public class Face: Align {

2. protected GameObject targetAux;

3. public override void Awake() {

4. base.Awake();

5. targetAux = target;

6. target = new GameObject();

7. target.AddComponent < Agent > ();

8. }

9. void OnDestroy() {

Page 56: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

51

10. Destroy(target);

11. }

12. }

U implementacija GetSteering metode, pomjeramo orijentaciju našeg praznog objekta

tako da je usmjerena u smjeru u kojem se nalazi naš traženi objekt, kako bi allign klasa vratila

usklađenu rotaciju.

1. public override Steering GetSteering() {

2. Vector3 direction = targetAux.transform.position - transform.position;

3. if (direction.magnitude > 0.0 f) {

4. float targetOrientation = Mathf.Atan2(direction.x, direction.z);

5. targetOrientation *= Mathf.Rad2Deg;

6. target.GetComponent < Agent > ().orientation = targetOrientation;

7. }

8. return base.GetSteering();

9. }

5.2.7. Lutanje

Lutanje je tehnika koja je savršena kada želimo postići nasumično kretanje. Prije

početka implementacije, unutar AgentBehaviour klase implementiramo dodatnu metodu

GetOriAsVec koja pretvara vrijednost orijentacije u vektor.

1. public Vector3 GetOriAsVec(float orientation) {

2. Vector3 vector = Vector3.zero;

3. vector.x = Mathf.Sin(orientation * Mathf.Deg2Rad) * 1.0 f;

4. vector.z = Mathf.Cos(orientation * Mathf.Deg2Rad) * 1.0 f;

5. return vector.normalized;

6. }

Klasa Wander nasljeđuje prethodno definiranu klasu Face. Ponašanje lutanjem

funkcionira na osnovu rotacije. Parametri offset, radius, rate definiraju vrijednosti na osnovu

kojih se nasumično definira smjer kretanja. Na slici je moguće vidjeti značenje tih varijabli.

1. public class Wander: Face {

2. public float offset;

3. public float radius;

4. public float rate;

5. public override void Awake() {

6. target = new GameObject();

7. target.transform.position = transform.position;

Page 57: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

52

8. base.Awake();

9. }

10. }

Metoda GetSteering prvo definira nasumičnu orijentaciju na osnovu koje računa traženu

rotaciju s obzirom na trenutnu orijentaciju agenta.

1. public override Steering GetSteering() {

2. Steering steering = new Steering();

3. float wanderOrientation = Random.Range(-1.0 f, 1.0 f) * rate;

4. float targetOrientation = wanderOrientation + agent.orientation;

5. Vector3 orientationVec = OriToVec(agent.orientation);

6. Vector3 targetPosition = (offset * orientationVec) + transform.position;

7. targetPosition = targetPosition + (OriToVec(targetOrientation) * radius);

8. targetAux.transform.position = targetPosition;

9. steering = base.GetSteering();

10. steering.linear = targetAux.transform.position - transform.position;

11. steering.linear.Normalize();

12. steering.linear *= agent.maxAccel;

13. return steering;

14. }

Slika 5-2: Način funkcioniranja algoritma lutanja (Palacios, 2016, p. 16)

Page 58: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

53

5.2.8. Suočavanje prema naprijed

Korištenjem prethodnih ponašanja, poput naganjanja, dostizanja na poziciju, nisu

obuhvaćali rotiranje, naš agent bi „klizio“ prema traženom objektu bez da se okrene u smjeru

kretanja. Stoga, suočavanje, odnosno rotiranje prema smjeru kretanja je jedno od važnijih

ponašanja ukoliko je bitna orijentacija našeg agenta.

Implementaciju vršimo u klasi FaceForward. Izračun orijentacije vršimo pomoću sile

smjera kretanja.

1. public class FaceForward: Align {

2. private Agent targetAgent;

3. public override void Awake() {

4. base.Awake();

5. }

6. void OnEnable() {

7. target = new GameObject();

8. targetAgent = target.AddComponent < Agent > ();

9. }

10. void OnDestroy() {

11. Destroy(target);

12. }

13. public override Steering GetSteering() {

14. Vector3 velocity = agent.velocity;

15. if (velocity.magnitude <= 0.0001 f) return new Steering();

16. targetAgent.orientation = Mathf.Atan2(velocity.x, velocity.z) * Mathf.Rad2Deg;

17. return base.GetSteering();

18. }

19. }

5.2.9. Izbjegavanje zidova

Tehnika izbjegavanja zidova funkcionira na osnovu sigurnosne zone i vektora normale.

Za provjeravanje zida, koristi se metoda Raycast iz Unity alata koja na osnovu vektora

provjerava ukoliko se nalazi prepreka sa kolizijama.

Varijable avoidDistance definira vrijednost udaljenosti od zida, lookAhead predstavlja

vrijednost dužine vektora koji provjerava postojanost zida. Unutar GetSteering metode nalazi

se implementacija zaobilaska zida. Ukoliko postoji prepreka, na osnovu vektora normale

dobivamo smjer suprotan od zida na temelju kojeg postavljamo poziciju praznog objekta. U

Page 59: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

54

tom slučaju, osnovna klasa Seek računa i vraća vrijednost tipa Steering na osnovu prethodno

pozicioniranog objekta target.

1. public class AvoidWall: Seek {

2. public float avoidDistance;

3. public float lookAhead;

4. public override void Awake() {

5. base.Awake();

6. target = new GameObject();

7. }

8. public override Steering GetSteering() {

9. Steering steering = new Steering();

10. Vector3 position = transform.position;

11. Vector3 rayVector = agent.velocity.normalized * lookAhead;

12. Vector3 direction = rayVector;

13. RaycastHit hit

14. if (Physics.Raycast(position, direction, out hit, lookAhead)) {

15. position = hit.point + hit.normal * avoidDistance;

16. target.transform.position = position;

17. steering = base.GetSteering();

18. }

19. return steering

20. }

21. }

5.2.10. Izbjegavanje agenata

Izbjegavanje agenata je ponašanje koje omogućuje zaobilazak agenata koji su u blizini.

Način na koji dohvaćamo agente je pomoću GameManager klase, koja je objašnjena u poglavlju

1. Algoritam prolazi kroz sve agenta, računa njihove udaljenost i sile kretanja. Na osnovu toga

zatim računa vrijeme do kolizije kako bi pronašao agenta koji će prvi biti u koliziji sa trenutnim.

Ukoliko pronađe takvog agenta zaobilazi ga pomoću vektora smjera, odnosno vraća Steering

objekt sa željenim smjerom kretanja koji je suprotan od smjera u kojem se nalazi drugi agent.

1. public class AvoidAgent: AgentBehaviour {

2. public float CollisionRadius = 0.4 f;

3. public override Steering GetSteering() {

4. Steering steering = new Steering();

5. float shortestTime = Mathf.Infinity;

6. GameObject firstTarget = null;

Page 60: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

55

7. float firstMinSeparation = 0.0 f;

8. float firstDistance = 0.0 f;

9. Vector3 firstRelativePos = Vector3.zero;

10. Vector3 firstRelativeVel = Vector3.zero;

11. foreach(GameObject t in GameManager.Instance.Enemies) {

12. if (t == null) continue;

13. Vector3 relativePos;

14. Agent targetAgent = t.GetComponent < Agent > ();

15. relativePos = t.transform.position - transform.position;

16. Vector3 relativeVel = targetAgent.velocity - agent.velocity;

17. float relativeSpeed = relativeVel.magnitude;

18. float timeToCollision = Vector3.Dot(relativePos, relativeVel);

19. timeToCollision /= relativeSpeed * relativeSpeed * -1;

20. float distance = relativePos.magnitude;

21. float minSeparation = distance - relativeSpeed * timeToCollision;

22. if (minSeparation > 2 * CollisionRadius) continue;

23. if (timeToCollision > 0.0 f && timeToCollision < shortestTime) {

24. shortestTime = timeToCollision;

25. firstTarget = t;

26. firstMinSeparation = minSeparation;

27. firstRelativePos = relativePos;

28. firstRelativeVel = relativeVel;

29. }

30. }

31. if (firstTarget == null) return steering;

32. if (firstMinSeparation <= 0.0 f || firstDistance < 2 * CollisionRadius)

firstRelativePos = firstTarget.transform.position;

33. else firstRelativePos += firstRelativeVel * shortestTime;

34. firstRelativePos.Normalize();

35. steering.linear = -firstRelativePos * agent.maxAccel;

36. return steering;

37. }

38. }

Page 61: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

56

5.3. Donošenje odluka pomoću automata

Za donošenje odluka i kreiranje stanja u našoj igri, implementirat ćemo konačnih

automate. Prvo ćemo definirati osnovnu arhitekturu i osnovne klase kako bi poslije mogli

kreirati konkretna stanja.

5.3.1. Osnovna arhitektura

Automati se sastoje od uvjeta, prijelaza i stanja. Naša osnovna klasa za uvjete sadrži

virtualnu metodu Test koja vraća rezultat.

1. public class Condition {

2. public virtual bool Test() {

3. return false;

4. }

5. }

Tranzicija između dva stanja predstavljamo objektom koji sadrži željeno stanje, i uvjet

koji mora biti ispunjen kako bi se traženo stanje ostvarilo.

1. public class Transition {

2. public Condition condition;

3. public State target;

4. }

Zatim definiramo klasu State. Klasa State je zapravo komponenta u Unitiju, te kao takva

biti će prikazana unutar Unity sustava. Stanje može posjedovati različit broj tranzicija prema

drugom stanju koje pohranjujemo u transitions listi. Implementacija se sastoji od niza virtualnih

metoda koje trebaju biti implementirane prilikom izrade konkretnog stanja. Metoda LateUpdate

testira ispunjenost uvjeta svake od tranzicija, te ukoliko je uvjet ispunjen, trenutno stanje se

deaktivira, i željeno uključuje.

1. public class State: MonoBehaviour {

2. public List < Transition > transitions;

3. public virtual void Awake() {

4. transitions = new List < Transition > ();

5. }

6. public virtual void OnEnable() {

7. // TO-DO develop state's initialization here

8. }

9. public virtual void OnDisable() {

10. // TO-DO develop state's finalization here

Page 62: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

57

11. }

12. public virtual void Update() {

13. // TO-DO develop behaviour here

14. }

15. public void LateUpdate() {

16. foreach(Transition t in transitions) {

17. if (t.condition.Test()) {

18. t.target.enabled = true;

19. this.enabled = false;

20. return;

21. }

22. }

23. }

24. }

5.3.2. Definiranje osnovnih uvjeta

Nakon kreirane arhitekture, možemo kreirati osnovne uvjete koji su najčešće korišteni.

Najjednostavniji uvjet je uvjet koji direktno vraća vrijednost tipa bool.

1. public class ConditionBool: Condition {

2. public bool testBool;

3. public override bool Test() {

4. return testBool;

5. }

6. }

Zatim jedan od čestih uvjeta je uvjet provjeravanja vrijednosti. ConditionFloat klasa

provjerava dali je testna vrijednost unutar željenog raspona.

1. public class ConditionFloat: Condition {

2. public float valueMin;

3. public float valueMax;

4. public float valueTest;

5. public override bool Test() {

6. if (valueMax >= valueTest && valueTest >= valueMin) return true;

7. return false;

8. }

9. }

Idući uvjet je uvjet testira vrijednost dvaju uvjeta i vraća istinitost ukoliko su oba istinita.

1. public class ConditionAnd: Condition {

2. public Condition conditionA;

Page 63: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

58

3. public Condition conditionB;

4. public override bool Test() {

5. if (conditionA.Test() && conditionB.Test()) return true;

6. return false;

7. }

8. }

Nešto kompleksniji uvjet je uvjet u kojem provjeravamo dali je objekt dovoljno udaljen.

ConditionTargetFar je klasa koja računa udaljenost i provjerava dali je objekt udaljeniji od

maksimalne udaljenosti.

1. public class ConditionTargetFar: Condition {

2. public GameObject origin;

3. public GameObject target;

4. public float maxDistance;

5. public override bool Test() {

6. if (origin == null || target == null) return false;

7. Vector3 originPos = origin.transform.position;

8. Vector3 targetPos = target.transform.position;

9. if (Vector3.Distance(originPos, targetPos) > maxDistance) return true;

10. return false;

11. }

12. }

Idući uvjet provjerava upravo suprotno, ukoliko je traženi objekt unutar određene

udaljenosti.

1. public class ConditionTargetClose: Condition {

2. public GameObject origin;

3. public GameObject target;

4. public float minDistance;

5. public override bool Test() {

6. if (origin == null || target == null) return false;

7. Vector3 originPos = origin.transform.position;

8. Vector3 targetPos = target.transform.position;

9. if (Vector3.Distance(originPos, targetPos) <= minDistance) return true;

10. return false;

11. }

12. }

Zatim idući uvjet provjerava vidljivost traženog objekta.

Page 64: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

59

1. public class ConditionTargetVisible: Condition {

2. public GameObject origin;

3. public GameObject target;

4. public override bool Test() {

5. bool passTest = false;

6. if (origin != null && target != null) {

7. Vector3 originPos = origin.transform.position + Vector3.up;

8. Vector3 targetPos = target.transform.position + Vector3.up;

9. Vector3 direction = targetPos - originPos;

10. RaycastHit hit;

11. if (Physics.Raycast(originPos, direction, out hit)) {

12. if (hit.collider.gameObject.Equals(target)) passTest = true;

13. else passTest = false;

14. }

15. }

16. return passTest;

17. }

18. }

5.3.3. Implementacija stanja

Stanja su definirana u poglavlju 0 gdje se navode neprijatelji temeljeni na automatima i

neprijatelji sa formacijama.

Prvo definiramo osnovni predložak za stanja koja mogu prijeći u stanje smrti.

StateDefault je klasa koja definira traženi predložak. Pomoću instance tipa StateHolder, dolazi

do komponente EnemyEntity što je ujedno osnovna klasa bilo kojeg neprijatelja u igri. U toj

klasi postoji događaj pod nazivom OnEmptyHealth na koji se klasa pretplaćuje. Na taj način

štedimo performanse izbjegavajući učestalo provjeravanje snage kako bi mogli izvršiti

tranziciju u stanje smrti. Također, u istoj klasi postavljamo unutar metode OnEnable aktivno

stanje za StateHolder komponentu.

1. public class StateDefault: State {

2. public StateHolder Owner;

3. public StateDie StateDie;

4. private ConditionBool _condition;

5. public override void Awake() {

6. base.Awake();

7. _condition = new ConditionBool();

8. _condition.test = false;

9. if (StateDie) {

Page 65: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

60

10. Owner.GetComponent <EnemyEntity> ().OnEmptyHealth.AddListener(OnEmptyHealth);

11. Transition transition = new Transition();

12. transition.condition = _condition;

13. transition.target = StateDie;

14. transitions.Add(transition);

15. }

16. }

17. void OnEmptyHealth() {

18. _condition.test = true;

19. }

20. public override void OnEnable() {

21. base.OnEnable();

22. Owner.ActiveState = this;

23. }

24. }

Zatim možemo implementirati i stanje smrti. Navedeno stanje je jednostavno za

implementirati ukoliko se glavna logika događa u klasi neprijatelja, kao što je u ovom slučaju

klasa EnemyEntity. Stanje smrti jednostavno se pozove kada je snaga neprijatelja jednaka nuli,

gdje stanje poziva metodu pod nazivom „Die“ koju posjeduje svaki od entiteta neprijatelja.

Zahvaljujući toj arhitekturi stanje je jednostavno za implementirati.

1. public class StateDie: StateDefault {

2. public override void Awake() {

3. base.Awake();

4. }

5. public override void OnEnable() {

6. base.OnEnable();

7. if (Owner.GetComponent < IEntity > () != null)

Owner.GetComponent < IEntity > ().Die();

8. }

9. public override void OnDisable() {

10. base.OnDisable();

11. }

12. }

Nešto kompleksnije stanje je stanje Attack. To je stanje koje koristi neprijatelj

FighterBot. Unutar stanja se definiraju osnovna svojstva napada, poput jačine i brzine napada.

Zatim koristi se objekt DamageDealer tipa OnColliderEvents koji izvještava klasu o kolizijama.

Kada se traženi objekt (igrač) nađe u koliziji sa trenutnim agentom, pozvat će se prvo metoda

OnDamageTriggerStart, te zatim OnDamageTriggerEnter gdje zapravo igraču oduzimamo

Page 66: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

61

energiju. U metodi OnDamageTriggerExit isključujemo animaciju za napad. Prilikom

uključivanja samog stanja, uključujemo ponašanje kretanjem, koje u ovom slučaju pomoću

unity alata postavljamo na ponašanje naganjanjem. Kod isljučivanja stanja, ponašanje

isključujemo. Postoji i dodatno ponašanje, definirano nazivom AdditionalBehavior. koje se

može koristiti.

1. public class StateAttack: StateDefault {

2. [Tooltip("Usually Face (for formation enemy) or Pursue")]

public AgentBehaviour ActiveBehaviour;

3. [Tooltip("Usually FaceForward of similar behavior used with Arrive/Pursue")]

public AgentBehaviour AdditionalBehavior;

4. [Header("Attack Properties")]

public float AttackDamage = 2 f;

5. public float AttackFrequency = 0.5 f;

6. public OnColliderEvents DamageDealer;

7. public GameObject _target;

8. public override void Awake() {

9. base.Awake();

10. if (!DamageDealer) {

11. DamageDealer = Owner.GetComponentInChildren < OnColliderEvents > ();

12. }

13. }

14. public override void OnEnable() {

15. base.OnEnable();

16. _target = GameManager.Instance.Player;

17. ActiveBehaviour.target = _target;

18. ActiveBehaviour.enabled = true;

19. if (AdditionalBehavior) AdditionalBehavior.enabled = true;

20. if (DamageDealer) {

21. DamageDealer.TriggerStayFrequency = AttackFrequency;

22. DamageDealer.OnTriggerEnterEvent.AddListener(OnDamageTriggerStart);

23. DamageDealer.OnTriggerStayEvent.AddListener(OnDamageTriggerEnter);

24. DamageDealer.OnTriggerExitEvent.AddListener(OnDamageTriggerExit);

25. }

26. }

27. public override void OnDisable() {

28. base.OnDisable();

29. ActiveBehaviour.enabled = false;

30. if (AdditionalBehavior) AdditionalBehavior.enabled = false;

31. if (DamageDealer) {

32. DamageDealer.OnTriggerEnterEvent.RemoveListener(OnDamageTriggerStart);

33. DamageDealer.OnTriggerStayEvent.RemoveListener(OnDamageTriggerEnter);

Page 67: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

62

34. DamageDealer.OnTriggerExitEvent.RemoveListener(OnDamageTriggerExit);

35. }

36. }

37. void OnDamageTriggerStart() {

38. Owner.GetComponent < EntityAnimations > ().

SetAnimation(EntityAnimations.EntityAnimType.Attack, true);

39. }

40. void OnDamageTriggerEnter() {

41. DamagableEntity playerDmg = _target.GetComponent < DamagableEntity > ();

42. if (playerDmg) {

43. playerDmg.ApplyDamage(AttackDamage);

44. }

45. }

46. void OnDamageTriggerExit() {

47. Owner.GetComponent < EntityAnimations > ().

SetAnimation(EntityAnimations.EntityAnimType.Attack, false);

48. }

49. }

Kod neprijatelja HealerBot, koristimo ponašanje dostizanja na poziciju. Također

kompleksniji oblik stanja gdje prvo pomoću ComponentPicker klase tražimo prigodne

komponente za liječenje. Traženje se izvršava svakih 5 sekundi tako da ukoliko u međuvremenu

druga komponenta zahtjeva veću potrebu za liječenje, onda se bira ta nova komponenta. Stanje

je aktivno sve dok igrač ne zakorači u prostor blizu komponente gdje može započeti stanje

liječenja. U tom trenutku, se poziva metoda OnHealEnter koja postavlja trenutnu komponentu

stanju liječenja, i postavlja uvjet za liječenje. Poput prethodnog stanja, ovo stanje također

uključuje dva ponašanja koja su točno definirana, a to su dostizanje na poziciju u suočavanje

prema naprijed, tako da agent može doći do komponente sa pravilnom rotacijom.

1. public class StateArriveToComponent: StateDefault {

2. [Header("Seek Component Parameters")]

public OnColliderEvents HealDealer;

3. public ComponentPicker ComponentPicker;

4. public StateHeal NextState;

5. [Header("ReadOnly")]

public DamagableEntity TargetComponent;

6. private ConditionBool _conditionToHeal;

7. private FaceForward _faceForwardBehaviour;

8. public Arrive _arriveBehaviour;

9. private WaitForSeconds _wait = new WaitForSeconds(5 f);

10. public override void Awake() {

Page 68: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

63

11. base.Awake();

12. if (!HealDealer)

13. HealDealer = Owner.GetComponentInChildren < OnColliderEvents > ();

14. _arriveBehaviour = Owner.GetComponent < Arrive > ();

15. if (!_arriveBehaviour)

_arriveBehaviour = Owner.gameObject.AddComponent < Arrive > ();

16. _faceForwardBehaviour = Owner.GetComponent < FaceForward > ();

17. if (!_faceForwardBehaviour)

_faceForwardBehaviour = Owner.gameObject.AddComponent < FaceForward > ();

18. _conditionToHeal = new ConditionBool();

19. _conditionToHeal.test = false;

20. if (NextState) {

21. Transition transition = new Transition();

22. transition.condition = _conditionToHeal;

23. transition.target = NextState;

24. transitions.Add(transition);

25. }

26. }

27. public override void OnEnable() {

28. base.OnEnable();

29. _conditionToHeal.test = false;

30. _faceForwardBehaviour.enabled = true;

31. StartCoroutine(PerformSearch());

32. if (HealDealer)

33. HealDealer.OnTriggerEnterTransformEvent.AddListener(OnHealEnter);

34. }

35. public override void OnDisable() {

36. base.OnDisable();

37. _arriveBehaviour.enabled = false;

38. _faceForwardBehaviour.enabled = false;

39. if (HealDealer)

40. HealDealer.OnTriggerEnterTransformEvent.RemoveListener(OnHealEnter);

41. }

42. void SearchAndSetTargetComponent() {

43. TargetComponent= ComponentPicker.GetBestComponent(GameManager.Instance.Components);

44. ComponentPicker.SetCurrentComponent(TargetComponent);

45. if (TargetComponent != null) {

46. _arriveBehaviour.target = TargetComponent.gameObject;

47. _arriveBehaviour.enabled = true;

48. }

49. }

50. public IEnumerator PerformSearch() {

51. SearchAndSetTargetComponent();

Page 69: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

64

52. yield return _wait;

53. if (!_conditionToHeal.test)

54. yield return PerformSearch();

55. }

56. void OnHealEnter(Transform transf) {

57. DamagableEntity component = transf.GetComponentInParent < DamagableEntity > ();

58. if (component && component == TargetComponent) {

59. if (NextState)

60. NextState.CurrentComponent = TargetComponent;

61. _conditionToHeal.test = true;

62. }

63. }

64. }

Zatim iduće stanje je stanje liječenja. Isječak klase je moguće vidjeti ispod, zbog

veličine koda, metoda Awake je skraćena, njezina implementacija je skoro identična kao kod

prethodnih stanja. Na početku, stanje liječenja poziva metodu OnHealEnter gdje postavlja

animaciju liječenja, te na kraju stanja poziva metodu OnHealExit koja isključuje animaciju

liječenja. Sve dok je agent unutar prostora za liječenje, pozivat će se metoda OnHeal gdje se

vrši povećavanje energije komponente. Stanje završava u trenutku kada metoda IsHealingDone

vrati istinit rezultat.

1. public class StateHeal: StateDefault {

2. [Header("Heal Properties")]

public float HealDamage = 2 f;

3. public float HealFrequency = 0.5 f;

4. public float MinHealTimeBeforeSearch = 4 f;

5. public float MaxHealTimeBeforeSearch = 8 f;

6. public OnColliderEvents HealDealer;

7. public State NextState;

8. [Header("ReadOnly")]

public DamagableEntity CurrentComponent;

9. protected ConditionBool _conditionState;

10. private float _lastWrittenTime = 0 f;

11. private bool _isHealing = false;

12. public AgentBehaviour _faceBehaviour;

13. public override void Awake() {

14. base.Awake();

15. // INICIJALIZACIJA I DOHVAT KOMPONENTI

16. }

17. public override void OnEnable() {

18. base.OnEnable();

Page 70: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

65

19. _lastWrittenTime = Time.time;

20. _conditionState.test = false;

21. if (CurrentComponent) {

22. _faceBehaviour.target = CurrentComponent.gameObject;

23. _faceBehaviour.enabled = true;

24. if (HealDealer) {

25. HealDealer.TriggerStayFrequency = HealFrequency;

26. HealDealer.OnTriggerStayEvent.AddListener(OnHeal);

27. OnHealEnter();

28. }

29. } else

30. Debug.LogError("No Component Found");

31. }

32. public override void OnDisable() {

33. base.OnDisable();

34. _faceBehaviour.enabled = false;

35. if (HealDealer) {

36. HealDealer.OnTriggerStayEvent.RemoveListener(OnHeal);

37. OnHealExit();

38. }

39. }

40. public override void Update() {

41. base.Update();

42. _conditionState.test = IsHealingDone();

43. }

44. void OnHealEnter() {

45. Owner.GetComponent < EntityAnimations > ().

SetAnimation(EntityAnimations.EntityAnimType.Heal, true);

46. _isHealing = true;

47. }

48. void OnHeal() {

49. if (!CurrentComponent) return;

50. CurrentComponent.ApplyDamage(HealDamage * -1);

51. _isHealing = true;

52. }

53. void OnHealExit() {

54. Owner.GetComponent < EntityAnimations > ().SetAnimation(EntityAnimations.EntityAnim

Type.Heal, false);

55. _isHealing = false;

56. }

57. bool IsHealingDone() {

58. bool healingDone = false;

Page 71: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

66

59. if (CurrentComponent != null && CurrentComponent.Health.IsFullHealth())

healingDone = true;

60. if (!_isHealing) healingDone = true;

61. if (Time.time - _lastWrittenTime < MinHealTimeBeforeSearch) healingDone = false;

62. else if(Time.time-_lastWrittenTime > MaxHealTimeBeforeSearch) healingDone = true;

63. return healingDone;

64. }

65. }

Page 72: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

67

5.4. Donošenje odluka pomoću stabla ponašanja

Implementacija stabla ponašanja je slična implementaciji prethodnih algoritama. Prvo

se implementiraju klase koje se trebaju nadalje proširiti sa vlastitom implementacijom. Način

na koji implementiramo stablo ponašanja se temelji na korutinama (engl. Courutines) Korutine

su metode koje omogućuju pauziranje izvođenja funkcije na određeni vremenski raspon.

Upravo to svojstvo je idealno za stablo ponašanja, jer stablo je strukturirano na rekurzivan

način, gdje određeni tipovi zadataka pozivaju zadatke djece koji mogu potrajati, te zahvaljujući

korutinama, idući zadatak će se pokrenuti tek nakon što trenutni završi sa radom.

Prvo ćemo kreirati osnovne klase: Task, Action, Condition, Decorator.

5.4.1. Implementacija osnovnih klasa

U stablu ponašanja najosnovnija klasa koju prvo implementiramo je klasa Task. Unutar

navedene klase se nalazi osnovna logika stabla ponašanja koju nadalje koriste sve klase.

Zadatak se sastoji od niza djece koji su zapravo zadaci pohranjeni u listi pod nazivom

children. Zadatak mora imati rezultat, koji predstavljamo pomoću tipa bool te pohranjuje

informaciju o završenosti zadatka. Naime implementacije stabla ponašanja mogu biti

implementirane na druge načine. Jedan od čestih oblika ne vraća bool tip podataka, već vraća

tip koji ima vrijednosti „Runing“, „Success“, „Fail“. Zbog korištenja tzv. Courutines nemamo

potrebu korištenja tog načina zbog toga što stablo ponašanje neće nastaviti dalje dok zadatak

koji se izvršava nije gotov.

1. public class Task: MonoBehaviour {

2. public Blackboard Blackboard;

3. public List < Task > children;

4. protected bool result = false;

5. protected bool isFinished = false;

6. protected WaitForFixedUpdate _waitForFixedUpdate = new WaitForFixedUpdate();

7. public virtual void SetResult(bool r) {

8. result = r;

9. isFinished = true;

10. }

11. public virtual IEnumerator Run(Blackboard blackboard) {

12. SetResult(true);

13. yield

14. return _waitForFixedUpdate;

15. }

Page 73: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

68

16. public virtual IEnumerator RunTask() {

17. yield

18. return StartCoroutine(Run(Blackboard));

19. }

20. public bool GetResult() {

21. return result;

22. }

23. public bool IsFinished() {

24. return isFinished;

25. }

26. }

Osnovna klasa za uvjete implementira virtualnu metodu Run. Unutar te metode uvjeti

provjeravaju dali su određena svojstva zadovoljena ili ne, te na osnovu toga postavljaju rezultat.

1. public class ConditionBT: Task {

2. public override IEnumerator Run() {

3. isFinished = false;

4. bool r = false;

5. // implement your behaviour here

6. // define result (r) whether true or false

7. SetResult(r);

8. yield break;

9. }

10. }

Akcije u stablu su implementirane na sličan način kao i uvjeti. Glavna razlika akcija je

ta što akcije uvijek vraćaju uspješan rezultat, te nema potrebe za postavljanjem rezultata.

Ukoliko imamo iznimku gdje zadatak može vratiti rezultat, jednostavno postavimo rezultat kao

i kod uvjeta i prekinemo izvođenje metode pomoću „yield break“.

1. public class ActionBT: Task {

2. public override IEnumerator Run() {

3. isFinished = false;

4. // implement your behaviour here

5. return base.Run();

6. }

7. }

Osnovna klasa za dekoratore je jako jednostavna. Dekorator posjeduje samo jedno

dijete.

1. public class Decorator: Task {

Page 74: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

69

2. public Task child;

3. }

5.4.2. Implementacija kompozita

Implementacija kompozita, se odnosi na implementaciju sekvence i selektora.

Implementacija selektora je prikazana ispod. Prolazeći kroz listu zadataka, selektor pomoću

naredbe „yield return“ pokreće izvođenje zadatka djeteta. Ostatak koda (nakon linije 8) će se

izvršiti tek nakon što je dijete izvršilo potreban zadatak, zahvaljujući korutinama. U slučaju da

dijete vrati uspješan rezultat, selekcija završava.

1. public class Selector: Task {

2. public override void SetResult(bool r) {

3. if (r == true) isFinished = true;

4. }

5. public override IEnumerator RunTask() {

6. foreach(Task t in children) {

7. t.Blackboard = Blackboard;

8. yield return StartCoroutine(t.RunTask());

9. if (t.GetResult()) {

10. SetResult(true);

11. yield break;

12. }

13. }

14. }

15. }

Za razliku od selektora, sekvenca provjerava dali je zadatak djeteta neuspješan, te

ukoliko je neuspješan, prekida izvršavanje i vraća neuspjeh.

1. public class Sequence: Task {

2. public override void SetResult(bool r) {

3. if (r == true) isFinished = true;

4. }

5. public override IEnumerator RunTask() {

6. foreach(Task t in children) {

7. t.Blackboard = Blackboard;

8. yield return StartCoroutine(t.RunTask());

9. if (!t.GetResult()) {

10. result = false;

11. SetResult(false);

12. yield break;

Page 75: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

70

13. }

14. }

15. SetResult(true);

16. }

17. }

Osim navedene dvije implementacije, kreirat ćemo i nedeterminističku sekvencu i

selekor. Jedina razlika u implementaciji što prije prolaska kroz listu djece, lista se izmiješa.

1. public class NonDeterministicSelector: Task {

2. public override void SetResult(bool r) {

3. if (r == true) isFinished = true;

4. }

5. public override IEnumerator RunTask() {

6. yield return ShuffleTasks();

7. // Isječak isti kao kod implementacije sekvence

8. }

9. IEnumerator ShuffleTasks() {

10. children.Shuffle < Task > ();

11. yield return _waitForFixedUpdate;

12. }

13. }

Izmjena u implementaciji nedeterminističke sekvence.

1. public class NonDeterministicSequence: Task {

2. public override void SetResult(bool r) {

3. if (r == true) isFinished = true;

4. }

5. public override IEnumerator RunTask() {

6. yield return ShuffleTasks();

7. // Isječak isti kao kod implementacije sekvence

8. }

9. IEnumerator ShuffleTasks() {

10. children.Shuffle < Task > ();

11. yield return _waitForFixedUpdate;

12. }

13. }

Metoda Shuffle na osnovu koje se miješaju zadaci je prikazana u isječku ispod.

1. public static void Shuffle < T > (this IList < T > list) {

2. int n = list.Count;

3. while (n > 1) {

4. n--;

Page 76: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

71

5. int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);

6. T value = list[k];

7. list[k] = list[n];

8. list[n] = value;

9. }

10. }

5.4.3. Implementacija dekoratora

Prvi dekorator koji ćemo implementirati je dekorator BlackboardManager. Navedeni

dekorator se odnosi na prijenos podataka, odnosno naznačava da dijete dekoratora će imati novu

instancu podataka. Prijenos podataka kroz stablo ponašanja je jedan od uobičajenih problema

koji se može riješiti na više načina. U ovom slučaju, koristimo tzv. Blackboard objekt koji se

sastoji od niza parova key, value gdje su pohranjeni podaci. Isti skup podataka se koristi u

cijelom stablu. Taj pristup je dobar ali postoji problem, ukoliko sa ključem „target“ naznačimo

referencu na glavnog igrača, onda mijenjanjem tog svojstva mogu nastati razni problemi. Iz tog

razloga koristimo BlackboardManager koji djetetu instancira novu instancu podataka koja neće

mijenjati postojeću. Na taj način, ostatak stabla će koristiti svoju referencu za ključ target, dok

će manji dio stabla promijeniti referencu i koristiti isti ključ.

Implementacije podataka, tj. Blackboard je vidljiva ispod. Kako bi mogli unutar Unity

alata definirati vrijednosti i ključeve, implementacija ograničava vrijednost podataka na:

GameObject, int, float, string tip podataka.

1. public class Blackboard {

2. public Blackboard Parent;

3. public class Data {

4. public string Name;

5. public GameObject Target;

6. public int intValue;

7. public float floatValue;

8. public string stringValue;

9. public Data(string name, GameObject target) {

10. Name = name;

11. Target = target;

12. }

13. public Data(string name, int intValue) {

14. Name = name;

15. this.intValue = intValue;

Page 77: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

72

16. }

17. public Data(string name, float floatValue) {

18. Name = name;

19. this.floatValue = floatValue;

20. }

21. public Data(string name, string stringValue) {

22. Name = name;

23. this.stringValue = stringValue;

24. }

25. }

26. public List < Data > data = new List < Data > ();

27. public void Add(Data d) {

28. data.Add(d);

29. }

30. public void Add(string name, Data d) {

31. bool dataInserted = false;

32. for (int i = 0; i < data.Count; i++) {

33. if (data[i].Name.Equals(name)) {

34. data[i] = d;

35. dataInserted = true;

36. break;

37. }

38. }

39. if (!dataInserted) Add(d);

40. }

41. public Data Get(string name) {

42. Data currentData = null;

43. foreach(Data d in data) if (d.Name.Equals(name)) currentData = d;

44. if (currentData == null && Parent != null) currentData = Parent.Get(name);

45. return currentData;

46. }

47. }

Klasa BlackboardHolder je klasa koja nasljeđuje MonoBehaviour, te u svojoj

implementaciji sadrži samo instancu Blackboard objekta.

Implementacija samog dekoratora BlackboardManager je prilično jednostavna.

Definira se nova instanca podataka tipa Blackboard, kao roditelj se postavi trenutna instanca

podataka te se djetetu proslijede podaci i pokreće se zadatak djeteta.

1. public class BlackboardManager: Decorator {

2. public override IEnumerator Run(Blackboard blackboard) {

3. Blackboard new_bb = new Blackboard();

Page 78: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

73

4. new_bb.Parent = blackboard;

5. child.Blackboard = new_bb;

6. yield return child.RunTask();

7. new_bb = null;

8. SetResult(child.GetResult());

9. yield return _waitForFixedUpdate;

10. }

11. }

Idući dekorat je Inverter. Kao što je prethodno navedeno, služi kako bi vratio suprotan

rezultat. Inverter jednostavno pokrene zadatak djeteta, te sebi postavi rezultat suprotan rezultatu

djeteta.

1. public class Inverter: Decorator {

2. public override IEnumerator Run(Blackboard blackboard) {

3. child.Blackboard = blackboard;

4. yield return child.RunTask();

5. SetResult(!child.GetResult());

6. yield return _waitForFixedUpdate;

7. }

8. }

Jedan od popularnih dekorata je Until Fail. Funkcionira tako da izvršava dijete sve dok

dijete ne vrati negativan rezultat. U tom slučaju prekida izvođenje djeteta i postavlja vrijednost

na neuspjeh. Kombinacijom Until Fail i Inverter dekoratora dobivamo dekorator Until Success

kojeg iz tog razloga nije potrebno posebno kreirati.

1. public class UntilFail: Decorator {

2. public override IEnumerator Run(Blackboard blackboard) {

3. child.Blackboard = blackboard;

4. isFinished = false;

5. while (true) {

6. yield return child.RunTask();

7. if (!child.GetResult()) break;

8. else result = true;

9. }

10. SetResult(false);

11. yield return _waitForFixedUpdate;

12. }

13. }

Page 79: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

74

5.4.4. Implementacija uvjeta

Prvi uvjet kojeg implementiramo je uvjet u kojem provjeravamo dali komponente

trebaju liječenje. Koristi se jednaka komponenta kao i kod implementacije automata, odnosno

stanja liječenja, ComponentPicker. Na osnovu te komponente provjeravamo jednostavno dali

su sve komponente izlječenje, i ukoliko uvjet nije istinit, vraćamo uspješan rezultat.

1. public class ComponentsNeedHeal: Task {

2. public ComponentPicker Picker;

3. public override IEnumerator Run(Blackboard blackboard) {

4. isFinished = false;

5. bool r = false;

6. if (!Picker.AreComponentsAtMaxHealth(GameManager.Instance.Components)) {

7. r = true;

8. }

9. SetResult(r);

10. yield return _waitForFixedUpdate;

11. }

12. }

Zatim uvjet u kojem provjeravamo energiju traženog objekta. Ovaj uvjet se koristi

najviše za provjeru energije igrača. Dohvaća se igračeva komponenta koja implementira sučelje

IDamagable te na osnovu toga provjeravamo ukoliko se igračeva energija nalazi unutar

traženog raspona.

1. public class HealthCondition: Task {

2. public float MinHealth;

3. public float MaxHealth;

4. public HealthProperties currentHealth = null;

5. public override IEnumerator Run(Blackboard blackboard) {

6. isFinished = false;

7. bool r = false;

8. GameObject target = blackboard.Get("target").Target;

9. if (currentHealth == null)

currentHealth = target.GetComponent < IDamagable > ().GetHealth();

10. if (MinHealth <= currentHealth.CurrentHealth

&& MaxHealth >= currentHealth.CurrentHealth) {

11. r = true;

12. }

13. SetResult(r);

14. yield return _waitForFixedUpdate;

15. }

16. }

Page 80: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

75

Idući uvjet je uvjet provjeravanja vlastite energije koji je identičan prethodnom uz

glavnu razliku što sa naše skupine podataka uzimamo ključ pod nazivom „owner“. Naime, ova

varijanta se mogla izbjeći korištenjem dekoratora BlackboardManager s tim da bi to uvjetovalo

kreiranjem novog zadatka koji postavlja objekt kojem provjeravamo energiju.

1. public class OwnerHealthCondition: Task {

2. public float MinHealth;

3. public float MaxHealth;

4. public HealthProperties currentHealth = null;

5. public override IEnumerator Run(Blackboard blackboard) {

6. isFinished = false;

7. bool r = false;

8. GameObject target = blackboard.Get("owner").Target;

9. if (currentHealth == null)

currentHealth = target.GetComponent < IDamagable > ().GetHealth();

10. if (MinHealth <= currentHealth.CurrentHealth

&& MaxHealth >= currentHealth.CurrentHealth) {

11. r = true;

12. }

13. SetResult(r);

14. yield return _waitForFixedUpdate;

15. }

16. }

Jedan od osnovnih uvjeta je provjeravanje udaljenosti. Uvjet vraća uspjeh ukoliko je

udaljenost manaja od maksimalne udaljenosti. Korištenjem invertera može se dobiti suprotan

rezultat. Uvjet računa udaljenost između traženog objekta, i vlasnika stabla, te vraća istinitost

ukoliko je ta udaljenost manja ili jednaka maksimalnoj.

1. public class ProximityCondition: Task {

2. public Transform Target;

3. public float MaxDistance;

4. public float CurrentDistance = 0;

5. public override IEnumerator Run(Blackboard blackboard) {

6. isFinished = false;

7. bool r = false;

8. Target = blackboard.Get("target").Target.transform;

9. GameObject owner = blackboard.Get("owner").Target;

10. if (Target != null) {

11. float distance = Vector3.Distance(Target.position, owner.transform.position);

12. CurrentDistance = distance;

Page 81: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

76

13. if (distance <= MaxDistance) r = true;

14. }

15. SetResult(r);

16. yield return _waitForFixedUpdate;

17. }

18. }

Posljednji uvjet koji je implementiran je provjeravanje ukoliko je traženi objekt unutar

kolizije. Uvjet se zasniva na OnColliderEvents komponenti koja je i prethodno korištena kod

automata. Prvo se pretplaćujemo na događaje OnTriggerEnter te OnTriggerExit i na osnovu

toga u listu objekata dodajemo objekte koji su u koliziji i izbacujemo objekte koji više nisu u

koliziji. Kada se pozove zadatak, odnosno Run metoda ovog uvjeta, jednostavno se provjeri

dali je traženi objekt unutar liste objekata koji su u koliziji.

1. public class InTriggerCollider: Task {

2. public OnColliderEvents CollisionChecker;

3. public List < GameObject > _inCollisionObjects = new List < GameObject > ();

4. void Start() {

5. CollisionChecker.OnTriggerEnterTransformEvent.AddListener(TrigerEntered);

6. CollisionChecker.OnTriggerExitTransformEvent.AddListener(TrigerExited);

7. }

8. void TrigerEntered(Transform obj) {

9. if (obj.parent != null) _inCollisionObjects.Add(obj.parent.gameObject);

10. else _inCollisionObjects.Add(obj.gameObject);

11. }

12. void TrigerExited(Transform obj) {

13. if (obj.parent != null) _inCollisionObjects.Remove(obj.parent.gameObject);

14. else _inCollisionObjects.Remove(obj.gameObject);

15. }

16. public override IEnumerator Run(Blackboard blackboard) {

17. isFinished = false;

18. bool r = false;

19. if (_inCollisionObjects.Contains(blackboard.Get("target").Target)) {

20. r = true;

21. }

22. SetResult(r);

23. yield return _waitForFixedUpdate;

24. }

25. }

Page 82: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

77

5.4.5. Implementacija akcija

Lista implementiranih akcija je nešto veća, postoje akcije: DoAttack,

DoEnableBehavior, DoEvade, DoHealing, DoPlayAnimation, DoPursue, DoStopEvade,

DoStopPursue, DoWait, MoveTo, StopMoveTo, SelectComponent. Pošto je popis zadataka

nešto veći, prikazat ćemo samo neke od njih.

Prva akcija koju implementiramo je akcija koja se jako često koristi, a to je akcija

čekanja. Akcija čekanja jednostavno pauzira zadatak na određeno vrijeme. Zahvaljujući

korištenju korutina i arhitekturi zadataka, cijelo stablo ponašanja će čekati na taj zadatak i

nastavit će tek kada vrijeme istekne.

1. public class DoWait: ActionBT {

2. public float WaitTime = 1 f;

3. protected WaitForSeconds _waitTime;

4. void Awake() {

5. _waitTime = new WaitForSeconds(WaitTime);

6. }

7. public override IEnumerator Run(Blackboard blackboard) {

8. isFinished = false;

9. yield return _waitTime;

10. isFinished = true;

11. yield return base.Run(blackboard);

12. }

13. }

Akcija MoveTo je jedna od čestih akcija u kojoj vlasniku stabla dodajemo ponašanje

dolaska na poziciju kojem dodjeljujemo traženi objekt kao ciljanu poziciju.

1. public class MoveTo: ActionBT {

2. public GameObject Target;

3. public override IEnumerator Run(Blackboard blackboard) {

4. isFinished = false;

5. GameObject target = blackboard.Get("target").Target;

6. GameObject owner = blackboard.Get("owner").Target;

7. Arrive arrive = owner.GetComponent < Arrive > ();

8. if (!arrive) arrive = owner.AddComponent < Arrive > ();

9. arrive.target = target;

10. arrive.enabled = true;

11. isFinished = true;

12. return base.Run(blackboard);

13. }

Page 83: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

78

14. }

Zatim akcija StopMoveTo dohvaća komponentu dolaska na poziciju i deaktivira ju.

1. public class StopMoveTo: ActionBT {

2. public GameObject Target;

3. public override IEnumerator Run(Blackboard blackboard) {

4. isFinished = false;

5. GameObject owner = blackboard.Get("owner").Target;

6. Arrive arrive = owner.GetComponent < Arrive > ();

7. if (arrive) {

8. arrive.enabled = false;

9. }

10. isFinished = true;

11. return base.Run(blackboard);

12. }

13. }

Zadatak napadanja definira osnovna svojstva koja predstavljaju jačinu napada i brzinu

napadanja. Dohvaća sučelje IDamagable sa traženog objekta i oduzima objektu energiju.

1. public class DoAttack: ActionBT {

2. public GameObject Target;

3. private IDamagable _targetDamagable;

4. public float Damage;

5. public float AttackFrequency;

6. protected WaitForSeconds _waitTime;

7. void Awake() {

8. _waitTime = new WaitForSeconds(AttackFrequency);

9. }

10. public override IEnumerator Run(Blackboard blackboard) {

11. isFinished = false;

12. Target = blackboard.Get("target").Target;

13. _targetDamagable = Target.GetComponent < IDamagable > ();

14. if (_targetDamagable != null) {

15. _targetDamagable.ApplyDamage(Damage);

16. yield return _waitTime;

17. SetResult(true);

18. } else {

19. SetResult(false);

20. }

21. isFinished = true;

22. yield break;

23. }

Page 84: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

79

24. }

Akcija liječenja je suprotna od napadanja, traženom objektu dodjeljuje pozitivnu štetu,

tako da se energija zapravo puni. Za razliku od napadanja liječenja se izvodi određeni

vremenski raspon, pošto neprijatelji koji lijeće komponente trebaju stati i liječiti, a tek nakon

isteka vremena, provjeravaju novu komponentu koju je potrebno liječiti.

1. public class DoHealing: ActionBT {

2. public DamagableEntity Target;

3. public float HealAmmount;

4. public float HealFrequency;

5. public float HealTimeBeforeCheck = 4 f;

6. private float _lastWrittenTime;

7. protected WaitForSeconds _waitTime;

8. void Awake() {

9. _waitTime = new WaitForSeconds(HealFrequency);

10. }

11. public override IEnumerator Run(Blackboard blackboard) {

12. isFinished = false;

13. Target = blackboard.Get("target").Target.GetComponent < DamagableEntity > ();

14. yield return Heal();

15. isFinished = true;

16. yield return base.Run(blackboard);

17. }

18. IEnumerator Heal() {

19. _lastWrittenTime = Time.time;

20. bool run = true;

21. while (run) {

22. Target.ApplyDamage(-1 * HealAmmount);

23. yield return _waitTime;

24. if (Time.time - _lastWrittenTime > HealTimeBeforeCheck) {

25. run = false;

26. }

27. }

28. yield break;

29. }

30. }

Akcija biranja komponente je zadatak koji dohvaća komponentu pomoću

ComponentPicker klase. Zatim unutar postojeće strukture podataka, dodaje i ažurira ključ

„target“ sa instancom objekta koji predstavlja odabranu komponentu. Naime može se uočiti da

je ključ target koji koristimo u mnogo akcija promijenjen, stoga ova akcija često prethodi

Page 85: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

80

korištenjem dekoratora BlackboardManager koji kreira novu strukturu podataka za određeno

dijete, na taj način unutar pod stabla ključ target predstavlja komponentu računala, dok u

drugom pod stablu isti taj ključ predstavlja objekt igrača.

1. public class SelectComponent: ActionBT {

2. public ComponentPicker Picker;

3. public DamagableEntity Component;

4. public override IEnumerator Run(Blackboard blackboard) {

5. isFinished = false;

6. Component = Picker.GetBestComponent(GameManager.Instance.Components);

7. blackboard.Add("target", new Blackboard.Data("target", Component.gameObject));

8. isFinished = true;

9. return base.Run(blackboard);

10. }

11. }

Akcija naganjanja je jako slična akciji dostizanja na poziciju. Objektu dodajemo

ponašanje naganjanjem i postavimo traženi objekt.

1. public class DoPursue: ActionBT {

2. public GameObject Target;

3. public float MaxPrediction = 2 f;

4. public override IEnumerator Run(Blackboard blackboard) {

5. isFinished = false;

6. Target = blackboard.Get("target").Target;

7. GameObject owner = blackboard.Get("owner").Target;

8. Pursue pursue = owner.GetComponent < Pursue > ();

9. if (!pursue) pursue = owner.AddComponent < Pursue > ();

10. pursue.maxPrediction = MaxPrediction;

11. pursue.weight = 2;

12. pursue.enabled = true;

13. pursue.Setup(Target);

14. isFinished = true;

15. return base.Run(blackboard);

16. }

17. }

Zadatak izbjegavanja je identičan prethodnom, u ovom slučaju dodajemo komponentu

izbjegavanja.

1. public class DoEvade: ActionBT {

2. public GameObject Target;

3. public float MaxPrediction = 2 f;

4. private Evade _evade;

Page 86: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

81

5. protected WaitForSeconds _waitTime;

6. public override IEnumerator Run(Blackboard blackboard) {

7. isFinished = false;

8. Target = blackboard.Get("target").Target;

9. GameObject owner = blackboard.Get("owner").Target;

10. _evade = owner.GetComponent < Evade > ();

11. if (!_evade) _evade = owner.AddComponent < Evade > ();

12. _evade.enabled = true;

13. _evade.maxPrediction = MaxPrediction;

14. _evade.Setup(Target);

15. yield

16. return base.Run(blackboard);

17. }

18. }

Akcija DoPlayAnimation je zapravo jednostavno rješenje korištenja postojeće

komponente EntityAnimations na modularan način. Akcija provjerava o kojem tipu animacije

se radi, te postavlja vrijednost koja može biti tipa bool ili se pak radi o okidaču.

1. public class DoPlayAnimation: ActionBT {

2. public EntityAnimations Animations;

3. public EntityAnimations.EntityAnimType AnimationType;

4. public bool UseBoolValue = false;

5. public bool UseTriggerValue = false;

6. public float floatValue = 0;

7. public bool boolValue = false;

8. public override IEnumerator Run(Blackboard blackboard) {

9. isFinished = false;

10. Animations = blackboard.Get("owner").Target.GetComponent < EntityAnimations > ();

11. if (Animations) {

12. if (AnimationType == EntityAnimations.EntityAnimType.Speed) {

13. Animations.SetAnimationMovement(floatValue);

14. } else if (AnimationType == EntityAnimations.EntityAnimType.Attack

|| AnimationType == EntityAnimations.EntityAnimType.Heal

||(AnimationType == EntityAnimations.EntityAnimType.Die && UseBoolValue)){

15. Animations.SetAnimation(AnimationType, boolValue);

16. } else if (AnimationType == EntityAnimations.EntityAnimType.Die

&& UseTriggerValue) {

17. Animations.SetAnimationTrigger(AnimationType);

18. }

19. }

20. isFinished = true;

Page 87: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

82

21. return base.Run(blackboard);

22. }

23. }

Zadatak DoStopEvade, DoStopPursue imaju gotovo identičnu implementaciju kao

StopMoveTo, dok zadatak DoEnableBehaviour ima implementaciju sličnu kao DoPursue sa

varijablom Behavior koju jednostavno uključuje, bez postavljanja traženog objekta.

Page 88: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

83

5.5. Formacije agenata

Implementacija formacija se zasniva na dvije osnovne klase, klasu FormationManager

koja kontrolira upravlja logikom formacije bez obzira na tip formacije i klasu FormaionPattern

koja definira oblik formacije.

5.5.1. Upravljanje formacijom

Klasa koja upravlja logikom formacije je klasa FormationManager. Njena

implementacija obuhvaća odgovornosti: dodavanje lika unutar formacije, brisanje lika iz

formacije, ažuriranje pozicije unutar formacije. Kako ova komponenta funkcionirala, potrebno

ju je koristiti zajedno sa nekim od tipova formacije, odnosno klase tipa FormationPattern.

Također klasa sadrži i pohranjene pozicije formacije unutar varijable slotAssignments.

Prije implementacije formacije implementiramo strukturu pohrane pozicija. Struktura

se sastoji od indeksa pozicije i reference na objekt lika.

1. public class SlotAssignment {

2. public int slotIndex;

3. public GameObject character;

4. public SlotAssignment() {

5. slotIndex = -1;

6. character = null;

7. }

8. }

Zatim glavna implementacija se sastoji od metoda AddCharacter u kojoj dodjeljujemo

novog lika formaciji, te RemoveCharacter koja radi suprotno. Metoda UpdateSlots je metoda

unutar koje ažuriraju pozicije svakog od objekata tako da prate oblik formacije. Metoda se

poziva iz neke klase iz više razine, poput klase koja predstavlja sami objekt formacije, ili se pak

može koristiti u nekom od stanja formacije.

1. public class FormationManager: MonoBehaviour {

2. public FormationPattern pattern;

3. private List < SlotAssignment > slotAssignments;

4. private Location driftOffset;

5. void Awake() {

6. slotAssignments = new List < SlotAssignment > ();

7. }

8. public bool AddCharacter(GameObject character) {

9. int occupiedSlots = slotAssignments.Count;

Page 89: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

84

10. if (!pattern.SupportsSlots(occupiedSlots + 1)) return false;

11. SlotAssignment sa = new SlotAssignment();

12. sa.character = character;

13. slotAssignments.Add(sa);

14. UpdateSlotAssignmentsWithCosts();

15. return true;

16. }

17. public void RemoveCharacter(GameObject agent) {

18. int index = slotAssignments.FindIndex(x => x.character.Equals(agent));

19. slotAssignments.RemoveAt(index);

20. UpdateSlotAssignmentsWithCosts();

21. }

22. public void UpdateSlots() {

23. GameObject leader = pattern.Leader;

24. Vector3 anchor = leader.transform.position;

25. Vector3 slotPos;

26. Quaternion rotation;

27. rotation = leader.transform.rotation;

28. foreach(SlotAssignment sa in slotAssignments) {

29. Vector3 relPos;

30. slotPos = pattern.GetSlotLocation(sa.slotIndex);

31. relPos = anchor + leader.transform.TransformDirection(slotPos);

32. Location charDrift = new Location(relPos, rotation);

33. FormationEntity character = sa.character.GetComponent < FormationEntity > ();

34. character.SetTarget(charDrift);

35. }

36. }

37. }

Obje metode, za brisanje i dodavanje lika, zasnivaju se na metodi

UpdateSlotAssignmentsWithCosts. Naime, jedan od najboljih prednosti formacija je

pozicioniranje različitih igrača na određene pozicije. Npr. ukoliko želimo napraviti formaciju u

obliku linije, na samom početku formacije možemo postaviti likove koji imaju veću energiju i

koji su više otporni na udarce. Kako bi to postigli, implementiramo algoritam cijene pozicija.

Svaka pozicija u formaciji ima određenu cijenu. Cijena se može definirati na različite načine i

ovisi isključivo o samom tipu formacije.

Metoda UpdateSlotAssignmentsWithCosts implementira algoritam cijene tako da

pozicije popunja na specifičan način. Prvo se popuni lista likova i njihovih cijena za svaku

poziciju u formaciji. Zatim se liste pozicija za svakog lika sortiraju, tako da je ona pozicija sa

Page 90: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

85

najmanjom cijenom na vrhu. Nakon toga se vrši dodjela likova samoj poziciji na način da, lika

dodjeljujemo prvoj slobodnoj poziciji prema prethodno sortiranoj listi.

Na taj način u formaciju ubacujemo agente sa najboljom mogućom raspodijelim s

obzirom na definirane cijene pojedine pozicije.

1. public int SlotsSize() {

2. return slotAssignments.Count;

3. }

4. public class CostAndSlot {

5. public int cost;

6. public int slot;

7. }

8. public class CharacterAndSlots {

9. public FormationEntity character;

10. public float assignmentEase;

11. public List < CostAndSlot > costAndSlots;

12. }

13. public List < CharacterAndSlots > charactersData;

14. public void UpdateSlotAssignmentsWithCosts() {

15. charactersData = new List < CharacterAndSlots > ();

16. // Compile the character data

17. for (int i = 0; i < slotAssignments.Count; i++) {

18. CharacterAndSlots datum = new CharacterAndSlots();

19. datum.costAndSlots = new List < CostAndSlot > ();

20. datum.character = slotAssignments[i].character.GetComponent < FormationEntity > ();

21. // Add each valid slot to it

22. for (int slot = 0; slot < pattern.NumOfSlots; slot++) {

23. // Get the cost of the slot

24. int cost = 0;

25. cost = pattern.GetSlotCost(slot, datum.character);

26. // Make sure the slot is valid

27. if (cost >= 1000) continue;

28. // Store the slot information

29. CostAndSlot slotDatum = new CostAndSlot();

30. slotDatum.slot = slot;

31. slotDatum.cost = cost;

32. datum.costAndSlots.Add(slotDatum);

33. datum.assignmentEase = 1 / (1 + cost);

34. }

35. charactersData.Add(datum);

Page 91: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

86

36. }

37. // Keep track of which slots we have filled

38. bool[] filledSlots = new bool[pattern.NumOfSlots];

39. for (int i = 0; i < filledSlots.Length; i++) filledSlots[i] = false;

40. slotAssignments.Clear();

41. if (charactersData.Count > 1) charactersData.Sort(delegate(CharacterAndSlots c1, Charac

terAndSlots c2) {

42. return c1.assignmentEase.CompareTo(c2.assignmentEase);

43. });

44. foreach(CharacterAndSlots characterDatum in charactersData) {

45. characterDatum.costAndSlots.Sort(delegate(CostAndSlot c1, CostAndSlot c2) {

46. return c1.cost.CompareTo(c2.cost);

47. });

48. bool slotFilled = false;

49. foreach(CostAndSlot slot in characterDatum.costAndSlots) {

50. if (!filledSlots[slot.slot]) {

51. SlotAssignment assigment = new SlotAssignment();

52. assigment.character = characterDatum.character.gameObject;

53. assigment.slotIndex = slot.slot;

54. slotAssignments.Add(assigment);

55. filledSlots[slot.slot] = true;

56. slotFilled = true;

57. break;

58. }

59. }

60. }

61. driftOffset = pattern.GetDriftOffset(slotAssignments);

62. }

5.5.2. Vrste formacija

Osnovna klasa za tipove formacija je klasa FormationPattern. Prvi dio klase definira

broj pozicija, postavlja virtualne metode koje treba naslijediti konkretna formacija. Unutar

GetSlotLocation se zapravo nalazi implementacija koja definira oblik formacije.

1. public class FormationPattern: MonoBehaviour {

2. public int NumOfSlots = 3;

3. public GameObject Leader;

4. void Start() {

5. if (Leader == null) Leader = transform.gameObject;

6. }

7. public virtual Vector3 GetSlotLocation(int slotIndex) {

Page 92: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

87

8. return Vector3.zero;

9. }

10. public bool SupportsSlots(int slotCount) {

11. return slotCount <= NumOfSlots;

12. }

13. public virtual Location GetDriftOffset(List < SlotAssignment > slotAssignments) {

14. Location location = new Location();

15. location.position = Leader.transform.position;

16. location.rotation = Leader.transform.rotation;

17. return location;

18. }

19. }

U drugom dijelu klase nalazi se implementacija cijena pozicija. Postoji niz instanci klase

CharacterTypeAndCost gdje definiramo za svaku vrstu lika cijenu za poziciju. Naime to je

jedna od jednostavnijih varijanti iskorištavanja cijena pozicija. Likove na pozicije smještamo s

obzirom na njihov tip. Druge mogućnosti mogu obuhvaćati prilagodbu cijene s obzirom na

poziciju lika, s obzirom na energiju, ili pak s obzirom na neki drugi faktor. U ovom slučaju

sasvim je dovoljna raspodjela pozicija prema tipu entiteta neprijatelja.

Implementacija se sastoji uglavnom od glavne metode u kojoj se dohvaća cijena

pozicije. Metoda Reset se odnosi na funkcionalnost same Unity komponente, te se izvršava

prilikom dodavanja komponente na neki objekt. U metodi Reset kreiramo listu svih tipova

neprijatelja i pozicije sa zadanim vrijednostima koje se mogu popuniti.

1. // Slot Cost

2. public class CharacterTypeAndCost {

3. public FormationEntity.FormationEntityType CharacterType;

4. public int[] Costs;

5. }

6. public CharacterTypeAndCost[] CharactersWithSlotCosts;

7. public int CostLimit;

8. void Reset() {

9. FormationEntity.FormationEntityType[] types = (FormationEntity.FormationEntityType[])

Enum.GetValues(typeof(FormationEntity.FormationEntityType));

10. CharactersWithSlotCosts = new CharacterTypeAndCost[types.Length];

11. for (int i = 0; i < types.Length; i++) {

12. CharactersWithSlotCosts[i] = new CharacterTypeAndCost();

13. CharactersWithSlotCosts[i].CharacterType = types[i];

14. CharactersWithSlotCosts[i].Costs = new int[NumOfSlots];

15. for (int j = 0; j < NumOfSlots; j++) {

Page 93: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

88

16. CharactersWithSlotCosts[i].Costs[j] = 0;

17. }

18. }

19. }

20. public virtual int GetSlotCost(int slot, FormationEntity character) {

21. int cost = int.MaxValue;

22. foreach(CharacterTypeAndCost characterWithCost in CharactersWithSlotCosts) {

23. if (characterWithCost.CharacterType.Equals(character.Type)) {

24. if (characterWithCost.Costs.Length > slot)

cost = characterWithCost.Costs[slot];

25. break;

26. }

27. }

28. return cost;

29. }

30. // If Even One Slot is avaiable for this

31. public bool IsCharacterOverLimit(FormationEntity character) {

32. bool isOverLimit = true;

33. foreach(CharacterTypeAndCost characterWithCost in CharactersWithSlotCosts) {

34. if (characterWithCost.CharacterType.Equals(character.Type)) {

35. for (int i = 0; i < characterWithCost.Costs.Length; i++) {

36. if (characterWithCost.Costs[i] < CostLimit) {

37. isOverLimit = false;

38. break;

39. }

40. }

41. break;

42. }

43. }

44. return isOverLimit;

45. }

Na slici ispod je moguće vidjeti Unity komponentu u kojoj je moguće definirati cijenu

određenog neprijatelja za svaku poziciju, elementi Element 0 do Element 5 su zapravo oznake

za pozicije.

Page 94: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

89

Slika 5-3: Komponenta kružne formacije

Nakon što imamo kostur, potrebno je samo implementirati oblik formacije. U ovom

radu, dovoljan nam je kružni tip formacije. Implementacija implementira virtualne metode

GetSlotLocation te GetDriftOffset.

1. public class DefensiveCirclePattern: FormationPattern {

2. public float CharacterRadius;

3. public override Vector3 GetSlotLocation(int slotIndex) {

4. float angleAroundCircle = 0;

5. angleAroundCircle = ((float) slotIndex / NumOfSlots) * Mathf.PI * 2;

6. float radius = CharacterRadius / Mathf.Sin(Mathf.PI / NumOfSlots);

7. Location location = new Location();

8. location.position.x = radius * Mathf.Cos(angleAroundCircle);

9. location.position.z = radius * Mathf.Sin(angleAroundCircle);

10. return location.position;

11. }

12. public override Location GetDriftOffset(List < SlotAssignment > slotAssignments) {

13. Location center = new Location();

14. for (int i = 0; i < slotAssignments.Count; i++) {

15. Vector3 location = GetSlotLocation(i);

16. center.position += location;

17. }

18. float numOfSlots = slotAssignments.Count;

19. center.position /= numOfSlots;

20. return center;

Page 95: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

90

21. }

22. }

Jedna od dodatnih klasa koja nam služi kao pomoćna klasa za upravljanjem svim

formacijama je klasa FormationsManager (množina). Kako neprijatelje kreiramo dinamički,

potrebno je dinamički i dohvatiti formaciju za agenta. Stoga nam klasa FormationsManager

služi za definiranje tipova formacija. Zbog veličine koda, kod ispod pokazuje pseudo javnih

metoda i varijabli koje se koriste kako bi ukazale na osnovne funkcije te klase koje je

jednostavno implementirati. DefinedPatterns se sastoji od niza mogućih formacija, dok

varijabla Formations pohranjuje aktivne formacije u sceni, i redom dodjeljuje neprijatelje u

prvu slobodnu formaciju.

1. public class FormationsManager: Singleton < FormationsManager > {

2. public PatternProperties[] DefinedPatterns;

3. public List < FormationsProperties > Formations;

4. FormationManager GetFormation(PatternType formationPatternType,

FormationEntity character);

5. FormationManager GetClosestFormationManager(FormationEntity character);

6. void AddToFormation(FormationManager formation, FormationEntity character);

7. void RemoveFromFormation(FormationManager formation, FormationEntity character);

8. }

Page 96: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

91

5.6. Slaganje neprijatelja unutar Unity alata

Kako bi složili funkcionalne neprijatelje, prvo moramo implementirati niz klasa. Klase

od kojih se sastoje neprijatelji obuhvaćaju korištenje životne energije, zatim korištenje događaja

vezanih za stanje životne energije, metode za smanjivanje energije. Također ukoliko se radi o

neprijatelju koji se dodaje u formacije, potrebno je implementirati dohvaćanje formacije,

dodavanje u formaciju. Zatim komponente računala također moraju koristiti vlastitu

implementaciju.

Klase koje su povezane za entitete u igri su:

EnemyEntity

FormationEntity

DamagableEntity

BTFlybotEntity

IDamagable

IEntity

IFormationEntity

Na slici ispod je prikazan UML dijagram navedenih klasa.

Page 97: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

92

Slika 5-4: UML dijagram klasa neprijatelja

5.6.1. Kreiranje osnovnih sučelja

Nakon što posjedujemo sve potrebne klase za umjetnu inteligenciju, kreirat ćemo i

osnovne klase koje predstavljaju svojstva neprijatelja.

Svaki neprijatelj će implementirati sučelje IEntity. IEntity sučelje se sastoji od samo

jedne metode, metoda Die.

1. public interface IEntity {

2. void Die();

3. }

Zatim svaki neprijatelj implementira sučelje IDamagable. S tim definiramo određena

svojstva neprijatelja koja obuhvaćaju korištenje HealthProperties klase za životnu energiju,

zatim metode ApplyDamage koji utječe na promjenu te energije, i OnHealthChanged metoda

koja se poziva prilikom promjene energije. HealthProperties je klasa koja se sastoji od

maksimalne energije i trenutne energije.

1. public interface IDamagable {

2. /// <summary>

3. /// Method to Apply Damage On Entity

4. /// </summary>

5. /// <param name="damage"></param>

6. void ApplyDamage(float damage);

7. /// <summary>

8. /// Method called when entity health is changed

9. /// </summary>

10. void OnHealthChanged();

11. HealthProperties GetHealth();

12. }

Iduće sučelje koje implementiramo je sučelje za neprijatelje koji podržavaju formacije.

Sučelje se sastoji od metoda u kojima dohvaćamo formaciju za neprijatelja, zatim metoda u

kojoj dodajemo formaciji neprijatelja, zatim jedna od bitnijih metoda SetTarget koju poziva

formacija te postavlja novu lokaciju, te UpdateLocationObject metoda koja primjenjuje željenu

lokaciju na nekom praznom objektu koji služi kao traženi objekt za neprijatelje koji su u

formaciji.

Page 98: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

93

1. public interface IFormationEntity {

2. FormationManager GetFormation();

3. void AddToFormation();

4. void RemoveFromFormation();

5. void UpdateLocationObject();

6. void SetTarget(Location location);

7. float DistanceFromLocation();

8. }

5.6.2. Kreiranje osnovne klase neprijatelja

Nakon kreiranja sučelja, potrebno ih je implementirati u konkretne klase. Prema

dijagramu klasa (vidi Slika 5-4) vrši se implementacija klasa. Zbog količine koda prikazat ćemo

implementaciju klase koja obuhvaća najviše sučelja a to je klasa EnemyEntity. Ostale klase su

jako slične, dok je klasa DamagableEntity gotovo identična.

Kreiranje samih neprijatelja u Unity alatu podrazumijeva korištenje već prethodno

definiranih animacija, modela, grafičkog sučelja i ostalih komponenti koje nisu vezani za

umjetnu inteligenciju.

EnemyEntity klasa sadrži već prethodno poznate varijable, a to je varijabla Health

vezana za životnu energiju i varijabla CanDie koja definira dali neprijatelj može umrijeti. Na

samom početku, u Start metodi koja se poziva samo jednom nakon inicijalizacije objekta te

prije uzastopnog pozivanja metode Update, vrši se dodavanje trenutnog objekta u statičku listu

neprijatelja koja je pohranjena u GameManager klasi. Ta ista lista se ažurira i neprijatelj se

briše tijekom uništenja u OnDestroy metodi, također metoda koja se automatski poziva.

EnemyEntity implementira već spomenuta sučelja koja obuhvaćaju metode Die, AppyDamage,

GetHealth, te OnHealthChanged.

1. public class EnemyEntity: MonoBehaviour, IDamagable, IEntity {

2. public HealthProperties Health;

3. public bool CanDie = true;

4. public float DestroyDelay = 2 f;

5. public CustomUnityEvent < float, float > OnHealthChange = new CustomUnityEvent < float,

float > ();

6. public HealthPercentangeEvent OnHealthChangePercentange = new HealthPercentangeEvent();

7. public CustomUnityEvent OnFullHealth = new CustomUnityEvent();

8. public CustomUnityEvent OnEmptyHealth = new CustomUnityEvent();

9. protected virtual void Awake() {

10. Health.Initialize();

Page 99: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

94

11. }

12. protected virtual void Start() {

13. GameManager.AddEnemy(gameObject);

14. OnHealthChangePercentange.Invoke(Health.CurrentHealth / Health.MaxHealth);

15. }

16. public void ApplyDamage(float damage) {

17. Health.ApplyDamage(damage);

18. if (OnHealthChange != null) {

19. OnHealthChanged();

20. OnHealthChange.Invoke(Health.CurrentHealth, Health.MaxHealth);

21. OnHealthChangePercentange.Invoke(Health.CurrentHealth / Health.MaxHealth);

22. }

23. if (Health.IsFullHealth() && OnFullHealth != null) OnFullHealth.Invoke();

24. if (!Health.IsAlive() && OnEmptyHealth != null) OnEmptyHealth.Invoke();

25. }

26. public void Die() {

27. StartCoroutine(OnDie());

28. }

29. protected virtual IEnumerator OnDie() {

30. if (CanDie) {

31. GameManager.OnEnemyDied();

32. this.GetComponent < Collider > ().enabled = false;

33. if (this.GetComponent < EntityAnimations > ()) {

34. this.GetComponent < EntityAnimations > ().SetAnimation(EntityAnimations.Ent

ityAnimType.Die, true);

35. }

36. yield return new WaitForSeconds(DestroyDelay);

37. Destroy(gameObject);

38. }

39. yield break;

40. }

41. void OnDestroy() {

42. GameManager.RemoveEnemy(gameObject);

43. }

44. public virtual void OnHealthChanged() {}

45. public HealthProperties GetHealth() {

46. return Health;

47. }

48. }

Page 100: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

95

5.6.3. Izgled osnovne strukture neprijatelja

Neprijatelji su strukturirani pomoću objekta igre, tzv. „GameObject“. Objekti u Unity

alatu se sastoje od niza komponenti, jedna od komponenti koje svaki GameObject posjeduje je

komponenta Transform koja predstavlja veličinu, lokaciju i rotaciju u prostoru.

Glavni objekt (roditelj) sadrži glavne komponente koje predstavljaju neprijatelja. Taj

objekt sadrži niz djece koji predstavljaju povezane objekte kako bi glavni objekt ispravno

funkcionirao. Pošto se radi o 3D modelu, uvijek će imati dvoje objekata od kojih jedan

predstavlja izgled (mesh), obično sa jednakim nazivom kao i naziv neprijatelja, a drugi

strukturu modela, često sa nazivom Armature. Ostali objekti koje sadrži glavni objekt može biti

objekt stanja automata, objekt stabla ponašanja, objekt u kojem je pohranjen vizualni izgled

životne energije (HealthCanvas), objekt sa prikazom naziva stanja (CanvasTop), te objekt koji

sadrži detektor napada ili liječenja (Attack).

Struktura neprijatelja Healerbot i Flybot je prikazana u hijerarhijskom pogledu u Unity

alatu na slici ispod.

Slika 5-5: Struktura neprijatelja Flybot Attacker i HealerBot

5.6.4. Kreiranje neprijatelja „Healerbot“

Nakon implementacije EnemyEntity klase možemo kreirati prvi tip neprijatelja, a to je

HealerBot neprijatelji koji lijeće komponente. Izgled same komponente u Unitiju je prikazan

na slici ispod. Kod pokretanja projekta trenutna životna energija se automatski postavi na

maksimalnu.

Page 101: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

96

Slika 5-6: Komponenta Enemy Entity na Healerbot neprijatelju

Animator komponenta je komponenta iz Unity sustava pomoću koje su definirane

animacije modela. Osim te komponente, postavljene su komponente Rigidbody za fiziku te

CapsuleCollider (prikazano zelenom bojom na Slika 5-7) za kolizije.

Vizualni izgled namještenog neprijatelja je moguće vidjeti na slici ispod.

Page 102: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

97

Slika 5-7: Neprijatelj Healerbot

Stanja Healerbot neprijatelja su definirana i prikazana na Slika 5-8. Vidi se kako je

uključeno početno stanje State Arrive To Component. ComponentPicker je komponenta koja je

već prethodno spomenuta više puta, te je zaslužna za biranje komponente u igri za liječenje.

UIState komponenta je zaslužna za upravljanje vizualnim prikazom stanja automata.

Page 103: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

98

Slika 5-8: Stanja Healerbot neprijatelja

5.6.5. Kreiranje neprijatelja „Fighterbot“

Neprijatelj Fighterbot je kreiran na identičan način kao što je kreiran i prethodni

neprijatelj Healerbot, izgled neprijatelja je vidljiv na Slika 5-9.

Page 104: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

99

Slika 5-9: Neprijatelj Fighterbot

Na Slika 5-10 vidimo implementirana stanja samog agenta koja su opisana u poglavlju 4.2.1.

Slika 5-10: Stanja Fighterbot neprijatelja

5.6.6. Kreiranje neprijatelja „Formation Fighterbot“

Formacije se sastoje od same formacije koja sadrži više neprijatelja, u ovom slučaju do

6 neprijatelja. Izgled objekta formacije prikazan je na Slika 5-11. Cijene pozicija su postavljene

za FighterBot neprijatelja na 0. Komponenta Character Formation Control poziva metodu

formacije UpdateSlots na osnovu koje se ažuriraju lokacije neprijatelja unutar formacije, koju

pomoću ponašanja dolaska na poziciju prate tu lokaciju.

Page 105: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

100

Slika 5-11: Kružna formacija za Fighterbot neprijatelje

Formacija posjeduje i vlastita stanja, prethodno spomenuta u poglavlju 4.2.2. Stanja su

prikazana na Slika 5-12.

Slika 5-12: Stanja kružne formacije

Page 106: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

101

Stanja samog neprijatelja Fighterbot unutar formacije prikazana su na Slika 5-13.

Slika 5-13: Stanja neprijatelja Fighterbot unutar kružne formacije

5.6.7. Kreiranje neprijatelja „Flybot Healer“

Flybot Healer neprijatelj je izrađen pomoću stabla ponašanja. Hijerarhija strukture je

prikazana na slici ispod.

Slika 5-14: Struktura i izgled Flybot Healer-a

Slika 5-15 prikazuje komponente na glavnom objektu neprijatelja. Entitet koji označava

neprijatelja je komponenta BTFlyBot koja sadrži referencu na BehaviourTree komponentu koja

se također nalazi na istom objektu. BehaviourTree komponenta sadrži referencu

BlackboardHolder komponente u kojoj se mogu direktno unijeti početni podaci kojima

pristupamo putem ključa.

Page 107: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

102

Slika 5-15: Komponente vezane za stablo ponašanja

Slika 5-16 prikazuje korijen stabla ponašanja, na Slika 5-14 objekt je označen plavom

bojom. Korijen stabla je zapravo selektor koji se sastoji od troje djece. Prvo dijete je RunAway

dijete.

Slika 5-16: Korijen stabla ponašanja za Flybot Healer neprijatelja

RunAway je prikazano na Slika 5-17. Sastoji se od sekvence koja ima 4 različita djeteta.

Prvo se provjerava dali je udaljenost traženog objekta ispod 36 m, te ukoliko je, sekvenca

nastavlja na zadatak izbjegavanja, koji se isključuje nakon zadatka čekanja.

Page 108: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

103

Slika 5-17: Zadaci pod stabla „RunAway“

Ostatak komponenti je jednostavno složen prema Slika 4-7.

5.6.8. Kreiranje neprijatelja „Flybot Attacker“

Flybot Attacker neprijatelj je također izrađen pomoću stabla ponašanja. Sastoji se od

jednakih komponenti kao i Flybot Healer. Jedina razlika je u strukturi stabla ponašanja i

njegovim zadacima što je vidljivo na Slika 5-19. Detalji stabla ponašanja prikazani su u

poglavlju 4.2.3 te na Slika 4-8.

Slika 5-18: Izgled Flybot Attacker neprijatelja

Page 109: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

104

Slika 5-19: Struktura i korijen stabla ponašanja za neprijatelja Flybot Attacker

Page 110: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

105

5.7. Dodatne komponente

Od dodatnih komponenti koje se koriste u projektu su:

Game Manager

Wave Spawner

Registered Events Manager

Transition To

Component Picker

On Collider Events

Shooting Ability

Bullet

UIState

CameraZoom

Entity Animations

State Holder

Komponenta Game Manager je singleton klasa koja pohranjuje glavne parametre igre i

na nju se referenciraju neka od ponašanja. Tako u navedenoj komponenti se nalazi lista svih

neprijatelja, zatim referenca na objekt igrača i lista komponenti.

Wave Spawner je komponenta zaslužna za stvaranje valova neprijatelja, unutar

komponente se može definirati broj valova, zatim broj neprijatelja u određenom valu i njihove

početne pozicije.

Registered Events Manager je singleton klasa koja ima sličnu ulogu kao i

GameManager. U njoj su pohranjeni glavni događaji poput OnMatchStart, na koje se mogu

preplatiti određeni objekti i izvršiti pozive prigodnih metoda.

On Collider Events je klasa koju koristimo na raznim mjestima. Pohranjuje više

različitih događaja među kojima su događaji OnTriggerEnter i OnTriggerExit koji se odnose

na to da je objekt koji posjeduje tu klasu, ušao unutar tzv. collidera. Collider je komponenta

koja omogućuje objektu u igri da poprimi fizičke osobine, odnosno kolizije.

ShootingAbility se koristi na objektu glavnog igrača, i omogućuje pucanje. Komponenta

omogućuje dodjelu objekta koji predstavlja metak, zatim poziciju od koje metak izlazi, efekt

pucanja, brzina metka, količina metaka, te brzina pucanja.

Page 111: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

106

Bullet se koristi na objektu koji predstavlja metak. Klasa provjerava dali je metak ušao

u koliziju sa drugim objektom, te ukoliko je taj objekt jedan od neprijatelja, oduzima mu snagu.

UIState je komponenta koja se koristi na agentima sa stanjima. Omogućuje korištenje

grafičkog sučelja za stanje.

StateHolder je komponenta koja predstavlja objekt sa stanjima koji su implementirani

pomoću automata. Preko tog objekta druge komponente mogu jednostavno pristupiti

aktivnom stanju i jednostavno ga uključiti ili isključiti. Tu funkcionalnost iskorištavaju

formacije kako bi kontrolirale agente koji se nalaze unutar formacije.

CameraZoom je komponenta koja omogućuje zumiranje kamere.

Entity Animations omogućuje jednostavan način aktivacije određene animacije,

pozivom jedne od tri metode. Postoji metoda koja postavlja animaciju brzine hodanja, zatim

metoda koja postavlja vrijednost istinitosti za animacije liječenja, napadanja, te za animaciju

smrti.

Page 112: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

107

6. Testiranje

U svrhe testiranja, kreirana je igra sa prethodnim implementacijama koja obuhvaća 7

različitih valova napada. Kontrole igre su jednostavne, kao što je već spomenuto, pomoću miša

se igrač okreće u željenom smjeru, dok pomoću strelica na tipkovnici ili tipki W,A,S,D se igrač

pokreće. U tablici ispod nalazi se popis neprijatelja unutar svakog vala.

Broj vala Neprijatelj Broj neprijatelja Vremenski raspon stvaranja

1 Healerbot 4 1.6

2 Healerbot

6 1 Fighterbot

3 Formation Fighterbot 6 1.2

4 Formation Fighterbot

8 1 Healerbot

5 Flybot Healer 8 1.8

6 Flybot Attacker 7 1.8

7 Flybot Healer

12 1.8 Flybot Attacker

Tablica 2: Neprijatelji kroz valove u igri

U igri su implementirani i gumbovi za ponavljanje trenutne scene, zatim gumb za izlaz,

te gumb za skrivanje i otkrivanje vizualnog prikaza stanja neprijatelja koji su kreirani pomoću

automata. Također u na samom vrhu oko sredine ekrana, postoji prikaz ukupnog i poraženog

broja neprijatelja, te brojač vala. U svrhe testiranja umjetne inteligencije, igrač ne može

umrijeti, te igra nema stanje pobjede i gubitka. Početna scena igre prikazana je na slici ispod.

Page 113: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

108

Slika 6-1: Početna scena igre

Nakon što igrač izađe iz svog prostora, vrata se zatvaraju i počinje stvaranje neprijatelja.

Na slici ispod je moguće vidjeti prve neprijatelje, odnosno Healerbot neprijatelje sa svojim

stanjima. U samom početku stvaraju se, i započinju sa stanjem „Arrive to component“ gdje

dostižu na određenu komponentu i započinju stanje liječenja. U ovom slučaju, sve komponente

imaju punu energiju, te im nije potrebno liječenje, ali unatoč tome Healerbot je prisiljen otići

jednoj od komponenti i pokušati je liječiti.

Slika 6-2: Početak stvaranja neprijatelja

Page 114: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

109

Na slici ispod je prikazano i stanje smrti Healerbot neprijatelja, nakon čega neprijatelj

nestaje sa mape.

Slika 6-3: Stanje smrti Healerbot neprijatelja

Nakon što su poraženi svi neprijatelji, započinje idući val neprijatelja u kojem se pojavljuje

neprijatelj Fighterbot.

Slika 6-4: Neprijatelj Fighterbot

U trećem valu se pojavljuju neprijatelji sa formacijama. Na slici ispod moguće je vidjeti izgled

neprijatelja kada proganjaju glavnog igrača.

Page 115: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

110

Slika 6-5: Kružna formacija Fighterbot neprijatelja

Formacija ide do neprijatelja i zajednički napada tako da smanjiva radijus kada se igrač nalazi

u središtu formacije.

Slika 6-6: Opkoljavanje i napadanje glavnog igrača sa isljučenim prikazom stanja

Peti val donosi neprijatelja Flybot Healera koji osim liječenja komponente, pokušava

se udaljiti maksimalno od igrača. Na Slika 6-7 moguće je vidjeti ponašanje neprijatelja, neki

bježe od igrača, dok neki liječe komponente.

Page 116: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

111

Slika 6-7: Ponašanje Flybot Healer neprijatelja

Posljednji neprijatelj koji se pojavljuje u šestom valu je Flybot Attacker koji napada

igrača i netom nakon toga odmah bježi. Za razliku od Fighterbot neprijatelja, znatno je brži.

Na Slika 6-8 moguće je vidjeti kako u samom početku svi Flybot Attacker neprijatelji

su počeli hvatati igrača kako bi ga napali. Slika 6-9 pak pokazuje stanje nakon toga, gdje neki

od neprijatelja pokušavaju pobjeći, tako da ih igrač ne može jednostavno uhvatiti.

Slika 6-8: Flybot Attacker neprijatelji pokušavaju uhvatiti igrača

Page 117: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

112

Slika 6-9: Ponašanje Flybot Attacker neprijatelja

Page 118: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

113

7. Zaključak

U ovom radu upoznali smo se sa umjetnom inteligencijom u video igrama. Agenti u

video igrama se očituju najviše u području umjetne inteligencije gdje se ponašanje određenih

entiteta u igri radi prema pristupu odozdo prema gore, odnosno po pristupu gdje entiteti

samostalno dohvaćaju podatke iz okoline bez da njima upravlja druga klasa.

Video igre su industrija koja se brzo razvija i unaprjeđuje, te umjetna inteligencija kao

dio igre igra veliku ulogu. Povećanje resursa igrama omogućuje korištenje raznih novih ili

kompleksnijih tehnika među kojima su neuronske mreže jedna od njih. Iako se tehnike

razvijaju, osnove kod izrade umjetne inteligencije nisu znatno promijenjene u posljednjih 15

godina. Čak u samom početku igre poput Pacmana su koristile automate za stanja. Igra Halo 2

2004. godine je pokazala primjenu stabla ponašanja, od tada su mnogi programeri počeli

slijediti njihov primjer. Zahvaljujući tome, trenutno, stablo ponašanja je postalo dovoljno

popularno da ga koristi velik broj igara koje posjeduju umjetnu inteligenciju.

Na samom primjeru implementacije igre može se uočiti kompleksnost izrade umjetne

inteligencije za igre. Tehnika pomoću automata je jednostavnija za implementirati u samom

početku, ali ukoliko želimo nešto različito ponašanje, obično zahtjeva programiranje novog

stanja. Stabla ponašanja su nešto kompleksnija za implementirati zbog toga što koriste velik niz

akcija i uvjeta. Jednom kada posjedujemo sve uvjete i akcije, zadatak slaganja inteligencije

može ispuniti i dizajner ili neka druga osoba koja ne mora znati programirati, pogotovo ukoliko

programer pripremi grafičko sučelje za kreiranje stabla.

Praktični dio ovog rada ukazuje na važnost umjetne inteligencije u igrama. Loša umjetna

inteligencija se lako primijeti i igra znatno gubi na vrijednosti. Dobra umjetna inteligencija

pridonosi izazovnijom igrom i nudi puno veću zabavu, stoga je jako bitno dobro isplanirati i

proučiti to područje prije same implementacije umjetne inteligencije ukoliko je ona potrebna u

igri.

Page 119: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

114

8. Literatura

[1] Chapple, C. (2014, April). The top 16 game engines for 2014.

[2] DeLoura, M. (2001). Game Programming Gems 2. Game Programming Gems 2, 220–227.

[3] Entertainment Software Assotiation. (2013). Essential Facts About the Computer and Video

Game Industry 2013.

[4] Entertainment Software Assotiation. (2016). Essential Facts About the Computer and Video

Game Industry. Preuzeto 20.08.2016. sa http://essentialfacts.theesa.com/Essential-Facts-

2016.pdf

[5] J. Champandard, A. (2007). Top 10 Most Influential AI Games.

[6] Madhav, S. (2014). Game Programming Algorithms and Techniques. Addison Wesley.

[7] McShaffry, M., & Graham, D. (2013). Game Coding Complete. (M. Justak, Ed.) (Fourth

Edi). Course Technology PTR.

[8] Millington, I., & Funge, J. (2009). Artificial Intelligence for Games, Second Edition.

Representations. http://doi.org/10.1017/S0263574700004070

[9] Palacios, J. (2016). Unity 5.x Game AI Programming.

[10] Rabin, S. (2002). AI Game Programming Wisdom. (S. Rabin, Ed.).

[11] Reynolds, C. W. (2011). Steering Behaviors For Autonomous Characters. Preuzeto

22.08.2016. sa http://www.cs.uu.nl/docs/vakken/mcrs/papers/8.pdf

[12] Unity Technologies. (2016). Unity. Preuzeto sa http://unity3d.com/

Page 120: Agentni pristup u računalnim igramaumjetnu inteligenciju za igre. Cilj akademskog istraživanja je orijentiran na rezultat, način na koji je problem riješen, dok cilj programera

115

9. Prilozi

U ovom poglavlju nalaze se poveznice vezane za praktični dio rada. Izvorni kod igre

kreiran je pomoću Unity 5.3.6 alata. Projekt je potrebno izvesti iz „rar“ datoteke, koji se otvori

pomoću Unity alata gdje se bira korijenska mapa. Zatim, u Unitiju je potrebno otvoriti scenu

pod nazivom „Gameplay“.

[1] Izvorni kod igre dostupan na:

https://dl.dropboxusercontent.com/u/29527409/AI/BotornotAI_source.rar

[2] Web verzija igre dostupna na:

https://dl.dropboxusercontent.com/u/29527409/AI/Prototype/index.html

[3] Windows verzija igre dostupna na:

https://dl.dropboxusercontent.com/u/29527409/AI/BotornotAI.rar