Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
UNIVERZA V MARIBORU
FAKULTETA ZA ELEKTROTEHNIKO,
RAČUNALNIŠTVO IN INFORMATIKO
Klemen Rus
RAZVOJ IN PROBLEMI PRI RAZVOJU RAČUNALNIŠKIH
IGER
Diplomsko delo
Maribor, avgust 2017
RAZVOJ IN PROBLEMI PRI RAZVOJU RAČUNALNIŠKIH IGER
Diplomsko delo
Študent: Klemen Rus
Študijski program: Univerzitetni študijski program
Računalništvo in informacijske tehnologije
Mentor: red. prof. dr. Peter Kokol, univ. dipl. inž. el.
i
ZAHVALA
Zahvaljujem se mentorju red. prof.
dr. Petru Kokolu, univ. dipl. inž. el.
za vodenje in pomoč pri pisanju
diplomskega dela.
Zahvaljujem se tudi družini, ki me je
med študijem podpirala.
ii
Razvoj in problemi pri razvoju računalniških iger
Ključne besede: Unity, računalniške igre, funkcija, skripta
UDK: 004.92(043.2)
Povzetek
V diplomskem delu smo preučili prosto dostopno razvojno okolje Unity in uporabili
pridobljeno znanje pri izdelavi temeljev računalniške igre, na katerih se lahko nato
preprosto gradi. Delo je vključevalo pisanje skript in izdelavo objektov z različnimi
komponentami. Potek izdelave smo podrobno opisali in posebej razložili funkcije, ki so
značilne za uporabljeno razvojno okolje. Za test smo ustvarili sceno, kjer smo uporabili
ustvarjene objekte, da smo lahko preučili njihovo obnašanje in popravili morebitne napake.
iii
The development of computer games and its
problems
Key words: Unity, computer games, function, script
UDK: 004.92(043.2)
Abstract
In our thesis we examined the freely accessible game engine Unity and used the acquired
knowledge to create the basis of a video game, which can then be easily built upon. The
work consisted of writing scripts and developing objects with different components. We
thoroughly described the developmental process and additionally explained the functions
that are typical for the used developmental setting. For testing we developed a scene, where
we used the created objects, so that we could study their behavior and correct any possible
mistakes.
iv
KAZALO
1 Uvod ........................................................................................................................................... 1
2 Unity ........................................................................................................................................... 2
2.1 Splošno o orodju................................................................................................................. 2
2.2 Delovno okolje Unity .......................................................................................................... 2
3 Komponente ............................................................................................................................... 4
3.1 Trkalniki in toga telesa ........................................................................................................ 4
3.2 Animator ............................................................................................................................. 5
3.3 Posebne funkcije v Unity .................................................................................................... 5
4 Izdelovanje igre .......................................................................................................................... 7
4.1 Scena .................................................................................................................................. 7
4.2 Navigacija ........................................................................................................................... 7
4.3 Interakcija s svetom ............................................................................................................ 9
4.4 Pogovorni sistem .............................................................................................................. 11
4.5 Statistike likov in orožij ..................................................................................................... 13
4.6 Inventar in JSON ............................................................................................................... 15
4.7 Uporaba orožij .................................................................................................................. 22
4.8 Nasprotniki ....................................................................................................................... 28
4.9 Skripta glavnega lika ......................................................................................................... 32
4.10 Megla vojne ...................................................................................................................... 33
4.11 Zemljevid .......................................................................................................................... 37
4.12 Glavna kamera .................................................................................................................. 38
4.13 Animacije .......................................................................................................................... 39
5 Diskusija in sklep....................................................................................................................... 41
6 Viri ............................................................................................................................................ 43
v
KAZALO SLIK
Slika 2.1 Uporabniški vmesnik ............................................................................................................ 3
Slika 3.1 Prikaz trkalnikov kvadra na modelu okostnjaka .................................................................. 4
Slika 4.1 Lastnosti navigacijskega agenta v inšpektorju. .................................................................... 8
Slika 4.2 Skripta WorldInteraction.cs. ................................................................................................ 9
Slika 4.3 Skripta Interactable.cs. ...................................................................................................... 10
Slika 4.4 Razred NPC, ki deduje od Interactable. ............................................................................. 10
Slika 4.5 Prvi del skripte DialogueSystem.cs, kjer smo inicializirali spremenljivke. ......................... 11
Slika 4.6 Funkcije za prikaz dialoga. ................................................................................................. 12
Slika 4.7 Del inšpektorja pogovornega objekta, kjer smo dodali vsebino pogovora. ...................... 12
Slika 4.8 Skripta StatBonus.cs. .......................................................................................................... 13
Slika 4.9 Spremenljivke v skripti BaseStat.cs. ................................................................................... 13
Slika 4.10 Metodi za dodajanje in odstranitev bonusov ter metoda za računanje statistik. ........... 14
Slika 4.11 Del skripte CharacterStats.cs, kjer imamo konstruktor za statistike likov. ...................... 14
Slika 4.12 Metode za spreminjanje statistik. .................................................................................... 15
Slika 4.13 Prikaz inventarja v igri. ..................................................................................................... 16
Slika 4.14 Objekti, ki sestavljajo inventar v hierarhiji. ...................................................................... 16
Slika 4.15 Del Json datoteke, kjer smo napisali statistiko meča. ..................................................... 17
Slika 4.16 Prikaz uporabe Json konstuktorja. ................................................................................... 18
Slika 4.17 Skripta ItemDatabase.cs, kjer se prebere Json datoteka. ................................................ 18
Slika 4.18 Skripta InventoryController.cs. ........................................................................................ 19
Slika 4.19 Funkciji SetItemDetails() in EquipItem(). ......................................................................... 19
Slika 4.20 Skripta InventoryUIItem.cs .............................................................................................. 20
Slika 4.21 Kratka skripta UIEventHandler() za vodenje dogodkov v uporabniškem vmesniku. ....... 20
Slika 4.22 Skripta InventoryUI.cs, ki prikazuje predmete na inventarju. ......................................... 21
Slika 4.23 Skripta InventoryUIDetails.cs, prikaže podrobnosti posameznih predmetov. ................ 21
Slika 4.24 Funkcije v skripti InventoryUIDetails.cs. .......................................................................... 22
Slika 4.25 Vmesnik za orožja v skripti IWeapon.cs. .......................................................................... 23
Slika 4.26 Skripta Sword.cs, ki je uporabljena za orožja na blizu. .................................................... 23
Slika 4.27 Del skripte RangedWeapon.cs, kjer smo napisali spremenljivke in naložili prefab
izstrelka. ........................................................................................................................................... 24
Slika 4.28 Del skripte s funkcijama PerformAttack() in CastProjectile(). ......................................... 24
Slika 4.29 Skripta Fireball.cs. ............................................................................................................ 25
Slika 4.30 Spremenljivke v skripti PlayerWeaponController.cs. ....................................................... 26
Slika 4.31 Funkcije v skripti PlayerWeaponController.cs ................................................................. 26
Slika 4.32 Funkcija projectile(), ki se kliče v določenem delu animacije. ......................................... 27
Slika 4.33 Prikaz funkcije Update(), ki ob kliku na tipko X sproži napad. ......................................... 27
Slika 4.34 Vmesnik za sovražnike v skripti IEnemy.cs. ..................................................................... 28
Slika 4.35 Del skripte Skeleton.cs, kjer so spremenljivke in funkcija Start(). ................................... 29
Slika 4.36 Funkciji PerformAttack() in TakeDamage() v skripti Skeleton.cs. .................................... 29
Slika 4.37 Funkcija ChasePlayer(), ki omogoča sovražnikom, da sledijo igralcu. ............................. 30
Slika 4.38 Funkcija, ki najde naključno točko v določenem krogu. .................................................. 30
Slika 4.39 Funkcija Update() v skripti Skeleton.cs. ........................................................................... 31
vi
Slika 4.40 Skripta EnemySword.cs, ki smo jo pripeli na meč nasprotnikov. ..................................... 32
Slika 4.41 Del skripte Player.cs, kjer je inicializacija spremenljivk. .................................................. 33
Slika 4.42 Funkcija TakeDamage() v igralčevi skripti. ....................................................................... 33
Slika 4.43 Prikaz megle vojne v igri................................................................................................... 34
Slika 4.44 Pravokotnik je nameščen na kamero, krog pa na igralca. ............................................... 35
Slika 4.45 Skripta FogOfWarSighs.cs. ............................................................................................... 35
Slika 4.46 Skripta FogOfWarVisibility.cs. .......................................................................................... 36
Slika 4.47 Izgled mape v igri. ............................................................................................................ 37
Slika 4.48 Skripta za nadzor kamere. ................................................................................................ 38
Slika 4.49 Okno animatorja, kjer so animacije in tranzicije. ............................................................. 39
Slika 4.50 Parametri, s katerimi se prožijo animacije. ...................................................................... 39
Slika 4.51 Primer klicanja tranzicij v kodi. ........................................................................................ 40
Slika 4.52 Konec seznama, kamor smo dodali trkalnik. ................................................................... 40
Slika 5.1 Scena iz igre. ....................................................................................................................... 42
1
1 UVOD
Industrija razvoja iger je v zadnjih desetletjih doživela velik razcvet tako na grafičnem kot
tudi na funkcijskem področju. Grafika se je razvila že skoraj v fotorealistično, kar omogoča
razvijalcem izdelavo vizualno zelo dodelanih iger, ki so uporabniku dostopne že v nižjem
cenovnem rangu. Obstaja mnogo različnih razvijalcev, ki izdelujejo igre iz vseh žanrov.
Nekateri imajo nad sabo velike založniške hiše medtem ko drugi izdelujejo igre bolj
samostojno (Indie). Orodja za razvoj so vedno bolj dostopna, posledica česar je pojav
mnogih novih razvijalcev, ki se hočejo preizkusiti pri izdelavi računalniških iger in mnogim
ne uspe, saj je kljub lažji dostopnosti vedno težje doseči zahteve mnogih končnih
uporabnikov. Tudi mnogim večjim razvijalcem (Bioware, Bethesda) včasih ne uspe pokriti
stroškov izdelave ali doseči pričakovanih ocen.
Skozi šolanje smo izdelali več računalniških iger, tako v projektni skupini kot tudi
individualno. Uporabljali smo več različnih orodij in eno od teh je bil Unity, ki smo ga
uporabili tudi pri izdelavi diplomskega dela. Namen je bil uporabiti pridobljeno znanje
tekom šolanja in pridobiti dodatne izkušnje v okviru izdelovanja iger. Cilj je bil narediti
osnovo za računalniško igro, na kateri se potem lahko gradi brez večjih problemov; torej
napisati urejene in optimizirane skripte, ki jih je možno dopolnjevati, npr. z dedovanjem,
ter definirati objekte, ki so potrebni na sceni za pravilno delovanje.
Za igro, ki je služila kot test, smo si zamislili fantazijski svet, kjer igralec igra lik, ki mora
preživeti pot skozi gozd, kjer se nahajajo sovražniki. Za žanr smo si izbrali igro, kjer igraš
izbrano vlogo z izometričnim pogledom na svet. Skozi razvoj smo implementirali različne
funkcionalnosti, ki so pomembne za takšen žanr igre in sproti opisali probleme, ki so
nastajali, ter njihove rešitve.
Opisali smo uporabniški vmesnik uporabljenega okolja ter njegove funkcionalnosti. Opisali
smo tudi uporabljene komponente in napisane skripte po logičnem zaporedju, da ni bilo
veliko referenc na stvari, ki še niso bile omenjene. Podrobno smo se spustili v dele kode, ki
so posebni za Unity. Izdelali smo tudi uporabniški vmesnik in preizkusili uporabo animacij
modelov.
2
2 UNITY
2.1 Splošno o orodju
Unity je razvojno okolje, ki ga je razvilo podjetje Unity Technologies in se uporablja
predvsem za izdelovanje iger za računalnike, konzole in mobilne naprave v 3D in 2D obliki.
Aplikacijski programski vmesniki (API), ki jih uporablja za grafično prikazovanje, so Direct3D
in Vulkan za Windows in Xbox, OpenGL za Mac, Linux in Windows ter OpenGL ES za Android
in iOS. Za skriptiranje se uporabljajo trije programski jeziki: C#, ki bo edini uporabljen pri
izdelavi diplomske naloge, javascript ter Boo. [12] Zraven je vključena prirejena verzija
razvojnega orodja MonoDevelop za pisanje skript, vendar Unity podpira tudi kateri koli
drugi urejevalnik besedil. Ima tudi svoj avdio in video sistem, omogoča preprosto
ustvarjanje terena, prilagajanje več različnih virov svetlobe ter tudi animacijo objektov. Na
voljo je spletna trgovina Unity Asset Store, na kateri se lahko najdejo različni modeli,
animacije, zvočne datoteke, teksture in druge stvari, nekatere na voljo popolnoma zastonj.
Nekatere igre, narejene v Unity so Bad Piggies, Temple Run, Hearthstone, Kerbal Space
Program in Pillars of Eternity. [6]
2.2 Delovno okolje Unity
Uporabniški vmesnik sestavljajo različna okna (slika 2.1), ki se jim da prilagoditi položaj in
velikost, lahko pa se katero tudi skrije v primeru, da ni več uporabno. Vsako teh oken
omogoča nadzor določenih delov iger. Najprej imamo hierarhijo (1), kjer se nahajajo
objekti, ki so trenutno na sceni. Objekti na svojem drevesu spadajo skupaj in sprememba
objekta, ki je višje na hierarhiji vpliva na vse, ki so nižje. Če bi v našem primeru na sceni
premaknili testni objekt (9), bi se prestavil tudi otrok, medtem ko sprememba otroka ne bi
vplivala na njegovega starša. Ustvarimo lahko tudi povsem prazne objekte, ki niso
namenjeni za vizualni prikaz na sceni, ampak za pripenjanje skript ali urejanje hierarhije.
3
Nato imamo projektne mape (2), kjer imamo vsa sredstva, ki jih hočemo uporabiti pri
izdelavi igre. Naslednja je konzola (3), kamor se poleg napak in opozoril izpisujejo tudi
sporočila za pomoč pri razhroščevanju. Okno za sceno (4) razvijalcu omogoča vizualno
upravljanje igre in sicer dodajanje in odstranjevanje objektov, spreminjanje njihovih
velikosti, pozicije in usmerjenosti v prostoru. Tukaj se spreminja teren in gradi okolica ter
tudi spreminja grafični vmesnik v sami igri. Pod njim se pri nas nahaja okno za igro (5), kjer
lahko testiramo njeno delovanje, tudi v celozaslonskem načinu. Zadnje od stalno
uporabljenih je nadzorno okno (6), kjer so izpisane vse komponente izbranega objekta, ki
smo mu jih dodali. To so lahko skripte, ki so nanj pripete, položaj, rotacija, velikost, trkalniki,
agent za navigacijo, izvori za avdio in druge komponente. Vsako teh komponent se da tudi
posebej izklopiti. Na voljo so še okna za navigacijo, animacijo, trgovino ter upravljanje s
svetlobo. Na vrhu se na sredini nahajata še gumba za zagon in pavzo igre (7), kar omogoča
testiranje že v samem Unityju. Zelo pogosto so uporabljene še transformacije (8), katerih
gumbi se nahajajo v zgornjem levem kotu uporabniškega vmesnika. Ti omogočajo premik,
rotacijo ter skaliranje objektov.
Slika 2.1 Uporabniški vmesnik
4
3 KOMPONENTE
Vsak objekt v Unity je v osnovi samo točka, ki ji lahko dodajamo različne komponente, s
čimer jo lahko definiramo v sovražnike, del terena, efekt, kamero, glavni lik ali karkoli
drugega, kar najdemo v igrah. Vsak objekt ima oznako (ang. tag), plast (ang. layer) in
ime(ang. name), ki so pomembne lastnosti npr. pri pisanju skript, saj lahko prek njih lažje
najdemo iskane objekte. Če imamo več kopij enakega objekta na sceni, lahko ob spremembi
enega to prenesemo še na ostale s klikom na gumb potrdi(ang. apply) v inšpektorju. Poleg
tega lahko vsak objekt na sceni kopiramo v projektno mapo, kjer se ustvari njegov prefab,
ki ima vse lastnostni kopiranega objekta, da ga lahko uporabimo kasneje ali na drugi sceni.
V nadaljevanju si poglejmo nekaj pomembnejših komponent, ki smo jih uporabili pri
izdelavi igre.
3.1 Trkalniki in toga telesa
V igri se lahko objekti med sabo trčijo in zato uporabljamo trkalnike (ang. colliders), s
katerimi lahko objekti ugotovijo, če se je zgodil trk med njimi. Unity pozna pet vrst
trkalnikov in mi smo od teh uporabili trkalnik kvadra (ang. box collider) (slika 3.1) in krogelni
trkalnik (ang. sphere collider). Prvemu lahko spreminjamo velikost in obliko (slika),
drugemu pa samo premer.
Slika 3.1 Prikaz trkalnikov kvadra na modelu okostnjaka
5
Togo telo (ang. rigidbody) omogoča, da se objekti podrejajo določenim fizikalnim pravilom,
kot je npr. gravitacija. Objekt je lahko kinematičen, kar pomeni, da drugi objekti nanj ne
morejo vplivati. Določimo lahko tudi maso in moč upočasnitve ter zaklenemo njegov
položaj in rotacijo. [10]
3.2 Animator
Animator omogoča, da lahko na objekt dodamo več animacij, ki jih potem v skripti
zaganjamo. Lahko pa dodamo komponento animacija (ang. animation), kar smo v igri
naredili, ko za enega od likov nismo potrebovali več kot ene animacije, ki se je ves čas
ponavljala.
Ostale komponente si bomo ogledali pri pisanju skript.
3.3 Posebne funkcije v Unity
Pri skriptiranju se v Unityju pogosto uporabljajo dogodkovne funkcije in v nadaljevanju si
poglejmo tiste, ki so bile uporabljene pri izdelavi diplomske naloge. Zaporedje izvajanja teh
funkcij je že v naprej definirano.
Začetek scene (te funkcije se kličejo samo enkrat v življenjski dobi skripte):
Start(): se pokliče tik preden se prvič kličejo metode iz funkcije Update().
Awake(): se izvede takoj, ko je objekt s skripto inicializiran, četudi skripta sama še ni
omogočena in se kliče pred funkcijo Start(). [7]
Nadgradnja (ang. update):
Update(): je najbolj pogosto uporabljena funkcija za posodobitve, ki se kliče vsak okvir in je
odvisna od hitrosti izrisovanja (Frame rate) oz. od zmogljivosti računalnika.
6
FixedUpdate(): podobna kot Update(), vendar ni odvisna od hitrosti okvirjev oz. zmogljivosti
računalnika, ampak od posebnega časovnika. Uporablja se pri fiziki, tako da le ta ni odvisna
od hitrosti izrisovanja.
Korutine (ang. coroutines):
Yield: ob klicu prekine izvajanje kode in se nadaljuje ob klicu naslednjega okvirja. [2]
Yield WaitForSeconds(n): ob klicu prekine izvajanje kode in se nadaljuje, ko poteče n
sekund.
Yield StartCoroutine(n): ob klicu zažene korutino n in zaustavi izvajanje kode, dokler se
korutina ne izvrši
Skripte, ki dedujejo od MonoBehavior so edine, ki jih lahko pripnemo na objekte v igri,
medtem ko ostale lahko uporabljamo samo preko drugih skript.
GetComponent(): je vgrajena funkcija v Unity s katero lahko inicializiramo spremenljivke s
komponentami objektov na sceni, da jim lahko potem spreminjamo lastnosti.
Pri izdelavi nekaterih funkcij igre smo si pomagali z navodili s spletne strani YouTube [4].
7
4 IZDELOVANJE IGRE
4.1 Scena
Igre so sestavljene iz različnih scen, ki jih lahko preklapljamo in vsebujejo objekte igre.
Lahko jih uporabimo pri ustvarjanju glavnega menija in različnih nivojev igre. Za podlago
smo uporabili vgrajen Unity teren (ang. terrain), kateremu lahko poljubno spreminjamo
obliko in nanj rišemo z različnimi teksturami. Za okraševanje okolice smo uporabili paket
Low Poly: Free Pack [1], ki vsebuje zelo preproste modele s standardnimi Unity materiali
brez tekstur, ki posledično ne bremenijo računalnika. Po potrebi smo nekatere od njih
tekom izdelovanja igre dodali na sceno, tako da smo lahko preizkusili izdelane
funkcionalnosti. Sprva smo za glavni lik izbrali kar preprosto kocko, da smo lahko testirali
navigacijo in interakcijo z drugimi objekti. Kasneje smo uporabili model ženske [3] za glavni
lik, model okostnjaka [11] za sovražnike in model čarovnika za pogovorni lik [8].
4.2 Navigacija
Unity ima vgrajeno navigacijo, ki omogoča uporabniku, da določi kateri objekti so ovira,
okoli katerih morajo liki najti pot. V oknu za navigacijo je bilo potrebno izbrati teren in
potem objekte, ki predstavljajo oviro, tako da je lahko Unity izračunal (ang. bake) območje,
kjer se liki lahko premikajo. Ker se dovoljeno območje ne računa tekom igranja, je potrebno,
da so ti objekti morali ostati statični. Na vse like, na katerih je bila potrebna navigacija smo
dodali navigacijskega agenta (ang. Nav Mesh Agent), ki mu lahko spreminjamo hitrost
premikanja in obračanja, pospešek in razdaljo od cilja, kjer se bo lik ustavil (slika 4.1).
8
Slika 4.1 Lastnosti navigacijskega agenta v inšpektorju.
Uporaba navigacijskega agenta nam v kodi omogoča uporabo njegovih funkcij:
ResetPath(): Izbriše začrtano pot, tako da se agent ustavi.
hasPath: Preveri, če ima agent pot, in vrne logično vrednost (true, false).
stoppingDistance: Kako daleč od cilja se bo agent ustavil.
destination: Cilj, do katerega se odpravi agent.
Stop(): Popolnoma ustavi navigacijo agenta.
9
4.3 Interakcija s svetom
Za interakcijo s svetom smo ustvarili skripto WorldInteraction.cs (slika 4.2), ki obravnava
vsak klik in se odzove odvisno od pogojev. Na določene objekte smo dali oznake (ang. tag),
s pomočjo katerih skripta prepozna vrsto interakcije in se potem pravilno odzove.
Slika 4.2 Skripta WorldInteraction.cs.
Položaj miške smo dobili s pomočjo žarkov (ang. ray), tako da smo prožili žarek od kamere
do pozicije kazalca s funkcijo Raycast(). V Update() imamo pogojni stavek, ki preverja ali je
bil stisnjen desni miškin gumb in če se kazalec trenutno nahaja na uporabniškem vmesniku.
Slednji pogoj prepreči, da bi se sprožila interakcija z nečim, kar se nahaja za uporabniškim
vmesnikom. Ob primeru, da sta bila oba pogoja izpolnjena, se kliče funkcija
GetInteraction(), ki preveri kje se trenutno nahaja miškin kazalec in se odzove odvisno od
pogojev. Na primer, če je bil klik izveden na objektu z oznako Interactable Object, se bo
sprožila skripta Interactable.cs (slika 4.3), ki se nahaja na tem objektu. Pogojni stavek else
se izvede, če kliknemo na objekt brez oznak ali pa na tla. V tem primeru se lik preprosto
prestavi na dano pozicijo.
10
Slika 4.3 Skripta Interactable.cs.
Za vsak objekt z interakcijo se lahko ustvari skripta oziroma nov razred (slika 4.4), ki
podeduje od Interactable s tem, da se tam določi, kaj točno bo funkcija Interact() naredila
(override). Ustvarili smo tri takšne razrede, enega za kažipot, drugega za pogovorne like
(ang. non-player character - NPC) in tretjega za predmete, ki se jih da pobrati. Te skripte
smo nato dodali na objekte odvisno od želene interakcije.
Slika 4.4 Razred NPC, ki deduje od Interactable.
11
4.4 Pogovorni sistem
Za pogovorni (ang. dialogue) sistem smo najprej morali v sceno dodati nekatere gradnike
uporabniškega vmesnika (ang. user interface - UI). Glavni gradnik je platno (ang. canvas),
na katerega se potem dodajo vsi ostali elementi kot so gumbi, polja s tekstom in plošče
(ang. panel). Platno v igri vsebuje plošče za inventar, zemljevid in pogovorni sistem. Slednji
ima dve polji s tekstom, eno za ime, drugo za besedilo ter gumb za nadaljevanje pogovora.
Poleg teh je na to ploščo pripet še prazni objekt, kamor smo prilepili skripto
DialogueSystem.cs (slika 4.5) ki obravnava pogovore. Spremenljivko dialoguePanel smo
določili s tem, da smo prenesli ploščo pogovornega sistema na pravilno mesto v
inšpektorju, kjer se nahaja skripta. Uporabili smo funkcijo Awake(), kjer smo povezali
elemente iz skripte s tistimi na platnu. Potrebno je bilo dodati še poslušalec (ang. listener)
na gumb, da se proži funkcija, ki nadaljuje pogovor.
Slika 4.5 Prvi del skripte DialogueSystem.cs, kjer smo inicializirali spremenljivke.
12
Nato imamo tri funkcije (slika 4.6). AddNewDialogue() se kliče iz objekta sogovornika v
zgoraj omenjeni funkciji Interact() in doda pogovor na seznam (ang. list). Nato ta ista
funkcija kliče CreateDialogue(), kjer se besedilo in ime sogovornika preneseta na
uporabniški vmesnik, ki se potem tudi aktivira in postane viden. ContinueDialogue() se proži
s klikom na gumb in nadaljuje pogovor, po koncu katerega se uporabniški vmesnik spet
skrije.
Slika 4.6 Funkcije za prikaz dialoga.
Vsebina pogovora se določi v inšpektorju (slika 4.7) tistih objektov, ki imajo skripte
podedovane od Interactable, npr. naš pogovorni lik s skripto NPC.
Slika 4.7 Del inšpektorja pogovornega objekta, kjer smo dodali vsebino pogovora.
13
4.5 Statistike likov in orožij
Vsak lik v igri ima osnovne statistike, ki se jih potem lahko nadgradi z različnimi bonusi, kot
je na primer povečanje moči z novim orožjem, kar smo dosegli z uporabo treh različnih
skript. Najprej imamo kratko skripto StatBonus.cs (slika 4.8), kjer imamo zgolj konstruktor,
ki pomaga pri dodajanju bonusov.
Slika 4.8 Skripta StatBonus.cs.
Nato imamo skripto osnovnih statistik BaseStat.cs (slika 4.9) z istoimenskim razredom, kjer
so definirane spremenljivke, konstruktor in metode za urejanje pozamezne osnovne
statistike. Ustvarili smo nove tipe spremenljivk BaseStatType (enumerator), ki predstavljajo
vsako od osnovnih statistik (Power, Toughness, AttackSpeed).
Slika 4.9 Spremenljivke v skripti BaseStat.cs.
14
Nato smo definirali konstruktor in napisali metodi za dodajanje in odstranitev bonusov ter
metodo, ki ob klicu vrne celotno izračunano vrednost določene statistike (slika 4.10).
Slika 4.10 Metodi za dodajanje in odstranitev bonusov ter metoda za računanje statistik.
Zadnji razred CharacterStats.cs (slika 4.11) združi vse osnovne statistike, da se ga lahko
uporabi pri inicializaciji posameznega lika v igri s tem, da se v konstruktorju preprosto
določijo željene vrednosti.
Slika 4.11 Del skripte CharacterStats.cs, kjer imamo konstruktor za statistike likov.
15
Nato imamo še metode za iskanje, povečanje in zmanjšanje določene statistike (slika 4.12).
Prva se uporabi pri slednjih dveh, saj je potrebno paziti, da se spreminja prava statistika.
Slika 4.12 Metode za spreminjanje statistik.
Ob primeru, da hočemo dodati k moči napada kakšnen bonus, preprosto pokličemo
metodo AddStatBonus(), ki ji v argument podamo željeni bonus. Nato metoda GetStat() na
podlagi tega bonusa najde pravilno osnovno statistiko in ji poveča vrednost s tem, da se
kliče metoda AddStatBonus() iz razreda BaseStat(). To bo podrobneje videno pri dodajanju
orožij.
4.6 Inventar in JSON
Da bi lahko uporabili skripte za bonuse, je bilo potrebno narediti še predmete, ki jih
vsebujejo. Za igro je bilo narejenih nekaj orožij, ki se nahajajo v inventarju (ang. inventory).
Najprej je bil izdelan del uporabniškega vmesnika, ki predstavlja inventar (slika 4.13). Na
platno smo dodali nov prazni objekt Inventory, (slika 4.14) na katerega smo dodali nekaj
skript. Nato smo v hierarhijo dodali ploščo za prikaz predmetov (ang. scroll view) in desno
od nje ploščo, ki vsebuje lastnosti določenega predmeta (ang. inventory details) ter gumb
16
za njegovo uporabo. V plošči za prikaz predmetov smo ustvarili še ploščo Item_Container s
komponentno gumba, ki pa smo jo nato prenesli v projektno mapo in s tem ustvarili njen
prefab. Komponenta gumba je potrebna, da se lahko izpišejo podrobnosti ob kliku na
predmet.
Slika 4.13 Prikaz inventarja v igri.
Slika 4.14 Objekti, ki sestavljajo inventar v hierarhiji.
17
Za delo z Json datotekami je bilo potrebno namestiti poseben Unity paket [5], ki omogoča
uporabo novih funkcij, potrebnih za branje Json podatkov, iz katerih se potem inicializirajo
lastnosti orožij. Na spodnji sliki je predstavljen del Json datoteke (slika 4.15), kjer so
zapisane lastnosti enega od orožij. Od teh so za igro najbolj pomembni objectSlug, ki
predstavlja ime modela, ki se mora naložiti iz projektne mape, itemType, ki pove, ali je
orožje uporabljeno na blizu ali za na daleč, actionName, ki predstavlja akcijo, ki se bo izvedla
ob uporabi predmeta ter stats, ki predstavlja statistike iz prejšnjega poglavja. Ostale
lastnosti so zgolj za prikaz v inventarju.
Slika 4.15 Del Json datoteke, kjer smo napisali statistiko meča.
Najprej smo ustvarili razred Item.cs (slika 4.16) za predmete, kjer smo definirali njihove
lastnosti, kot so tip, ime in opis. Tudi tukaj smo naredili nove spremenljivke (enumerator)
in sicer za tip predmeta, ki smo jih inicializirali s pomočjo Json pretvornika, ki prebere
vrednosti iz Json datoteke in jih pretvori v pravilne tipe, ki so potrebni v konstruktorju.
18
Slika 4.16 Prikaz uporabe Json konstuktorja.
Sam bralnik Json datotek smo naredili v skripti ItemDatabase.cs (slika 4.17), kjer najprej
ustvarimo seznam tipa Item in ga nato v funkciji BuildDatabase() preprosto zapolnimo s
pomočjo Json funkcije, ki prebere datoteko. Imamo še funkcijo GetItem(), ki iz tega
seznama poišče in vrne iskani predmet. Ta skripta je prva, ki smo jo dodali na objekt
Inventory v hierarhiji.
Slika 4.17 Skripta ItemDatabase.cs, kjer se prebere Json datoteka.
19
Nato smo morali napisati skripte za dejanski prikaz predmetov na inventarju. V glavni,
nadzorni skripti InventoryController() (slika 4.18), katero smo pripeli na glavni lik, smo
naredili seznam s predmeti. Tega polnimo v funkciji GiveItem(), ki dobi predmete iz baze
podatkov ItemDatabase, ki se ustvari ob zagonu igre. Za test smo uporabili meč in lok.
Deklarirati smo morali tudi nadzornik za orožja PlayerWeaponController ter skripto za
prikaz podrobnosti InventoryUIDetails, saj SetItemDetails() ter EquipItem() uporabljata
njune funkcije (slika 4.19). Obe skripti bomo prikazali v nadaljevanju.
Slika 4.18 Skripta InventoryController.cs.
Slika 4.19 Funkciji SetItemDetails() in EquipItem().
20
Naslednja je krajša skripta InventoryUIItem.cs (slika 4.20), ki je pripeta na zgoraj omenjeni
Item_Container prefab, katere vsaka instanca prikazuje enega od predmetov v inventarju.
V njej smo deklarirali nekaj spremenljivk in funkcije, ki jih inicializirajo. Ena od spremenljivk
je slika (ang. sprite) predmeta, da je lahko v inventarju tudi vizualno prikazan. Zadnja od
funkcij se sproži ob kliku na gumb, ki je komponenta na objektu Item_Container.
Slika 4.20 Skripta InventoryUIItem.cs
Nato imamo zelo kratko skripto UIEventHandler() (slika 4.21), ki vodi dogodke(ang. event
handler) v uporabniškem vmesniku in se sproži vedno, ko želimo dodati predmet v inventar.
Najprej ustvarimo delegat(kazalec na metodo) ItemEventHandler, ki vodi vse, kar se zgodi
s predmetom na uporabniškem vmesniku. Nato ustvarimo še statični dogodek in funkcijo,
ki proži ta dogodek. Oba morata biti statična, da se lahko na njiju normalno sklicujemo tudi
izven vodnika dogodkov.
Slika 4.21 Kratka skripta UIEventHandler() za vodenje dogodkov v uporabniškem vmesniku.
21
Naslednja skripta InventoryUI.cs (slika 4.22) obravnava prikaz seznama predmetov na
inventarju. Deklarirati smo morali dva javna objekta, ki smo ju inicializirali v inšpektorju, in
sicer inventoryPanel, ki predstavlja celotno ploščo inventarja, da ga lahko vklopimo in
izklopimo po potrebi, ter scrollViewContent, kjer se nahajajo predmeti instanc
InventoryUIItem, ki so trenutno v inventarju. Deklarirati smo morali še InventoryUIItem, ki
smo ga inicializirali v funkciji Start(), s tem da smo naložili Item_Container prefab. Poleg
tega imamo v Start() še vodnika dogodkov, ki se sproži vedno ko želimo dodati predmet v
inventar, kar kliče funkcijo ItemAdded(), ki predmet dejansko doda.
Slika 4.22 Skripta InventoryUI.cs, ki prikazuje predmete na inventarju.
Na koncu je bilo v okviru inventarja potrebno napisati še skripto (slika 4.23), ki ob pritisku
na predmet sproži izpis njegovih lastnosti. To naredimo v skripti InventoryUIDetails.cs, ki
smo jo dodali na ploščo Inventory Details, katera se nahaja v hierarhiji.
Slika 4.23 Skripta InventoryUIDetails.cs, prikaže podrobnosti posameznih predmetov.
22
Najprej smo v funkciji Start() našli komponente(tekst in gumb) na plošči, katerim smo
potem priredili vrednosti iz predmeta, ki je bil izbran (slika 4.24). To smo naredili v funkciji
SetItem(), kjer poleg teksta dodamo še poslušalec (ang. listener) na gumb, ki se sproži ob
kliku. Poslušalec smo definirali v funkciji OnItemInteract(), kjer se odvisno od vrste
predmeta izbere pripadajoča akcija, ki je v primeru orožja opremiti lik s tem orožjem.
Slika 4.24 Funkcije v skripti InventoryUIDetails.cs.
4.7 Uporaba orožij
Za orožja smo najprej ustvarili vmesnik (ang. interface) IWeapon (slika 4.25) v istoimenski
skripti, kjer smo deklarirali metode in spremenljivke, ki jih uporabljajo vsa orožja:
List<BaseStat> Stats: Je seznam z osnovnimi statistikami orožij.
PerformAttack(): Je funkcija za izvajanje napada, ki se kliče iz PlayerWeaponController-ja.
CharacterStats stats: So statistike lika, ki drži orožje.
23
Slika 4.25 Vmesnik za orožja v skripti IWeapon.cs.
Te funkcije smo potem natančneje definirali v skriptah za posamezna orožja. Prva takih
skript je Sword.cs (slika 4.26) za orožja na blizu, na katere je bila skripta tudi dodana. Pri
ustvarjanju animacij je mogoče na določenem delu animacije vklopiti ali izklopiti trkalnik.
To je bilo pomembno, da meč ni ranil nasprotnikov, če se jih je zgolj dotaknil ob gibanju
lika, ampak pri dejanskem napadu. Tukaj je nastal problem, ker orožja niso pripeta na lik
ves čas, kar pomeni, da v oknu animacij ni bilo mogoče nadzorovati njihovih trkalnikov.
Sicer je mogoče pavzirati sceno po dodajanju orožja, ki mu potem v oknu animacij lahko
nastavimo trkalnik in ta deluje po nadaljevanju igranja, vendar preneha delovati ob
ponovnem zagonu igre. Da bi rešili problem, smo naredili nov objekt ColliderSword na liku,
ki se nahaja na isti poziciji kot orožja. Ta objekt nima upodobitve, ampak zgolj trkalnik. Ker
je ta objekt vedno na sceni, mu med animacijo lahko spreminjamo lastnosti trkalnika in
potem v kodi preprosto ranimo nasprotnika, če sta bila hkrati vklopljena trkalnika od
objekta ColliderSword in dejanskega orožja.
Slika 4.26 Skripta Sword.cs, ki je uporabljena za orožja na blizu.
24
Nato smo napisali skripto RangedWeapon.cs (slika 4.27) za orožja, ki so uporabljena za
napade na daleč. Ta ima poleg spremenljivk iz vmesnika IWeapon še instanco razreda za
izstrelek, ki ga bomo predstavili v nadaljevanju.
Slika 4.27 Del skripte RangedWeapon.cs, kjer smo napisali spremenljivke in naložili prefab izstrelka.
Vsebuje tudi posebno funkcijo CastProjectile() (slika 4.28) za izstrelitev, ki jo kličemo v
nadzorniku orožij. Tukaj se določi pozicija, usmerjenost ter razdalja do cilja za izstrelek.
Slika 4.28 Del skripte s funkcijama PerformAttack() in CastProjectile().
Skripta Fireball.cs (slika 4.29), ki smo jo dodali na objekt izstrelka, vsebuje Start(), kjer smo
uporabili vgrajeno funkcijo AddForce(), ki doda silo na določen objekt. Poleg tega imamo še
funkcijo, ki gleda, če je prišlo do trčenja med izstrelkom in nasprotnim likom. V tem primeru
se slednjega rani, izstrelek pa uniči.
25
Slika 4.29 Skripta Fireball.cs.
Prej smo že omenili skripto PlayerWeaponController.cs, ki nadzoruje funkcionalnosti orožij.
Tukaj smo napisali funkcijo EquipWeapon(), ki jo kličemo v nadzorniku inventarja, ko želimo
opremiti lik z določenim orožjem. Poleg te pa imamo še funkcijo za napad in sprožitev
izstrelka ob primeru, da imamo opremljen lok . Najprej smo deklarirali nekaj spremenljivk
(slika 4.30):
GameObject playerHand, leftHand (inicializirani v inšpektorju): Uporabljeni, da lahko ima
lik orožja v obeh rokah.
IWeapon equippedWeapon: Da smo lahko uporabili funkcije iz vmesnika za orožje.
Transform spawnProjectile (inicializirali v inšpektorju): Kjer se ob primeru loka izstreli
puščica.
CharacterStats characterStats: Da lahko združimo statistike lika in orožja ob napadu.
26
Slika 4.30 Spremenljivke v skripti PlayerWeaponController.cs.
V funkciji EquipWeapon() smo najprej pogledali, če je orožje že bilo določeno in ga v tem
primeru odstranimo iz lika, da naredimo prostor za novo izbrano orožje. Tukaj kličemo tudi
metodo RemoveStatBonus() iz razreda CharacterStats, da odstranimo bonus statistike, ki
smo jih pridobili z odstranjenim orožjem. Nato smo napisali nekaj pogojnih stavkov, ki
preverijo, ali je orožje za na blizu ali za na daleč, saj se v slednjem primeru mora ustvariti še
izvor za izstrelke. Orožju smo morali na koncu dodati še komponento vmesnika za njegov
nadzor, v katerem smo napisali funkcije ter definirali statistike, ki jih vsebuje. (slika 4.31)
Slika 4.31 Funkcije v skripti PlayerWeaponController.cs
27
Nato smo napisali še funkcijo projectile(), ki se sproži v določenem delu animacije orožja,
kar si bomo ogledali v nadaljevanju pri dogodkih animacij.
Slika 4.32 Funkcija projectile(), ki se kliče v določenem delu animacije.
V funkciji Update() (slika 4.33) preverjamo, ali je bil stisnjen določen gumb na tipkovnici, ki
omogoči, da se sproži napad. Nato je bilo potrebno preveriti še kje se nahaja miška, ker lik
vedno sproži napad v smeri kazalca, saj je bil cilj narediti dinamičen napadalni sistem z
veliko premikanja in napadi. Pri pridobitvi položaja miške smo morali upoštevati
podlago(ang. plane), da se lahko lik obrača le po navpični osi. V primeru, da je želen napad,
se lik obrne proti položaju kazalca in se sproži funkcija PerformAttack(). Morali smo ustaviti
navigacijskega agenta, da se lik ni premikal med napadom. Za obračanje smo uporabili
Quaternion.Lerp, ki interpolira dve vrednosti za določeno številko. Tukaj je nastal problem,
saj smo najprej prožili napad po končani rotaciji, kar pa je trajalo preveliko časa zaradi
interpolacije. To smo rešili s tem, da smo gledali kot in prožili napad, ko je bil ta dovolj
majhen.
Slika 4.33 Prikaz funkcije Update(), ki ob kliku na tipko X sproži napad.
28
4.8 Nasprotniki
Tudi za nasprotnike smo naredili vmesnik in sicer s skripto IEnemy.cs (slika 4.34), kjer smo
definirali funkcijo za prejemanje napada TakeDamage() ter funkcijo za napad
PerformAttack().
Slika 4.34 Vmesnik za sovražnike v skripti IEnemy.cs.
Nato smo lahko napisali skripto Skeleton.cs za sovražnika, kjer smo med drugim definirali
te funkcije. Ta skripta je bila dodana na objekte, ki predstavljajo sovražnika. Najprej je bilo
potrebno deklarirati nekaj spremenljivk:
LayerMask aggroLayerMask: Glavnemu liku smo določili plast (ang. layer), v kateri ga
nasprotniki lahko iščejo, če je spremenljivka LayerMask enaka plasti lika.
Collider[] withinAggroCollider: Polje, ki se polni, če trkalnik najde določen lik.
CharacterStats characterStats: Tudi nasprotnikom smo na enak način kot glavnemu liku
določili lastnosti.
EnemySword enemySword: Instanca skripte za nasprotnikovo orožje.
Bool wanderer: Da lahko v inšpektorju določimo, ali se sovražniki premikajo naokoli ali pa
ostanejo na svoji poziciji do prihoda igralca.
29
Slika 4.35 Del skripte Skeleton.cs, kjer so spremenljivke in funkcija Start().
Najprej smo definirali funkciji (slika 4.36) iz IEnemy.cs. PerformAttack() se sproži ob napadu
in usmeri objekt proti napadenemu liku, saj se včasih lahko zgodi, da navigacijski agent tik
pri koncu poti hoče obiti glavni lik, kar lahko povzroči, da se napad sproži v prazno. Potem
se kliče funkcija iz EnemySword.cs, ki izvede napad. TakeDamage() zmanjša življenjske
točke in ob primeru negativnih točk oz. nič ustavi navigacijskega agenta ter sproži animacijo
smrti.
Slika 4.36 Funkciji PerformAttack() in TakeDamage() v skripti Skeleton.cs.
30
Nato smo napisali funkcijo (slika 4.37) ChasePlayer(), ki se sproži, če je igralec dovolj blizu
nasprotnika. Ko se navigacijski agent dovolj približa glavnemu liku, se začnejo prožiti napadi
s pomočjo InvokeRepeating, ki za argumente prejme ime funkcije, ki se mora ponavljati, čas
začetka ter trajanje intervala med ponovitvami. To vse smo napisali v pogojne stavke, ki
zagotavljajo, da ponavljanje nikoli ni napačno.
Slika 4.37 Funkcija ChasePlayer(), ki omogoča sovražnikom, da sledijo igralcu.
Ker nismo hoteli, da nekateri sovražniki samo stojijo pri miru, preden se jim igralec dovolj
približa, smo v kodo dodali še premike v naključno smer, ki se sprožijo na nekaj sekund.
Določili smo krog okoli lika, v katerem se naključno poišče neka ciljna točka s pomočjo
funkcije RandomNavSphere() (slika 4.38).
Slika 4.38 Funkcija, ki najde naključno točko v določenem krogu.
Na koncu smo morali napisati še Update() (slika 4.39), ki združi vse ostale funkcije, da
nasprotniki pridobijo preprosto umetno pamet. Physics.OverlapSphere išče trkalnike v
določeni plasti in napolni polje withinAggroColliders, ki smo ga deklarirali na začetku. Ob
primeru, da je v tem polju vsaj en objekt, se sproži funkcija za lovljenje igralca. Če smo
hoteli, da določen nasprotnik tava naokoli, smo mu morali prirediti spremenljivko wanderer
31
na logični ja (ang. true) v inšpektorju. V tem primeru lik vsakih nekaj sekund določi nov cilj
s funkcijo RandomNavSphere in se odpravi do tja. Tukaj je nastala težava, ker pot do cilja
nikoli ni bila vrnjena kot izpolnjena in smo zato izračunali dolžino med začetno in končno
pozicijo, kar je omogočilo, da se je animacija za nedejavnost pravočasno vklopila.
Slika 4.39 Funkcija Update() v skripti Skeleton.cs.
Da se napad lahko izvede, smo morali napisati še skripto EnemySword.cs (slika 4.40), ki smo
jo pripeli na orožje sovražnikov. Ker je meč že na začetku pripet na lik, smo lahko v
animacijah brez problemov določili, kdaj se bo vklopil njegov trkalnik, za razliko od
igralčevega lika, kjer se meč doda šele iz inventarja tekom igranja. Ta skripta ima samo
funkcijo za napad, ki se proži v skripti Skeleton.cs ter funkcijo, ki se pokliče ob trčenju. Če je
bil trk z glavnim likom, se temu odbije določeno število življenjskih točk.
32
Slika 4.40 Skripta EnemySword.cs, ki smo jo pripeli na meč nasprotnikov.
4.9 Skripta glavnega lika
Tako kot v diplomski nalogi, je bila tudi skripta Player.cs, ki je bila dodana na glavni lik,
napisana šele proti koncu dela, saj igralcu dolgo ni bilo potrebno skrbeti za napade nad
njim. Čeprav je ta skripta zelo kratka, so se tukaj pojavile največje težave, če vzamemo za
kriterij čas popravljanja. Problem se je pokazal v skripti PlayerWeaponController.cs, ki za
svoje delovanje potrebuje statistike glavnega lika, ki jih inicializiramo v igralčevi skripti. Žal
se te statistike niso pravočasno izdelale pri gradnji (ang. build) igre in jih zato nadzornik
orožij ni mogel poiskati. Zato smo funkcijo Start() spremenili v Awake(), kar je zagotovilo,
da so lahko bile najdene, saj se slednja funkcija sproži hitreje od prve. Če problema ne bi
želeli rešiti na tak način, bi lahko tudi določili, da se Player.cs skripta zgradi pred
nadzornikom, kar lahko naredimo v projektnih nastavitvah Unity v orodni vrstici, s čimer
dosežemo podoben rezultat kot z Awake().
33
Slika 4.41 Del skripte Player.cs, kjer je inicializacija spremenljivk.
Potem smo napisali še skripto TakeDamage() za zniževanje življenjskih točk igralčevega lika,
ki sproži tudi animacijo smrti pod pravim pogojem.
Slika 4.42 Funkcija TakeDamage() v igralčevi skripti.
4.10 Megla vojne
Megla vojne (ang. fog of war) je navadno nujni del izometričnih iger, saj prepreči igralcu
videti vse sovražnike na polju, kar doda k težavnosti igranja. Nekatere igre poleg likov
zakrijejo tudi ves teren, dokler ga ne odkrijemo. Tega pristopa smo se sprva lotili tudi mi in
ga uspešno implementirali, vendar smo se s časom odločili, da je dovolj zakriti zgolj like na
sceni, teren pa pustiti prikazan čeravno malo temneje (slika 4.43).
34
Slika 4.43 Prikaz megle vojne v igri.
Svetlejšo okolico okoli igralca smo dosegli z dvema senčilnikoma [9], prvi, ki naredi temo
po celotni mapi, ter drugi, ki v območju okoli glavnega lika izbriše to temo. (slika 4.44)
Najprej smo naredili nov objekt na sceni in sicer pravokotnik, ki smo ga dodali na kamero,
zato da se tema premika z njo. Nastavljen je malo pred kamero, da zastre njen pogled. Na
ta objekt smo dali prvi senčilnik NotEqualOne, ki naredi temo. Poleg senčilnika smo morali
dodati še material Transparent Diffuse RefNotEqualOne na mrežni upodabljalnik. Nato smo
naredili še en objekt in sicer sfero, na katero smo dodali senčilnik Mask OneZLess ter
istoimenski material. Ta objekt smo dodali na glavni lik, saj se mora premikati skupaj z
igralcem.
35
Slika 4.44 Pravokotnik je nameščen na kamero, krog pa na igralca.
Nato smo morali poskrbeti še za prikaz likov na sceni, saj zatemnitev ni dovolj, da se jih ne
vidi, razen če bi zatemnili preveč, kar pa ni bil želen učinek. Napisali smo dve skripti, eno za
glavni lik, drugo pa za vsak lik, ki ga hočemo skriti ob primeru prevelike razdalje.
Skripta FogOfWarSight.cs (slika 4.45), ki se nahaja na igralčevem liku, vsebuje dve
spremenljivki:
Float radius: Da lahko določimo razdaljo, do koder še lahko vidimo.
LayerMask layerMask: Za določanje plasti za iskanje. Vrednost smo nastavili na -1, kar
pomeni da išče vse plasti.
Slika 4.45 Skripta FogOfWarSighs.cs.
36
V Update() smo uporabili že znano funkcijo Physics.OverlapSphere, ki išče trkalnike likov, ki
jih hočemo skriti oziroma pokazati. Ob primeru trka se pošlje sporočilo najdenemu liku, kar
kliče funkcijo Observed() v skripti FogOfWarVisibility.cs (slika 4.46), ki je pripeta na vsak lik,
ki ga želimo skriti. Tu se v Update() ob prejetju sporočila vklopi upodabljanje, ki prikaže lik.
Dokler se sporočila pošiljajo, je lik prikazan, v nasprotnem primeru se skrije.
Slika 4.46 Skripta FogOfWarVisibility.cs.
Tukaj je nastal manjši problem, ker smo sprva testirali samo s kockami, ki so imele navadno
mrežno upodabljanje (ang. mesh renderer), medtem ko imajo liki iz Unity spletne trgovine
drugačno upodabljanje in je bilo zato potrebno spremeniti tip iz MeshRenderer v
SkinnedMeshRenderer.
37
4.11 Zemljevid
Za igro smo naredili tudi manjšo mapo (ang. minimap), ki s ptičjo perspektivo prikazuje
okolico igralca. To smo dosegli z uporabo kamere in tekstur. Najprej smo ustvarili novo
teksturo (ang. render texture), ki smo jo poimenovali Minimap.
Nato smo na platnu ustvarili nov prazni objekt na katerega smo dodali objekt s komponento
Raw Image, kjer smo vstavili našo teksturo. Potem smo na lik pripeli novo kamero in jo
dvignili visoko v zrak ter usmerili proti tlom. V komponenti te kamere smo za ciljno teksturo
izbrali prej ustvarjeni Minimap, s čimer smo zaključili izdelavo mape (slika 4.47).
Slika 4.47 Izgled mape v igri.
Medtem ko se glavni lik premika, se premika tudi kamera, ki sproti riše svet na teksturo, ki
jo imamo na uporabniškem vmesniku. Lahko tudi določimo, katere plasti bo kamera
zaznala, kar omogoči prikazovanje samo objektov na tistih plasteh.
38
4.12 Glavna kamera
Zadnjo skripto CameraController.cs (slika 4.48) v diplomski nalogi smo napisali za nadzor
glavne kamere, na katero smo skripto tudi pripeli. Najprej smo deklarirali nekaj
spremenljivk za omejitev in hitrost premikov. V funkciji Update() smo napisali pogojne
stavke, ki preverjajo, ali je miška na katerem robu ekrana, kar povzroči spremembo
vektorja. Na koncu se kamera prestavi na novo vrednost, ki je odvisna od tega vektorja. S
koleščkom na miški pa lahko nadzorujemo prikazno polje (ang. field of view).
Slika 4.48 Skripta za nadzor kamere.
39
4.13 Animacije
V oknu Animator (slika 4.49) smo dodali nekaj animacij, ki smo jih poleg njihovih modelov
prenesli iz spletne trgovine.
Slika 4.49 Okno animatorja, kjer so animacije in tranzicije.
Potem smo ustvarili nekaj parametrov (slika 4.50), ki so potrebni za spreminjanje stanj v
animatorju. Če želimo na primer preiti iz mirovanja v zamah z mečem, moramo narediti
tranzicijo med tema dvema stanjema.
Slika 4.50 Parametri, s katerimi se prožijo animacije.
40
Nato lahko v inšpektorju ob kliku na tranzicijo dodajamo pogoje nanjo tako, da izberemo
željeni ustvarjeni parameter. Za igro smo uporabili dve vrsti parametrov in sicer sprožilce
ter logične vrednosti (true, false). V inšpektorju lahko tudi določimo ali se mora trenutna
animacija končati, preden se izvede tranzicija in koliko časa traja preklop med animacijami.
Ob nastanku objekta se najprej sproži privzeta animacija, ki je obarvana z oranžno barvo v
animatorju.
V skripti smo potem lahko napisali pogoje za spremembo stanj oziroma aktivacijo tranzicij.
Na sliki se vidi primer klicanja tranzicij (slika 4.51), kjer se najprej nastavi logična vrednost
prve tranzicije na pozitivno, kar sproži animacijo na katero kaže. Nato se sproži druga
tranzicija in naslednja animacija.
Slika 4.51 Primer klicanja tranzicij v kodi.
V oknu animacij (ang. animation) lahko dodajamo dogodke, katerim določimo funkcije, ki
se kličejo, ko se določen dogodek sproži. Mi smo to naredili pri izstrelitvi puščice, kar se
zgodi šele ko animacija kaže popolnoma napet lok. Na seznam lahko dodajamo tudi lastnine
(ang. property), kar smo mi naredili s trkalnikom za orožje (Slika 4.52), da smo ga lahko
izklopili vse do popolnega zamaha. Na začetku smo ga preprosto izklopili in ga potem na
časovnici vklopili, ko je bila animacija na pravem delu napada.
Slika 4.52 Konec seznama, kamor smo dodali trkalnik.
41
5 DISKUSIJA IN SKLEP
V diplomskem delu smo uspešno preučili razvojno okolje Unity in ga uporabili pri izdelavi
temeljev računalniške igre. V prvem delu smo se seznanili z okoljem in napisali nekaj
primerov iger, ki so nastale v njem. Podrobneje smo si ogledali tudi nekaj pomembnejših
komponent in funkcij, ki smo jih uporabili. Napisali smo skripte, ki so potrebne za delovanje
in jih uspešno uporabili na testni sceni poleg ostalih komponent in objektov. Sproti smo
opisali tudi probleme, ki so nastali, in njihove rešitve. Izdelali smo tudi uporabniški vmesnik
za inventar in pogovore.
Rezultat (slika 5.1) vsega tega je igra z manjšim inventarjem z nekaj predmeti za uporabo.
Omogočeno je premikanje po terenu in napadanje nasprotnika, ki lahko napade nazaj. Na
mapi se lahko vidi okolico igralca in položaj sovražnikov v bližini. Z nekaterimi liki v igri se je
mogoče tudi pogovarjati.
Zaradi zastavitve temeljev je igro preprosto razširiti z novimi objekti in skriptami, ki se jih
da preprosto povezati na izdelano osnovo. Vsako novo orožje lahko uporablja že izdelane
skripte in tudi vsak nov lik potrebuje le manjšo nadgradnjo glede animacij saj se te lahko
med različnimi modeli razlikujejo. Z uporabo inventarja se lahko naredi tudi preprost sistem
nalog, ki jih mora igralec izpolniti, da lahko nadaljuje igro.
Ker smo se že z naslovom diplomske naloge odločili podrobneje predstaviti tudi probleme
pri razvoju, smo večino teh opisali že sproti. Eden večjih problemov, ki ga nismo opisali, je
bil nadgradnja razvojnega okolja Unity v novejšo različico, saj je to povzročilo, da se scena
ni pravilno zgradila. Posledično smo preprosto prešli na starejšo različico na kateri se je
začel razvoj naše igre. Za izogib ti težavi je priporočeno, da se tekom razvoja vedno
uporablja ista verzija razvojnega okolja. Razen teh problemov z združljivostjo je Unity
odlično okolje za razvoj računalniških iger že v njegovi zastonjski obliki.
Skozi šolanje smo pridobili večino znanja, ki je bilo uporabljeno pri izdelovanju te diplomske
naloge, saj smo podrobno spoznali programski jezik C# ter tudi uporabo modelov in
animacij. Ob primeru, da bi se odločili za izdelavo lastnih tekstur, bi lahko nastala težava,
saj tekom šolanja nismo podrobneje spoznali programov za njihovo izdelavo.
42
Slika 5.1 Scena iz igre.
43
6 VIRI
[1] Unity Asset Store: AxeyWorks. Low Poly: Free Pack. Dostopno na:
https://www.assetstore.unity3d.com/#!/content/58821. [24. 5 2017]
[2] Unity Documentation: Coroutines. Dostopno na:
https://docs.unity3d.com/Manual/Coroutines.html. [28. 7 2017]
[3] Unity Asset Store: Female Warrior Princess. Dostopno na:
https://www.assetstore.unity3d.com/en/#!/content/44041. [24. 6 2017]
[4] Youtube: Gregory, A. Gamegrind. Dostopno na:
https://www.youtube.com/user/AwfulMedia/videos. [5. 5 2017]
[5] GitHub: Gregory, A. GameGrind/Json.Net.Unity3D. Dostopno na:
https://github.com/GameGrind/Json.Net.Unity3D. [26. 7 2017]
[6] Wikipedia: List of Unity games. Dostopno na:
https://en.wikipedia.org/wiki/List_of_Unity_games. [1. 8 2017]
[7] Unity Documentation: MonoBehaviour.Awake(). Dostopno na:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Awake.html. [28. 7 2017]
[8] Unity Asset Store: MonsterSnail. MOBA Game Witch Doctor. Dostopno na:
https://www.assetstore.unity3d.com/en/#!/content/59073. [28. 7 2017]
[9] Youtube: PushyPixels. Breakfast With Unity: Radial Fog of War Part 2. Dostopno na:
https://www.youtube.com/watch?v=sfI2fabWNEQ. [20. 7 2017]
[10] Unity Documentation: Rigidbody. Dostopno na:
https://docs.unity3d.com/ScriptReference/Rigidbody.html. [31. 8 2017]
[11] Unity Asset Store: Teamjoker. Fantasy Monster - Skeleton. Dostopno na:
https://www.assetstore.unity3d.com/en/#!/content/35635. [25. 6 2017]
[12] Wikipedia: Unity (game engine). Dostopno na:
https://en.wikipedia.org/wiki/Unity_(game_engine). [28. 7 2017]