You are on page 1of 43

UNIVERZITET U NIŠU

PRIRODNO-MATEMATIČKI FAKULTET
DEPARTMAN ZA RAČUNARSKE NAUKE

Master rad

Virtuelna realnost: Osnove i izrada igara

Mentor: Student:
Prof. dr Marko D. Petković Filip Stojanović
br. Indeksa 79

Niš, 2017
Virtuelna realnost: Osnove i izrada igara

Sadrţaj

1. Uvod.………………………………………………………………………..2
1.1. Šta je Virtuelna realnost?...........................................................................2
1.2. Istorija i razvoj Virtuelne realnosti………………………………………3
1.3. Tipovi naočara (Head-Mounted Display)………………………………..3
1.4. Razlika izmeĎu VR, AR i MR…………………………………………...4
1.5. Igre i aplikacije…………………………………………………………..5
2. Unity, Oculus I Virtuelna realnost………………………………….....6
2.1. Šta je Unity?..................................................……………………………6
2.2. Šta je Oculus?..………………………………………………………….6
2.3. Mobile VR principi………………………………………………………7
2.4. Optimizacija…………………………………………………………….8
2.5. Kretanje…………………………………………………………………9
2.6. Interakcija igrača………………………………………………………..9
2.7. Korisnički interfejs……………………………………………………...9
3. Novi projekat…………………………………………………………..…11
3.1. Kreiranje projekta………………………………………………………11
3.2. Editor i layout…………………………………………………………..12
3.3. Podešavanja projekta………………………………………………...…13
4. Projekat "VR Master"…………………………………………………...14
5. Prirodno-matematički fakultet – prezentacija u 360 stepeni………….……16
5.1. Postavljanje slika……………………………………………………….17
5.2. Kretanje korisnika……………………………………………………...17
5.3. Podaci o kabinetima i profesorima……………………………………..19
5.4. Firebase skladište……………………………………………………….19
5.5. Parsiranje XML-a………………………………………………………22
5.6. Dinamičko kreiranje liste………………………………………………23
6. VR Survival Shooter igra……………………………………………….26
6.1. Igrač………………………………………………………………….…26
6.2. Pojačanja igrača (power up)……………………………………………30
6.3. Neprijatelji…………………………………………………………...…33
7. Oculus prodavnica I developer konzola……………………………...38
8. Zaključak……………………...…………………………………………..39
9. Literatura……………………………...…………………………………..40

1
Virtuelna realnost: Osnove i izrada igara

1. Uvod

Stalni razvoj računara i informacionih tehnologija omogućuje realizaciju i


pojavljivanje mogućnosti koje ranije nisu bile moguće. Jedan primer toga je i razvoj
Virtuelne realnosti.
Cilj ovog rada je upoznavanje osnova Virtuelne realnosti, skraćeno VR. Pored istorije
i osnova virtuelne realnosti, obratićemo paţnju na razvoj igara i aplikacija u okruţenju za
razvoj igara Unity. Rad će uz primere proći kroz izradu projekta, od kreiranja novog do
njegove objave na Oculus store.

1.1. Šta je Virtuelna realnost?

Reality is merely an illusion, albeit a very persistent one.


-Albert Einstein
Svedoci smo širenja Virtuelne realnosti, uzbudljive nove tehnologije koja obećava
promenu načina na koji interagujemo sa informacijama, prijateljima i svetom. To je medijum
sa ogromnim potencijalom. Mogućnost da se korisnik transportuje na neko drugo mesto,
potpuno uroni u iskustvo i oseća se kao da je stvarno prisutan, otvara nezamislive potencijale.
Razvoj tehnologije doprineo je tome da VR ureĎaji budu pristupačni mnogobrojnim
korisnicima.
Virtuelna realnost je kompjuterski generisana simulacija 3D prostora koja je korisniku
dočarana veoma realno koristeći opremu sa senzorima za prostor. Cilj ove simulacije je
stvaranje jakog osećaja prisutnosti u virtuelnom okruţenju. Današnja VR oprema uključuje
"head-mounted display"(HMD) - naočare za gledanje stereoskopskih 3D scena. Stereoskopija
je tehnika kreiranja iluzije dubine na slici. Prikazuju se dve slike, za oba oka po jedna, koje su
malo pomerene u stranu. Korisnik moţe gledati okolo pomeranjem glave i hodati
korišćenjem ručnih kontrola i senzora za pokret. Potrošački hardver je nov i još se razvija.
MeĎutim, nekoliko platformi je napravilo ureĎaje pristupačne korisnicima. Neki od njih su
Oculus Rift, HTC Vive, Samsung Gear VR, Google Cardboard i Google Daydream.
Efekat virtuelne realnosti se postiţe "varanjem" ljudskog mozga, konkretno vizuelnog
korteksa i delova mozga za percepciju pokreta. Mnoštvo tehnologija je uključeno u pravljenju
ove iluzije kao što su:
 Stereoskopski ekrani. Poznati i kao 3D ekrani ili HMD kombinuju dve slike, optičku
distorziju i specijalna sočiva da naprave stereo sliku koju naš mozak interpretira kao
trodimenzionalnu sliku.
 Hardver za praćenje pokreta. Ţiroskopi, akselerometri i ostale komponente se
koriste da prate pokrete tela i okrete glave kako bi aplikacija osveţila sliku u 3D
prostoru.
 Uređaji za unos. Virtuelna realnost je donela potraţnju za ureĎajima za unos koji su
van domašaja tastature i miša. To su kontroleri i senzori za ruke i telo koji mogu da
prepoznaju pokrete i gestove.
 Desktop i mobilne platforme. Ovde spadaju kompjuterski hardver, operativni
sistemi, softver za interfejs ureĎaja i softveri za pravljenje igara.

2
Virtuelna realnost: Osnove i izrada igara

1.2. Istorija i razvoj Virtuelne realnosti

Virtuelna realnost je prisutna već decenijama i bila je korišćena u istraţivačke,


industrijske i vojne svrhe. U početku je bila jako glomazna i skupa.
U ranim devedesetim godinama pojavile su se prve stereoskopske slike i ureĎaj
"View-Master" (1939) koji je korišćen u turističke svrhe (slika 1.1). Taj koncept se koristi za
današnji Google Cardboard. Ivan Sutherland je 1965. godine napravio prvi HMD pod
imenom "The Ultimate Display". UreĎaj je bio veliki i isuviše teţak da bi ga korisnik sam
nosio. Zato je bio zakačen za plafon, a korisnik bi morao da bude vezan za ureĎaj. Nakon
toga bilo je nekoliko ureĎaja koji su bili ili preskupi ili neuspešni (EyePhone HRX $49.000,
SEGA VR Glasses, Nintendo Virtual Boy).

Slika 1.1: The Ultimate Display

Palmer Lakej i Dţon Karmaksu pokrenuli kikstarter i objavili Oculus Rift


Development Kit 1 (DK1), komplet za razvoj virtuelne realnosti. Marta 2014. godine
Fejsbuk je otkupio kompaniju za dva biliona dolara. Paţnja i novac koji su privučeni otvorili
su novu kategoriju potrošačkih proizvoda. Nakon toga Google, Sony, Samsung i Steam su
objavili svoje proizvode.
Danas na trţištu imamo neke od poznatijih VR ureĎaja kao što su: Oculus Rift 2, HTC
Vive, Playstation VR, Google Cardboard i Daydream i Samsung Gear VR. Iskustvo koje
pruţaju ovi ureĎaji se razlikuju, kao i njihove cene. UreĎaji su redom prikazani na slici 1.2.

Slika 1.2: VR uređaji

1.3. Tipovi naočara (Head-Mounted Display)


Trenutno postoje dva tipa HMD-a za virtuelnu realnost. To su desktop VR i mobile
VR. Svi HMD su povezani sa nekim ureĎajem, računarom, konzolom ili mobilnim
telefonom.

3
Virtuelna realnost: Osnove i izrada igara

 Desktop VR. Ovde spadaju HMD ureĎaji koji su povezani kablovima na računare ili
konzole koje imaju jače grafike. Igra se pokreće na mašini a prikazuje se na HMD-u.
Ovde spadaju Oculus Rift, HTC Vive i Playstation VR.
 Mobile VR. Najjednostavniji primer mobile VR-a je Google Cardboard, jednostavno
kućište (obično od kartona) sa dva sočiva i mestom za mobilni telefon. Telefon
prikazuje dva stereografska prikaza i ima senzor za rotaciju glave, ali ne i za poziciju.
TakoĎe postoji i dugme za klik kojim korisnik interaguje sa aplikacijom. Kvalitet i
performanse su ograničene, jer aplikaciju pokreće procesor telefona. Pored Google
Cardboard-a ovde spadaju i Samsung Gear VR i Google Daydream.

1.4. Razlika izmeĎu VR, AR i MR


Pojmovi Virtual Reality i Augmented Reality se često mešaju. Kod VR-a korisnik
je "prebačen" u virtuelni svet i kroz naočare ga vidi kao pravi svet. Augmented Reality
(proširena realnost), skraćeno AR nadograĎuje kompjuterski generisanu grafiku u realan svet.
Primeri ovoga se mogu videti na mobilnim telefonima, tabletima i nekim ručnim konzolama
kao što je Nintendo 3DS. Jedna od najpoznatijih igara je Pokemon Go (slika 1.3). Pored toga,
AR se koristi i u muzejima.

Slika 1.3: Pokemon Go

Najnoviji je pojam MR ili Mixed Reality. Microsoft je predstavio novi ureĎaj


HoloLens, naočare koje povezuju VR i AR i prikazuje nadograĎenu grafiku direktno u
korisnikovom vidnom polju (slika 1.4).

Slika 1.4: HoloLens

Sve tri oblasti obećavaju dosta toga u budućnosti, ali različitog. Dok AR angaţuje
korisnika da interaguje sa trenutnom okolinom, virtuelna realnost u potpunosti uranja u novu
okolinu i iskustvo. U AR moţete na svom stolu stvoriti plan neke kuće, okretati ga i studirati,
dok u VR moţete ući u tu kuću i kretati se njom. HoloLens će omogućiti povezivanje ove dve
stvari tako što će korisnik trenutno okruţenje moći da pretvori u nešto sasvim novo po ţelji.

4
Virtuelna realnost: Osnove i izrada igara

1.5. Igre i aplikacije


Iako je virtuelni svet još uvek nov, razvoj aplikacija je sve brţi. Developeri prave
mnogo aplikacija za virtuelnu realnost i to dosta uspešno. Potrošački nivo VR-a zasniva se na
gejmingu. Gejmeri najbolje prihvataju nove tehnologije i brzo se navikavaju na njih.
Masovna produkcija konzola za igranje i računarskih komponenti dovodi do brţeg razvoja
tehnologije i pada cena. Iz tog razloga veći deo kompanija koje se bave virtuelnom realnošću
za ciljnu grupu imaju gejming. Već danas se dosta igara mogu naći na Google Play-u i
Oculus storu.
ProizvoĎači igara moraju prilagoditi igre virtuelnoj realnosti tako što će mehanike
igara kao što su puzle, verovatnoća, strategije, tajming i memorija mišića (trzaji),
modifikovati i primeniti u svoje igre. Mehanike u običnim i VR igrama ne mogu biti
identične, npr. kretanje karaktera u običnoj igri je 1.5 puta brţe nego u stvarnom svetu jer bi
normalno kretanje korisniku bilo isuviše sporo i igra bi bila dosadna. Ako se to isto kretanje
primeni u VR igri, bilo bi isuviše brzo i izazvalo bi mučninu kod igrača, jer ljudski mozak
nije navikao na toliko brzo kretanje. Za brţe kretanje u VR se koriste drugi principi koje
ćemo videti kasnije u radu. MeĎutim, koliko god se mehanika prilagodila virtuelnoj realnosti,
ne mogu se sve igre prebaciti u nju. Na primer mali broj igrača bi se osećao prijatno da se
naĎe u sred ratne zone kao jedan od vojnika.

Osim gejminga, virtuelna realnost se primenjuje i u drugim oblastima. Ove aplikacije


se razlikuju od igara tako što akcenat bacaju na sam doţivljaj i iskustvo umesto na mehaniku
igara. Neke od tih kategorija su:
 Turizam - Korisnik moţe posetiti daleka mesta bez izlaska iz kuće. Stereoskopske
360 panorame su veoma privlačne i predstavljaju jednostavan i efikasan način da se
doţivi iskustvo kao da ste na nekom drugom mestu.
 Arhitektura i nekretnine - Arhitekte i agenti za nekretnine mogu koristiti 3D modele
u virtuelnoj realnosti kako bi klijentima vernije dočarali svoje projekte kupcima.
 Medicina - Potencijal VR-a u medicini je veliki. Svakoga dana skenerima se prave
modeli ljudskog tela koji se koriste za dijagnoze i planiranje operacija. Korišćenje
virtuelne realnosti bi poboljšalo preglednost modela.
 Edukacija - 3D vizuelizacija i interaktivno učenje pomaţe učenicima i studentima
svih uzrasta. Jer je samo iskustvo dosta bolji način učenja u odnosu na knjigu.
 Industrija - Programi kao što su AutoCAD i SOLIDWORKS mogu napraviti 3D
modele i simulacije objekata. Uz VR inţenjeri i dizajneri mogu doći u dodir sa
proizvodom i pre nego što on bude napravljen.
 Treninzi - Postoje simulacije voţnje i upravljanje teškim mašinama koje
omogućavaju korisnicima da steknu potrebno iskustvo pre nego što sednu za volan.
Na taj način dolazi do smanjenja rizika od slučajnih nezgoda pri pravoj obuci.
 Zabava - Sve više dogaĎaja širom sveta se prenosi uţivo kamerama koje snimaju svih
360 stepeni. Uz VR naočare korisnik moţe doţiveti koncert ili neki drugi dogaĎaj iz
svoje kuće.
Ovo je samo deo aplikacija koje su prisutne u virtuelnom svetu. Što se daljeg razvoja
tiče ne moţemo ni pretpostaviti u kom smeru će se aplikacije i igre kretati i šta će preovladati
na trţištu.

5
Virtuelna realnost: Osnove i izrada igara

2. Unity, Oculus i Virtuelna realnost


Igre za virtuelnu realnost se prave u Unity3D i Unreal Engine. U ovom radu ćemo
videti osnovne koncepte i opis razvoja VR igre u Unity-u. Svaki od HMD-a koristi svoj SDK
(Sofrware Development Kit) ali su principi isti za sve. Veoma je bitna optimizacija grafike i
koda da bi igra radila na konstantnih 60fps (frame per second) jer je to najlagodnije za
ljudsko oko. Oculus store ne prihvata igre koje rade na manje od te vrednosti. Osim
optimizacije u radu su prikazani i načini kretanja, interakcija sa objektima i vrste korisničkog
interfejsa.

2.1. Šta je Unity?


Unity je game engine koji podrţava izradu 2D i 3D igara za 21 platformu meĎu
kojima su Android, Gear VR, Google Cardboard i Daydream, iOS, macOS, Oculus Rift, Play
Station, Tizen, Windows itd. Pisanje skripti je bilo moguće u C#, Boo i UnityScript, ali su
druga dva izbačena iz upotrebe. Uz instalaciju Unity-a se dobija Monodevelop koji se koristi
za pisanje skripti, ali se umesto njega moţe koristiti i Microsoft Visual Studio. Pri instalaciji
VS 2017 moţe se izabrati posebna opcija za razvoj Unity igara koja uključuje dodatne alate
za lakši i brţi rad.

2.2. Šta je Oculus?


Oculus je američka kompanija specijalizovana za izradu hardvera i softvera za
virtuelnu realnost. Osnovana je 2012. godine i iste godine su napravljena dva Rift modela za
developere, Oculus VR DK1 (Development Kit) i Oculus VR DK2. Tek 2016. godine je
napravljen novi model za trţište sa specijalnim VR displejima, audio sistemom i sistemom za
praćenje pokreta, koji se zove Oculus Rift. U martu 2014. Mark Cukerberg je otkupio Oculus
VR kompaniju za 2.3 biliona dolara. A kasnije, novembra 2015. godine, kompanija je
sklopila partnerstvo sa Samsungom i počela proizvodnju Samsung Gear VR za Samsung
Galaxy ureĎaje. Danas postoje tri Samsung Gear VR ureĎaja. Prvi je bio Samsung Gear VR
Innovator Edition i bio je namenjen prvim developerima. Drugi model koji je bio namenjen
za prodaju bio je beo sa touch-pad, back dugmetom i dugmićima za zvuk. Treći i poslednji
model je malo unapreĎen i uz njega se dobija Gear VR Controller. Modeli su prikazani na
slici 2.1 redom.

Slika 2.1: Samsung GearVR uređaji

6
Virtuelna realnost: Osnove i izrada igara

Oculus trenutno ima dve onlajn prodavnice za skidanje igara i aplikacija. Posebna
prodavnica je za Rift a posebna za Gear VR jer je hardver telefona dosta slabiji od računara
pa samim tim su i igre za Samsungov Gear VR dosta slabije. Prodavnica za Gear VR iz
samog ureĎaja je prikazana na slici 2.2.
Iako su principi programiranja za svaki head-mounted display slični, za svaki od njih
potreban je poseban development kit koji se uključuje u Unity. Oculus ima poseban SDK za
Rift i Gear VR. Počev od Unity verzije 5.1, Oculus SDK je uključen u ovaj game engine pa
developeri mogu praviti igre za Oculus prodavnice bez dodatnog skidanja SDK.

Slika 2.2: Gear VR Oculus prodavnica

2.3. Mobile VR principi


Izrada igara za virtuelnu realnost za mobilne telefone je malo zahtevnija nego za
računare, jer je veoma bitno da se sve optimizuje kako bi igre nesmetano radile. Postoje neki
principi koji se moraju ispoštovati kako bi se korisnici osećali prijatno pri korišćenju igre ili
aplikacije. Oculus store vodi računa o tim principima i pre objavljivanja aplikacija prolazi
kroz detaljan pregled kako bi se proverilo da li ona zadovoljava sve standarde.
Svaka Oculus VR aplikacija ima životni ciklus koji se moţe pratiti na Oculus
dashboard-u i prikazana je na slici 2.3.

Slika 2.3: Životni ciklus VR aplikacije

7
Virtuelna realnost: Osnove i izrada igara

Za svaki od ovih koraka Oculus nudi smernice koje developeri trebaju pratiti kako bi
njihov proizvod bio zadovoljavajuć i kako bi prošao test i proveru. Smernice su podeljene u
pet kategorija i to su kompatibilnost, funkcionalnost, grafika i performanse, bezbednost i
interakcija korisnika.
 Kompatibilnost osigurava da aplikacija ostane kompatibilna sa Oculus-ovim
bibliotekama i da developer vodi računa o hardverskim specifikacijama koje Oculus
preporučuje. UreĎaji koji trebaju biti podrţani su svi Samsung S modeli od S6 do
najnovijeg S8 i Note 4 i 5 modeli. C i C++ aplikacije moraju biti pisane da podrţavaju
Oculus SDK 1.60 i noviji. Tu su i preporučene verzije Unity game egine na kojima
kojima Oculus SDK radi. Developer mora koristiti jednu od tih verzija kako bi Oculus
SDK funkcionisao.
 Funkcionalnost obezbeĎuje da aplikacija funkcioniše po Oculus-ovim standardima.
Igre za jednog igrača se moraju pauzirati kada igrač skine HMD ili se vrati u
univerzalni meni takoĎe aplikacija ne sme iscrtavati frejmove niti prihvatati unos.
Igrač nikada ne sme biti "zaglavljen" u aplikaciji, npr. kod ekrana za login mora
postojati opcija za kreiranje naloga. Ukoliko aplikacija zahteva internet a njega nema,
korisnik se mora obavestiti o njegovoj potrebi. Aplikacija ne sme izgubiti snimljene
podatke korisnika.
 Grafika i performanse su veoma bitni u VR igrama. Ako je grafika loša ili igra
sporo radi, korisniku moţe biti neprijatno i moţe osetiti mučninu. Aplikacija mora
raditi na 60fps konstantno inače će se korisnik osećati nelagodno. Više o "ceĎenju
performansi" za Unity VR igre za telefone moţe se naći na adresi -
https://developer.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-
game/. Aplikacija mora raditi bez zamrzavanja i pucanja. Pri pokretanju aplikacije
scena se mora pojaviti u roku od 4 sekunde, u suprotnom treba da se obezbedi loading
ekran. CPU i GPU (Central & Graphics processing unit - procesor i grafčki čip) se
moraju koristiti najefikasnije kako se telefon ne bi pregrevao i brzo potrošio bateriju.
 Bezbednost traţi da se zaštite privatnost i integritet Oculus-ovih i korisnikovih
podataka. Aplikacija mora zahtevati minimalan broj permisija za funkcionisanje.
Ukoliko se neki podaci šalju eksternom servisu korisniku se to mora naglasiti.
 Interakcija korisnikamora biti po Oculus-ovim standardima. Back i home dugme
moraju funkcionisati uvek isto kao što Oculus nalaţe. Ukoliko aplikacija zahteva
kontroler, korisniku se to mora napomenuti. Ako je kontroler podrţan, korisnik mora
da ima opciju da bira izmeĎu kontrolera i touch pad-a. TakoĎe aplikacija mora
detektovati da li se kontroler nalazi sa leve ili desne strane.

2.4. Optimizacija
Kod VR igara optimizacija je veoma vaţna, pogotovu ako je to igra za Gear VR.
Postoje razni trikovi koji mogu pomoći u optimizaciji igara. Jedan od njih je static batching.
Svi objekti na sceni koji se ne pomeraju mogu biti označeni kao statični i tada će ih Unity
iscrtavati kao jedan objekat. Još je bolje da ti objekti koriste jedan materijal jer za svaki
materijal na sceni Unity pravi jedan draw call (poziv za crtanje). Maksimalni broj draw call-
ova na sceni treba biti 50. Ovde se moţe koristiti texture atlasing, jedna velika tekstura koja
u sebi sadrţi teksture svih statičnih objekata i ona se postaviti kao materijal za sve objekte.
Nakon toga se objekti mapiraju i označava se koji deo teksture da koriste.
Dobar level dizajn moţe dosta optimizovati igru. Npr. ukoliko se igrač kreće iz sobe
u sobu, loša praksa je učitati sve sobe na početku, već ih treba učitavati pri ulasku igrača u

8
Virtuelna realnost: Osnove i izrada igara

nju. Loša strana toga je što bi se onda koristilo više memorije pri učitavanju svakog objekta.
Zato je najbolje sobe odvojiti po nivoima i asinhrono ih učitavati po potrebi iz koda.
Asoinhrono učitavanje nivoa je veoma korisno ukoliko igra ima velike nivoe. Pre
nego što igrač napusti jednu sobu, sledeća se moţe učitati asinhrono sa
Application.LoadLevelAsync().
Ukoliko se nivo učita klasično bez asinhronog učitavanja, igra će se zamrznuti dok se sledeći
nivo ne učita.
Bejkovanje svetla je veoma vaţno ne samo u VR igrama. Svim statičnim objektima
mogu se isključiti realtime senke i nakon toga bejkovati osvetljenje. Na taj način pravi se
tekstura sa senkama koja se iscrtava statično umesto "ţivih" senki koje se iscrtavaju u
svakom frejmu.

2.5. Kretanje
Kretanje je veoma vaţan faktor koji uslovljava zadovoljstvo igrača. Ukoliko u igri
postoji neki način kretanja on mora biti što pribliţniji prirodnom. U suprotnom kod igrača se
javlja mučnina koja se drugačije zove VR bolest. Javlja se zbog toga što je telo igrača u
pravom svetu statično dok se u virtualnom svetu kreće. Najbolje je izbegavati kretanje osim
ako ono ne kopira pravo kretanje igrača jer moţe uticati na vestibularni sistem (sistem organa
za ravnoteţu).
Kod klasičnih igara u prvom licu često se javlja mučnina, zato je najbolje izbegavati
ih. Ako developer ipak odluči za ovaj tip igre najbolje je testirati kretanje sa što više
korisnika. Jedno rešenje za FPS igru je pravljenje konstantne statične vizuelne reference kao
što je kokpit, kabina ili unutrašnjost auta.
Popularna metoda kretanja je Fade/Blink tranzicija. Igrač se kreće sa jedne pozicije
na drugu tako što se kamera brzo zamrači da korisniku ispred očiju bude samo crna boja,
nakon toga se kamera pomeri na novu poziciju i crna boja se skloni. Ovo je jedan od
najprijatnijih i najjednostavnijih načina kretanja igrača.

2.6. Interakcija igrača


U zavisnosti od modela Gear VR-a, same igre i izbora igrača, kontrole se mogu vršiti
sa samog HMD-a ili sa kontrolera. I na ureĎaju i na kontroleru se nalazi touch-pad na koji se
moţe kliknuti ili prevlačiti. Prevlačenje se detektuje u četiri smera gore (napred), dole
(nazad), levo i desno.
Neke igre imaju i gaze kontrolu koja funkcioniše na sledeći način: kada igrač pogleda
u neki predmet koji je predefinisan za interakciju, ispred njega se pojavljuje krug koji se
popunjava sekundu ili dve (vreme zavisi od developera) i nakon toga se registruje kao da je
igrač kliknuo. Ukoliko za vreme popunajvanja kruga igrač skloni pogled sa predmeta, krug se
sklanja i tajmer se resetuje.

2.7. Korisnički interfejs


Pri pravljenju korisničkog interfejsa za VR igre postoje stvari koje treba uzeti u
obzir,a ne koriste se pri izradi klasičnih igara. Postoje tri vrste korisničkih interfejsa koji se
obično koriste i to su non-diegetic, diegetic i spatial.

9
Virtuelna realnost: Osnove i izrada igara

Kod običnih igara koje nisu VR, interfejs se nalazi preko svega na ekranu i zove se
HUD (Heads Up Display). To je non-diegetic interfejs, interfejs koji se ne nalazi u sklopu
sveta, ali ima smisla za igrača kao posmatrača igre. To su obično energija igrača, rezultat itd.
Pojam diegetic je preuzet iz filmske industrije gde je non-diegetic zvuk pozadinska muzika u
nekom filmu ili TV emisiji, a diegetic zvuk bi bio neki razgovor npr. Primer non-diegetic
interfejsa moţemo videti u igri World of Warcraft gde su magije, razgovori, energija i mapa
na samoj kameri (slika 2.4).

Slika 2.4: World of Warcraft non-diegetic interface Slika 2.5: Forza 4 spatial interface

Spatial ili prostorni korisnički interfejs bi bio interfejs koji se nalazi u samom svetu
igre. To moţe biti glavni ili neki pomoćni meni u igri kao u igri Forza 4 (slika 2.5). Kod ovog
interfejsa veoma je bitno obratiti paţnju na udaljenost od korisnika. Ukoliko je isuviše blizu,
korisnik će naprezati oči, a ako je isuviše daleko činiće se kao da je fokus na horizontu.
Najbolje je pozicionirati interfejs na razdaljini od par metara od korisnika, i skalirati slike i
tekst da budu vidljive i prijatne za čitanje.
Developeri obično u početku korisnički interfejs lepe za kameru tako da se ostane na
fiksnoj poziciji dok se igrač kreće. To moţe biti korisno za neke manje stvari u interfejsu, dok
će velike stvari stvoriti utisak kao da sve vreme drţite novine ispred lica pokušavajući da
gledate naokolo što moţe dovesti do nelagodnosti.

Slika 2.6: Dead Space diegetic interface

Alternativa za prostorni korisnički interfejs je postavljanje elemenata interfejsa u


samo okruţenje. To moţe biti pravi sat na zidu, TV, računar, mobilni telefon ili čak ekran na
futurističkoj puški. Primer diegetic korisničkog interfejsa moţemo videti u igri Dead Space
(slika 2.6) u kojoj se energija igrača nalazi na samom odelu na njegovim leĎima.
Ove vrste korisničkih interfejsa se naravno mogu kombinovati u igrama. Neke od njih
kao i neke od pomenutih principa videćemo kroz primere u projektu koji je u sklopu rada.

10
Virtuelna realnost: Osnove i izrada igara

3. Novi projekat

Za izradu jedne VR igre za Samsung Gear VR potrebne su sledeće komponente:


Unity game engine, Android SDK i Oculus nalog.
Android SDK se ne moţe instalirati samostalno već se automatski instalira uz
Android Studio. Instalacija je jednostavna i moţe se skinuti sa adrese
https://developer.android.com/studio/index.html.
Unity instalacija je takoĎe besplatna i moţe se naći na adresi https://unity3d.com/get-
unity/download. Za izradu ovog projekta korišćena je Unity verzija 5.6.1p1. Vidljive razlike
izmeĎu besplatne i plaćene verzije Unity-a je splash screen na kome piše "Made with Unity",
koji se u besplatnoj verziji ne moţe skloniti i boja okruţenja. Postoje dve teme u Unity-u
Light i Dark, drugu verziju mogu koristiti samo korisnici koji imaju plaćenu verziju.
Što se Oculusa tiče postoje dve opcije za login. Moţe se napraviti novi nalog na
njihovom developer sajtu na adresi https://secure.oculus.com/sign-up/ ili se moţe ulogovati
preko facebook naloga.

3.1 Kreiranje projekta


Pri pokretanju Unity programa otvara se prozor za kreiranje novog ili otvaranje
postojećeg projekta (slika 3.1).

Slika 3.1: Unity New Project

Klikom na "Projects" prikazuje se lista postojećih projekata i odabirom nekog od njih


Unity učitava potrebne fajlove i otvara projekat. Odabirom opcije "New" otvara se
ProjectWizard koji nudi opcije kao što su ime projekta, njegova lokacija i dodatni asseti koji
mogu biti učitani pri samom kreiranju. Asseti u Unity-u predstavljaju sve stavke koje se
mogu koristiti u projektu. Dosta bitna stvar pri kreiranju projekta je da ni njegovo ime ni
putanja nemaju razmak u imenu, u suprotnom neke biblioteke kao što je Firebase koji se
koristi u ovom projektu neće funkcionisati. U ovom slučaju izabraćemo 3D opciju jer su sve

11
Virtuelna realnost: Osnove i izrada igara

VR igre u 3D svetu, a assete učitati naknadno iz Unity editora. Klikom na "Create project"
Unity kreira sve potrebne fajlove za projekat i otvara Unity editor (slika 3.2).

Slika 3.2: Unity Editor

3.2. Editor i layout


Unity Editor se sastoji iz više prozora koje koristimo pri izradi igara. Prozori (views)
se mogu skalirati, pomerati i odvojiti iz programa. U gornjem levom uglu nalazi se padajuća
lista Layout, gde se mogu izabrati predefinisana podešavanja za Editor. Editor je središte
kreiranja projekta u kome dizajneri i programeri rade zajedno. Najbolje je da programer sam
podesi layout kako bi se lakše snalazio. Pri radu sa dva monitora pogodno je da se Game
prozor odvoji na drugi monitor kako bi pregled igre bio veći.
Game prozor sluţi za testiranje aplikacije. U njemu se vidi sve ono što kamera na
sceni vidi za razliku od Scene prozora. U ovom prozoru moţemo podesiti Aspect Ratio
(odnos širine i visine ekrana) kako bi mogli da testiramo igru za više ureĎaja. Scale uvećava
prikaz koji kamera vidi, dok opcija Maximize on Play povećava Game prozor preko celog
ekrana pri pokretanju igre. Mute Audio gasi zvuk igre, a Stats otvara prozor u kome se moţe
pratiti statistika igre za zvuk, grafiku i mreţu.
U Scene prozoru se za razliku od Game prozora moţemo slobodno kretati. U ovom
prozoru vidimo 3D svet naše igre. Ovde razvijamo vizuelni deo igre prevlačenjem objekata
na scenu i njihovim podešavanjem.
Sve objekte koje prevučemo na scenu moţemo videti izlistane u Hierarchy prozoru.
Ovde se vide svi objekti bilo da su upaljeni ili ugašeni. Lista funkcioniše na principu Parent-
Child tako da svaki objekat moţe imati druge objekte kao svoju decu (pod objekte).
Klikom na neki od objekata u Inspector prozoru dobijamo njegov detaljan opis: ime,
poziciju, rotaciju, veličinu i ostale komponente ukoliko one postoje na tom objektu. TakoĎe,
iz ovog prozora se mogu dodavati nove komponente.
U Project prozoru vidimo hijerarhiju projekta sa svim folderima i fajlovima koji se
nalaze u njemu. Korisnik sam pravi hijerarhiju i smešta objekte, skripte, teksture i ostale
fajlove u foldere. Iako korisnik moţe sam da pravi hijerarhiju kako mu odgovara, poţeljno je
fajlove podeliti u kategorije i koristiti hijerarhiju sa slike 3.3.

12
Virtuelna realnost: Osnove i izrada igara

Slika 3.3: Hijerarhija

3.3. Podešavanja projekta


Kod projekata za virtuelnu realnost bitna je maksimalna optimizacija da bi igra
funkcionisala nesmetano na 60fps.
Jedno od podešavanja je Quality Settings (slika 3.4) do koga dolazimo iz menija Edit
> Project Settings > Quality. U koloni za Android sklonićemo sva podešavanja osim Fast, jer
nam je bitno da igra radi "brzo". Pored toga na ovoj strani uključujemo i Anti Aliasing da bi
grafika bila bolja, tj. da ne bi imala izlomljene ivice.

Slika 3.4: Quality Settings Slika 3.5: Build Settings

Sledeća stvar koju trebamo uraditi je promena platforme. Pri kreiranju novog projekta
podrazumevana platforma je PC, Mac i Linux. U meniju File > Build Settings moţemo
izabrati Android i kliknuti na Switch Platform. Nakon toga moţemo preći na podešavanja za
Android odabirom Player Settings opcije (slika 3.5).
U inspektoru se otvara PlayerSettings gde imamo opšta podešavanja za projekat
(slika 3.6.). Prvo unosimo ime kompanije koja je vlasnik projekta ili naloga na koji će igra
biti postavljena. Nakon toga unosimo ime koje će se prikazivati na ureĎaju kada se igra
instalira. Ukoliko ne izaberemo neku ikonicu za projekat, Unity će dodeliti svoj logo kao

13
Virtuelna realnost: Osnove i izrada igara

podrazumevanu. Splash Image, slika koja se prikazuje pri učitavanju igre, moţe da se
promeni samo ako imamo plaćenu verziju Unity-a. U suprotom moţemo samo dodati još
neku splash sliku. U Other Settings imamo podešavanja za Color Space koja odreĎuje kako
će se boje mešati sa osvetljenjem i tu biramo Linear. Za Graphics API isključujemo Auto
opciju i u listi ostavljamo samo OpenGLES3 i Vulkan jer je OpenGLES2 grafika isuviše
slaba za VR. OpenGLES je interfejs za renderovanje (iscrtavanje) grafike u aplikacijama.
Obavezno štikliramo Virtual Reality Supported i iz padajuće liste izaberemo Oculus. Kod
identifikacije biramo Package Name koji nam identifikuje igru na storu jer svaka aplikacija
ima svoj package name koji se mora razlikovati od svih ostalih. TakoĎe unosimo i trenutnu
verziju projekta. Minimum API za VR igre je Android 5.0. Na kraju u Publish Settings
unosimo ključ sa koji obezbeĎuje aplikaciju. Taj isti ključ kasnije koristimo za ponovno
pakovanje aplikacije.

Slika 3.6: Oculus Signature file

Da bi mogli da pokrenemo igru na mobilnom telefonu i testiramo je u Gear VR u


projekat moramo ubaciti Oculus signature File (OSIG), fajl koji definiše naš mobilni ureĎaj
kao test ureĎaj. OSIG dobijamo tako što na adresi https://dashboard.oculus.com/tools/osig-
generator unesemo IMEI našeg mobilnog telefona i kliknemo na Download File (slika 3.6).
Ovaj fajl smeštamo u naš projekat na lokaciji Project / Assets / Plugins / Android / assets/.
Ukoliko ovo ne radimo u Gear VR će nam se pojaviti greška da APK (Android Package Kit),
fajl za distribuciju aplikacija, nije potpisan (not signed).

4. Projekat "VR Master"

Nakon svih podešavanja moţemo početi izradu igre za virtuelnu realnost. Projekat
koji se koristi kao primer u ovom radu podrţava Samsung Gear VR ureĎaj. U njemu ćemo
videti neke od principa VR-a koje smo prethodno pomenuli i kako se oni koriste.
Projekat se sastoji iz dva dela. Prvi deo je prezentacija Prirodno-matematičkog
fakulteta u 360 stepeni. Korisnik se nalazi u sferama na kojima se nalaze slike u 360 stepeni
koje su napravljene Samsung Gear 360 kamerom i kreće se iz jednog dela fakulteta u naredni
teleportovanjem.
Drugi deo projekta je VR Survival Shooter igra u kojoj se igrač nalazi u jednom kraju
sobe dok iz drugog kraja ka igraču kreću raznolika čudovišta. Kada čudovišta stignu do
igrača napadaju ga i polako ubijaju. Cilj igre je da igrač što duţe preţivi napad i sakupi što
veći broj poena uništavanjem čudovišta.
U projektu ćemo imati četiri scene (slika 4.1) Preload, Enter, Sphere i Game
Scene. Na preload sceni neće biti ničega osim osim jednog objekta koji će nam sluţiti za
učitavanje Firebase-a što ćemo videti kasnije u radu. Scene u Unity-u funkcionišu kao
odvojeni nivoi i svaka se dizajnira zasebno.

14
Virtuelna realnost: Osnove i izrada igara

Slika 4.1: Scene u projektu

Pri pokretanju scene odmah se učitava naredna scena jer ona sluţi samo za učitavanje
podešavanja za projekat. Kameru ćemo podesiti tako što podešavamo Clear Flags na Solid
Color i biramo crnu boju. U slučaju da se naredna scena ne učita odmah, neće se videti
prazan prostor nego će korisnik videti crnu boju. Novu scenu učitavamo sa:
SceneManager.LoadScene("EnterScene");

Slika 4.2: Enter Scene

Naredna scena je Enter Scene na kojoj se nalaze vrata za prethodno pomenute delove
projekta, prezentaciju u 360 stepeni i survival shooter igru (slika 4.2). Sama rotacija kamere
je automatski ubačena uključivanjem podrške za Gear VR. Jedna od stvari koja nam je
potrebna u ovom trenutku je interakcija igrača. Ceo prefab sa Main kamerom i Reticle-om
koji se koristi za interackiju moţemo naći u VR Samples assetu na adresi
https://www.assetstore.unity3d.com/en/#!/content/51519. Prefab je objekat sa unapred
odreĎenim svojstvima koji je spreman za ubacivanje na scenu.

Slika 4.3: VR Sample prefab sa kamerom

Ubacivanjem ovog prefab-a na centru ekrana dobijamo Reticle, belu tačku koja
funkcioniše kao meta (slika 4.3). Klikom na touch-pad registruje se klik na onaj objekat na
kome se nalazi Reticle. Interakcija se vrši tako što se iz pravca kamere pravo pušta zrak koji
pogaĎa ciljani objekat. Funkcija za to se nalazi u skripti VREyeRaycaster.cs:
private void EyeRaycast()
{
// Kreiranje zraka koji ide pravo od kamere.
Ray ray = new Ray(m_Camera.position, m_Camera.forward);
RaycastHit hit;
// Pustanje zraka unapred i detektovanje mete
if (Physics.Raycast(ray, out hit, m_RayLength, ~m_ExclusionLayers))
{
//pokušavamo da dobijemo VRInteractiveItem skriptu pogođenog objekta
VRInteractiveItem interactible = hit.collider.GetComponent<VRInteractiveIte
m>();

15
Virtuelna realnost: Osnove i izrada igara

m_CurrentInteractible = interactible;
// Nešto smo pogodili i postavljamo Reticle na tu poziciju.
if (m_Reticle)
m_Reticle.SetPosition(hit);
if (OnRaycasthit != null)
OnRaycasthit(hit);
}
else
{
// Ništa nismo pogodili i postavljamo Reticle na podrazumevanu razdaljinu.
if (m_Reticle)
m_Reticle.SetPosition();
}
}

Skripta VRInteractiveItem.cs sluţi za detektovanje osnovnih komandi za


interakciju korisnika sa nekim objektom. Skripta se stavi kao komponenta na odreĎeni
objekat, i tek tada taj objekat postaje interaktibilan. Detektuju se sledeće akcije:
 OnOver - poziva se kada Reticle preĎe preko objekta
 OnOut - poziva se kada Reticle izaĎe sa objekta
 OnClick - poziva se kada se detektuje klik dok je Reticle preko objekta
 OnDoubleClick - poziva se pri detekciji duplog klika na objektu
U nekoj drugoj skripti dodajemo akcije iz VRInteractiveItem skripte i
odlučujemo šta će se desiti ukoliko se neka akcija registruje.
Još jedna od korisnih skripti iz ovog asseta je i VRCameraFade.cs, skripta koja
poseduje funkcije za fejdovanje kamere. FadeIn i FadeOut se koriste pri prelasku sa jedne
scene na drugu ili kod teleportovanja. Na slici 4.3. na dnu liste se nalazi FadePanel, slika
koja se nalazi preko celog ekrana i koja je transparentna. Pri pozivu funkcije FadeIn, Fade
panel se zatamnjuje do potpuno crne boje, i nakon toga pozivom funkcije FadeOut on
ponovo prelazi u transparentno stanje. Na ovaj način izbegava se izazivanje mučnine kod
korisnika pri kretanju.

5. Prirodno-matematički fakultet - prezentacija u 360 stepeni


Prvi deo projekta je "360 degree" prezentacija fakulteta. Cilj ove prezentacije je
mogućnost prikazivanja virtuelne ture fakulteta potencijalnim budućim studentima. Pri
nedostatku 3D modela fakulteta, korišćene su sferne slike koje su napravljene Samsung
Gear360 kamerom sa više pozicija na fakultetu.

16
Virtuelna realnost: Osnove i izrada igara

Slika 5.1: Hijerarhija sfera

5.1. Postavljanje slika


Scena se sastoji od 18 sfera na kojima se nalaze slike i napravljena je modularno tako
da se broj sfera sa slikama moţe menjati bez problema (slika 5.1). U sredini prve sfere nalazi
se prefab MainCamera identičan onom sa prethodne scene koji sadrţi Reticle i
funkcionalnost za interakciju.

Slika 5.2: Teleport - prostorni korisnički interfejs

5.2. Kretanje korisnika


U svakoj sferi nalazi se jedan ili više objekata sa imenom Teleportx-y. Ovi objekti
sa jednom slikom na sebi su primeri prostornog korisničkog interfejsa (slika 5.2). Ovi
teleporti pretstavljaju prolaz ka drugoj sferi i dugom delu fakulteta, a slova X i Y u nazivu
označavaju početnu sferu i destinaciju na koju se korisnik teleportuje. Npr. Teleport2-4
prebacuje korisnika iz svere 2 u sferu 4. Ovakvo imenovanje je korišćeno radi lakšeg
snalaţenja.
Teleporti na sebi imaju po dve skripte i BoxCollider. Jedna skripta je
VRInteractiveItem.cs jer objekat treba biti kliktabilan, a iz istog razloga se na njemu
nalazi i BoxCollider koji vrši koliziju sa zrakom koji se pušta iz pravca kamere. Druga
skripta na Teleportima je:
public class InteractivePortal : MonoBehaviour
{
Vector3 startScale;
Vector3 biggerScale;
bool cameraMoveable = true;
public GameObject targetSpehere;
VRCameraFade cameraFade;

17
Virtuelna realnost: Osnove i izrada igara

GameObject cameraHolder;
private VRInteractiveItem m_InteractiveItem;
private void Awake (){
m_InteractiveItem = gameObject.GetComponent<VRInteractiveItem> ();
cameraHolder = GameObject.Find ("MainCameraHolder");
cameraFade = GameObject.Find ("MainCamera").GetComponent<VRCameraFade> ();
startScale = gameObject.transform.localScale;
biggerScale = new Vector3 (startScale.x + 0.005f,
startScale.y + 0.005f, startScale.z + 0.005f);
}

private void OnEnable (){


m_InteractiveItem.OnOver += HandleOver;
m_InteractiveItem.OnOut += HandleOut;
m_InteractiveItem.OnClick += HandleClick;
}

private void OnDisable (){


m_InteractiveItem.OnOver -= HandleOver;
m_InteractiveItem.OnOut -= HandleOut;
m_InteractiveItem.OnClick -= HandleClick;
}

private void HandleOver (){


gameObject.transform.localScale = biggerScale;
}

private void HandleOut (){


gameObject.transform.localScale = startScale;
}

private void HandleClick (){


if (m_InteractiveItem.name.Equals ("TeleportExit"))
{
SceneManager.LoadScene ("EnterScene");
}
else if (cameraMoveable)
{
cameraMoveable = false;
cameraFade.FadeOut (0.5f, false);
targetSpehere.SetActive (true);
Invoke ("moveCamera", 0.6f);
}
}

private void moveCamera (){


cameraHolder.transform.position = targetSpehere.transform.position;
cameraMoveable = true;
cameraFade.FadeIn (0.5f, false);
gameObject.transform.parent.gameObject.SetActive (false);
}
}

Skripta kao javni parametar ima GameObject targetSphere u koji se iz editora


prevlači ciljana sfera gde će se korisnik teleportovati klikom na Teleport objekat. U
funkcijama OnEnable i OnDisable uključujemo i isključujemo tri funkcije iz
VRInteractiveObject.cs skripte. HandleOver će povećati Teleport objekat pri
fokusiranju istog. Kada korisnik skloni pogled sa Teleporta, pozvaće se HandleOut funkcija
koja vraća početnu veličinu objektu. Na klik se poziva funkcija HandleClick, koja u
slučaju da se Teleport zove TeleportExit učitava prethodnu scenu,u suprotnom ispituje da
li kamera moţe da se pomeri, fejduje ekran u crnu boju da se ne bi videlo pomeranje,
uključuje narednu scenu i odlaţe pozivanje funkcije moveCamera za 0.6 sekundi. Ova

18
Virtuelna realnost: Osnove i izrada igara

funkcija pomera cameraHolder u centar nove sfere, sklanja fade prelaskom iz crne boje u
transparentnu i gasi prethodnu sferu.

5.3. Podaci o kabinetima i profesorima

Prezentacija ima mogućnost postavljanja informacionih lista o kabinetima i


profesorima koji se nalaze u njima. Ova mogućnost je takoĎe modularna i moţe se postaviti u
bilo kom delu sfere za jedan ili više kabineta odjednom.
Korisnik u nekim delovima fakulteta moţe naići na sličicu sa slovom ”i” na sebi.
Klikom na ovu sličicu otvara se lista kabineta i imena ljudi koji se nalaze u njima (slika 5.3).

Slika 5.3: Primer liste kabineta i profesora

Podaci o kabinetima i profesorima se dobijaju iz parsiranjem XML fajla koji se nalazi


online na Firebase serveru. Izmenom XML fajla na serveru, dinamički se menjaju i podaci u
listama u prezentaciji.

5.4. Firebase skladište

Firebase je Google-ov onlajn servis i sadrţi mnoštvo opcija kao što su baza podataka,
izveštaji o greškama, sinhronizacija ureĎaja, autentikacija korisnika, skladištenje podataka na
oblaku (cloud), hosting i praćenje performansi. Servis je besplatan i moţe se ugraĎivati u
Android, iOS i Unity projekte, a moţe se koristiti već postojeći Google nalog za pristup
konzoli. Mnoge poznate aplikacije, kao što su Shazam, Duolingo, Trivago i druge, koriste
Firebase servise.
U ovom projektu koristićemo Firebase Cloud Storage za onlajn skladištenje XML
fajla kome će naša aplikacija pristupati kako bi prikupila podatke o kabinetima i profesorima
na fakultetu.

19
Virtuelna realnost: Osnove i izrada igara

Slika 5.4: Kreiranje novog projekta u Firebase

Konzoli za otvaranje i podešavanje aplikacija pristupamo na adresi


https://console.firebase.google.com/. Konzola je mesto gde stoje sve potrebne informacije o
aplikacijama. Na početnoj strani vidimo Recent projects listu i u njoj već postojeće projekte
ukoliko ih imamo. Na prvom mestu u listi se nalazi Add project opcija koja otvara Create а
project prozor (slika 5.4) u koji unosimo ime projekta, drţavu u kojoj se nalazimo i
generišemo Project ID koji sluţi kao identifikacioni kod našeg projekta.

Slika 5.5: Firebase konzola

Klikom na Create Project nakon par sekundi se kreira projekat i otvara Firebase
konzola (slika 5.5). Sa leve strane konzole moţemo videti spisak svih proizvoda koje nudi
ovaj servis. Nama je potreban Storage gde se nalazi forma za upload novog fajla i spisak
postojećih fajlova koji se već nalaze u skladištu. Novi fajl dodajemo tako što kliknemo
dugme Upload File i izaberemo ţeljeni fajl sa našeg računara.
Da bi svi korisnici mogli da pristupe našem fajlu, moramo podesiti njegovu privatnost
u pravilima skladišta. Odabirom opcije Rules na vrhu konzole otvara se polje za editovanje
teksta gde su upisana pravila. Da bi fajl bio javni i dostupan svima trebamo upisati sledeće:

20
Virtuelna realnost: Osnove i izrada igara

service firebase.storage {
match /b/vr-master-rad.appspot.com/o {
match /{allPaths=**} {
allowread, write;
}
}
}

Sledeći korak je skidanje potrebnih fajlova za rad u Unity-u. Da bi Firebase Storage


funkcionisao u našem projektu potrebne su nam dve stvari, Firebase SDK i google-
services.json fajl.
Json fajl koji nam je potreban dobijamo iz konzole. Potrebno je kliknuti na zupčanik
na vrhu ekrana i izabrati Project Settings nakon čega nam se otvara strana sa informacijama
o trenutnom projektu. Sa desne strane se nalazi dugme sa natpisom google-services.json i
klikom na njega dobijamo fajl koji ubacujemo u bilo koji folder Unity projekta.
SDK je dostupan na adresi https://firebase.google.com/download/unity i odatle
dobijamo zip fajl u kome se nalazi poslednja stabilna verzija SDK-a za svaki Firebase
proizvod posebno.
Sada je potrebno uključiti paket za Firebase Storage u projekat. To se radi odabirom
opcije Assets > Import Package > Custom Package iz menija. Nakon toga potrebno je
izabrati FirebaseStorage.unitypackage i kliknuti na dugme Import kada se svi fajlovi
učitaju u listu za uvoz. Sada je projekat spreman za rad sa skladištem i za to koristimo skriptu
FirebaseAgent.cs koja se nalazi na istoimenom objektu u Preload sceni.
public class FirebaseAgent : MonoBehaviour {

public static bool xmlLoaded = false;

void Awake () {
DontDestroyOnLoad(gameObject);
StartCoroutine(DownloadFromFirebaseStorage());
SceneManager.LoadScene("EnterScene");
}

private string fileContents;

IEnumerator DownloadFromFirebaseStorage()
{
StorageReference reference = FirebaseStorage.DefaultInstance
.GetReferenceFromUrl("gs://vr-master-rad.appspot.com/kancelarije.xml");
var task = reference.GetBytesAsync(1024 * 1024);
yield return new WaitUntil(() => task.IsCompleted);
if(task.IsFaulted)
{
Debug.Log(task.Exception.ToString());
} else
{
fileContents = Encoding.UTF8.GetString(task.Result);
xmlLoaded = XMLParser.loadXML(fileContents);
}
}
}

Funkcija DontDestroyOnLoad kao parametar uzima objekat na kome se nalazi


sama skripta, i ne dozvoljava da se taj objekat uništi pri učitavanju naredne scene. Nakon

21
Virtuelna realnost: Osnove i izrada igara

toga pozivamo IEnumerator DownloadFromFirebaseStorage koji nam omogućava da


u pozadini sačekamo, u ovom slučaju, download fajla i tek onda radimo parsiranje XML-a da
bi dobili listu kabineta i profesora na fakultetu. U okviru ove funkcije pravimo referencu na
Firebase Storage prosleĎujući putanju do potrebnog fajla funkciji
FirebaseStorage.DefaultInstance.GetReferenceFromUrl. Ova putanja se moţe
naći u konzoli pored dugmeta Upload File. Nakon završetka skidanja fajla, ukoliko je rezultat
ispravan, smeštamo ga u promenljivu tipa string, i nju prosleĎujemo kao parametar funkciji
za parsiranje XML-a.

5.5. Parsiranje XML-a


XML fajl koji koristimo za projekat se sastoji iz sledećih elemenata:
 Tag fakultet obuhvata ceo XML.
 U okviru fakulteta se nalaze tagovi kancelarija i svaki od njih sadrţi attribute: br koji
označava broj kancelarije i ime ukoliko kancelarija ili kabinet imaju naziv kao što je
“Računski centar”. Atribut ime moţe biti prazan.
 Svaka kancelarija sadrţi pod tagove tekst koji kao vrednost sadrţi ime osobe koja se
nalazi u tom kabinetu.

Primer ovog fajla izgleda ovako:

<?xml version="1.0" encoding="utf-8"?>


<fakultet>
<kancelarija br="1" ime="">
<tekst>Prof. dr Marko Petković, redovni profesor</tekst>
<tekst>Prof. dr Dragan Stevanović, redovni profesor</tekst>
<tekst>Aleksandar Trokicić, asistent</tekst>
<tekst>Nikola Milosavljević, asistent</tekst>
<tekst>Dejan Kolundţija, asistent</tekst>
</kancelarija>
<kancelarija br="2" ime="Računski centar">
<tekst>Aleksandra Petrović, programer</tekst>
</kancelarija>
<kancelarija br="3" ime="Računarska učionica">
</kancelarija>
<kancelarija br="4" ime="">
<tekst>Dr Ranko Dragović, vanredni profesor</tekst>
<tekst>Dr Selim Šaćirović, vanredni profesor</tekst>
<tekst>Sonja Miletić, nastavnik za engleski jezik</tekst>
</kancelarija>
<kancelarija br="5" ime="">
<tekst>Dr Vidoje Stefanović, redovni profesor</tekst>
<tekst>Dr Tatjana Đekić, vanredni profesor</tekst>
</kancelarija>
<kancelarija br="6" ime="Biblioteka">
</kancelarija>
<kancelarija br="8" ime="">
<tekst>Prof. dr Sneţana Ilić</tekst>
</kancelarija>
<kancelarija br="8a" ime="">
<tekst>Dr Dijana Mosić, vanredni profesor</tekst>
<tekst>Dr Nebojša Dinčić, docent</tekst>
<tekst>Dr Milica Kolundţija, docent</tekst>
</kancelarija>
<kancelarija br="9" ime="Amfiteatar">
</kancelarija>
</fakultet>

22
Virtuelna realnost: Osnove i izrada igara

Kada se završi download fajla i ispravan rezultat smesti u string, poziva se funkcija
loadXML(string content) koja se nalazi u skripti XMLParser.cs.
public class XMLParser : MonoBehaviour {

private static XmlDocument xmlDoc;


public static Fakultet fakultet;

public static bool loadXML(string file)


{
xmlDoc = new XmlDocument();
xmlDoc.LoadXml(file);
fakultet = new Fakultet();
fakultet.kancelarije = new ArrayList();

foreach(XmlElement kc in xmlDoc.SelectNodes("fakultet/kancelarija"))
{
Kancelarija kancelarija = new Kancelarija();
kancelarija.brojKancelarije = kc.GetAttribute("br");
kancelarija.imeKancelarije = kc.GetAttribute("ime");
kancelarija.imena = new ArrayList();
foreach(XmlElement ime in kc.SelectNodes("tekst"))
{
string i = ime.InnerText;
Debug.Log(">>" + i);
kancelarija.imena.Add(i);
}
fakultet.kancelarije.Add(kancelarija);
}
return true;
}
}

Za parsiranje XML-a koristimo dve pomoćne klase Fakultet koja sadrţi javnu listu
kancelarija, i klasu Kancelarija koja kao promenljive ima javne stringove
brojKancelarije i imeKancelarije i javnu listu imena.
String koji smo prosledili funkciji kao parametar učitavamo u novu promenljivu tipa
XmlDocument i kreiramo jednu promenljivu tipa Fakultet u koju ćemo smestiti sve
kancelarije.
Uz pomoć foreach petlje prolazimo kroz sve čvorove dokumenta koji su tipa
“kancelarija”. Za svaki od njih kreiramo novu promenljivu tipa Kancelarija, u nju
smeštamo atribute dobijene funkcijom GetAttribute i pravimo novu listu u koju smeštamo
osobe.
Novom foreach petljom prolazimo kroz sve čvorove sa imenom “tekst” i njihovu,
vrednost koju dobijamo funkcijom InnerText, dodajemo u prethodno kreiranu listu.
Nakon završetka parsiranja XML-a, ukoliko je sve proteklo bez greške, potvrĎujemo
da je parsiranje uspešno završeno kako bi kasnije u prezentaciji mogla da se generiše
dinamička lista kabineta i profesora.

5.6. Dinamičko kreiranje liste


Lista koju ćemo kreirati je primer prostornog korisničkog interfejsa jer se nalazi u
samom svetu (pored vrata nekog kabineta). Na mestu gde se nalazi lista u startu se vidi samo
sličica sa slovom “i” koje označava “informacije”. Klikom na ovu sličicu pored se otvara lista

23
Virtuelna realnost: Osnove i izrada igara

u kojoj su ispisani kabineti za taj deo fakulteta i osobe koje se nalaze u tim kabinetima a
sličica sa slovom “i” se menja u sličicu za gašenje sa znakom “X”.

Slika 5.6: Struktura InfoHoldera

Objekat koji sadrţi listu u koju se dinamički dodaju elementi naziva se InfoBG i
nalazi se u Canvas-u (slika 5.6), osnovnom elementu za korisnički interfejs još od Unity
verzije 4.6. Komponenta koju sadrţi ovaj objekat i koja je zaduţena za pravljenje liste je
Vertical Layout Group (slika 5.7)

Slika 5.7: Vertical Layout Group

Objekti koji se dodaju kao deca objekta InfoBG se automatski reĎaju jedan ispod
drugog. Da bi imalo dovoljno mesta za upis imena, štiklirana je opcija Child Force
Expand Width koja raširi svu decu na maksimalnu širinu.
Postoje dva tipa objekata koje ćemo instancirati u listu, to su prefabovi
Kancelarija i Osoba. Oba su objekti koji sadrţe komponentu Text s tim što su boja i
veličina slova predefinisani tako da se razlikuju i budu lako čitljivi u listi i komponentu
Layout Element kako bi ih lista registrovala kao elemente liste.
Na objektu InfoButton se nalazi skripta VRInteractiveItem.cs kako bi on bio
interaktibilan i InfoScript.cs koja je zaduţena za generisanje liste.
public class InfoScript : MonoBehaviour {
[SerializeField]
public string[] brojKancelarije; //brojevi kancelarija
public Sprite infSprite; //slika za info dugme
public Sprite closeSprite; //slika za zatvaranje liste
public Canvas infoCanvas; //Canvas u kome se nalazi lista
public VerticalLayoutGroup VerticalList; //Lista u koju se instanciraju objekti
public GameObject KancelarijaPrefab; //prefab za kancelariju
public GameObject ProfesorPrefab; //prefab za imena profesora
bool infoOpened; //flag koji oznacava da li je lista otvorena ili ne
SpriteRenderer sprite;
VRInteractiveItem interactiveItem;

void Awake () {
interactiveItem = GetComponent<VRInteractiveItem>();
sprite = GetComponent<SpriteRenderer>();
infoOpened = false;
if (FirebaseAgent.xmlLoaded)
{
foreach(Kancelarija k in XMLParser.fakultet.kancelarije)
{
foreach(string s in brojKancelarije)
{
if (k.brojKancelarije.Equals(s))
{
GameObject kancelarija =

24
Virtuelna realnost: Osnove i izrada igara

Instantiate(KancelarijaPrefab) as GameObject;
kancelarija.transform.SetParent(VerticalList.transform, false);
kancelarija.GetComponent<Text>().text =
k.brojKancelarije + " " + k.imeKancelarije;
foreach(string ime in k.imena)
{
GameObject profesor =
Instantiate(ProfesorPrefab) as GameObject;
profesor.transform.SetParent(VerticalList.transform, false);
profesor.GetComponent<Text>().text = ime;
}
}
}
}
}
infoCanvas.gameObject.SetActive(false);
if (!FirebaseAgent.xmlLoaded) {
gameObject.transform.parent.gameObject.SetActive (false);
}
}
private void OnEnable(){
interactiveItem.OnDown += ToggleOpenClose;
}
private void OnDisable() {
interactiveItem.OnDown -= ToggleOpenClose;
}

private void ToggleOpenClose(){


if (infoOpened)
{
infoOpened = false;
sprite.sprite = infSprite;
infoCanvas.gameObject.SetActive(false);
}
else
{
infoOpened = true;
sprite.sprite = closeSprite;
infoCanvas.gameObject.SetActive(true);
}
}
}

Parametre u ovoj skripti unosimo iz Unity Editora direktno i tako podešavamo koji
info će prikazivati koje kabinete (slika 5.8).

Slika 5.8: InfoScript.cs

25
Virtuelna realnost: Osnove i izrada igara

Prvo unosimo koliko će kancelarija biti prikazano u listi, a nakon toga brojeve tih
kancelarija kao elemente niza. Ostali parametri su uvek isti na svim info objektima. U Awake
funkciji prvo proveravamo da li je uspešno izvršeno parsiranje XML-a, ukoliko jeste
popunjavamo listu tako što uporeĎujemo brojeve kancelarija iz XML-a i brojeve koji su uneti
u listu brojKancelarije. Ako se brojevi poklapaju instanciramo objekat Kancelarija,
stavljamo ga kao dete u listu, podešavamo tekst i foreach petljom prolazimo kroz imena
svih osoba koje se nalaze u toj kancelariji. Za svako ime instanciramo objekat Osoba i
podešavamo mu tekst. Ukoliko učitavanje XML-a nije uspešno, gasimo ceo holder za listu.
Funkcija ToggleOpenClose() omogućava paljenje i gašenje liste klikom na dugme
"i" ili "X". Ako je lista zatvorena, menja se sličica u "X" i pali se lista. U suprotnom postavlja
se sličica "i" i gasi lista.

6. VR Survival Shooter igra

Drugi deo projekta je igra "VR Survival Shooter", first person shooter čiji je cilj što
duţe preţivljavanje napada čudovišta. Igri se pristupa iz Enter scene klikom na vrata sa leve
strane.
Igrač se nalazi u jednom kraju prostorije sa visokim zidovima. Na drugom kraju
prostorije stvaraju se čudovišta koja imaju jedan cilj, a to je uništenje igrača. U ruci igrač ima
pištolj kojim puca na čudovišta i na taj način im skida energiju i ubija ih. Svakim uništenjem
čudovišta igrač dobija odreĎeni broj poena. Na Enter sceni iznad vrata stoji najveći rezultat
koji je igrač postigao. Kraj igre je uvek isti i to je uništenje igrača koje je neizbeţno.

Slika 6.1: VR Shooter Survival

Elementi igre su sam igrač, čudovišta, pojačanja za igrača (power up), način
instanciranja čudovišta i vrste čudovišta. Svaki od ovih elemenata ima svoju logiku kroz koju
ćemo proći u ovom radu.

6.1. Igrač
U ovoj FPS igri kod igrača se vidi samo ruka i pištolj. Igrač ima odreĎenu količinu
energije koja se smanjuje kada neko od čudovišta priĎe dovoljno blizu. Kretanje je

26
Virtuelna realnost: Osnove i izrada igara

onemogućeno jer bi zbog dosta okretanja igraču bilo neprijatno i osetio bi mučninu. Na
svojoj statičnoj poziciji igrač moţe da se okreće i na taj način nišani čudovišta. Reticle koji se
nalazi na sredini ekrana sluţi kao nišan.
Korisnik puca na čudovišta pritiskom touch pad-a na Gear VR ureĎaju. Pucanje se
vrši uz pomoć PlayerShooting.cs skripte koja izgleda ovako:
public class PlayerShooting : MonoBehaviour
{
public int damagePerShot = 20;
public float timeBetweenBullets = 0.20f;
public float range = 100f;
float timer;
Ray shootRay = new Ray ();
RaycastHit shootHit;
int shootableMask;
ParticleSystem gunParticles;
LineRenderer gunLine;
AudioSource gunAudio;
float effectsDisplayTime = 0.2f;
public PowerUpScript powerUpScript;
[SerializeField]
VRInput vrInput;

private void OnEnable (){


vrInput.OnDown += HandleDown;
}

private void OnDisable (){


vrInput.OnDown -= HandleDown;
}

void Awake (){


shootableMask = LayerMask.GetMask ("Shootable");
gunParticles = GetComponent<ParticleSystem> ();
gunLine = GetComponent <LineRenderer> ();
gunAudio = GetComponent<AudioSource> ();
}

void Update (){


timer += Time.deltaTime;
}

void HandleDown (){


if (timer >= timeBetweenBullets && Time.timeScale != 0) {
Shoot ();
}
}

void Shoot ()
timer = 0f;
gunAudio.Play ();
gunParticles.Stop ();
gunParticles.Play ();
gunLine.enabled = true;
gunLine.SetPosition (0, transform.position);
shootRay.origin = transform.position;
shootRay.direction = transform.forward;
if (Physics.Raycast (shootRay, out shootHit, range, shootableMask)) {
EnemyScript enemyHealth = shootHit.collider.GetComponent <EnemyScript> ();
PowerUpScript powerUp = shootHit.collider.GetComponent<PowerUpScript>();
if (enemyHealth != null) {
enemyHealth.TakeDamage (
Mathf.FloorToInt(PowerUpManager.atackOn * damagePerShot),

27
Virtuelna realnost: Osnove i izrada igara

shootHit.point);
} else if (powerUp != null) {
powerUp.PickUpPowerUp();
}
gunLine.SetPosition (1, shootHit.point);
}
else {
gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
}
}
}

Na početku se nalaze parametri koji odreĎuju koliko će brzo igrač pucati, tj vreme
izmeĎu ispaljivanja metkova timeBetweenBullets i damagePerShot koji odreĎuje štetu
koju igrač nanosi čudovištima. Promenljiva timer nam sluţi za merenje vremena izmeĎu
ispaljivanja metkova.
U funkciji HandleDown() koja se poziva pri kliku na touch pad, u slučaju da je
prošlo potrebno vreme za ispaljivanje meta, pozivamo funkciju Shoot() koja reguliše
ispaljivanje metka.
Osim puštanja zvučnih i vizuelnih efekata pri svakom ispaljivanju metka, u ovoj
funkciji se pusta zrak iz kamere u pravcu nišana. U slučanu da zrak pogodi nešto, ispituje se
da li je taj objekat neprijatelj ili power up. Ukoliko je to neprijatelj, njemu se skida odreĎena
količina energije. Ako igrač pogodi neki od power up-ova, poziva se funkcija za njegovo
aktiviranje koji ćemo videti kasnije.
Korisnički interfejs u ovoj igri je diegetic. Primer ovoga su tabla koja prikazuje
energiju igrača koja se nalazi na samoj ruci, poeni koje je igrač sakupio koji su sa leve strane
i sličice za power up-ove koje se pojavljuju iza pištolja (slika 6.2).

Slika 6.2: Diegetic korisnički interfejs

Ţivot ili energija igrača kontroliše se kroz PlayerHealth.cs skriptu:


public class PlayerHealth : MonoBehaviour
{
public int startingHealth = 100;
public int currentHealth;
public Image healthSlider;
public Image damageImage;
public AudioClip deathClip;
public float flashSpeed = 5f;
public Color flashColour = new Color (1f, 0f, 0f, 0.1f);
Color32 greenColour = new Color32 (126, 255, 122, 232);
Color32 orangeColour = new Color32 (255, 191, 122, 232);
Color32 redColour = new Color32 (255, 122, 122, 232);
Animator anim;
AudioSource playerAudio;
PlayerShooting playerShooting;

28
Virtuelna realnost: Osnove i izrada igara

bool isDead;
bool damaged;
VRCameraFade cameraFade;

void Awake (){


isDead = false;
cameraFade = GameObject.Find ("MainCamera").GetComponent<VRCameraFade> ();
anim = GetComponent <Animator> ();
playerAudio = GetComponent <AudioSource> ();
playerShooting = GetComponentInChildren <PlayerShooting> ();
currentHealth = startingHealth;
healthSlider.color = greenColour;
}

void Update (){


if (damaged){
damageImage.color = flashColour;
}else{
damageImage.color = Color.Lerp (damageImage.color, Color.clear,
flashSpeed * Time.deltaTime);
}
damaged = false;
}

public void TakeDamage (int amount){


if (!PowerUpManager.shieldOn){
damaged = true;
currentHealth -= amount;
healthSlider.fillAmount = currentHealth / 100f;
if (currentHealth <= 30){
healthSlider.color = redColour;
}else if (currentHealth <= 60)
healthSlider.color = orangeColour;
playerAudio.Play();
if (currentHealth <= 0 && !isDead){
Death();
}
}
}

public void healPlayer(int health){


currentHealth += health;
if (currentHealth >= startingHealth)
{
currentHealth = startingHealth;
}
healthSlider.fillAmount = currentHealth / 100f;
}

public void Death (){


if (!isDead){
isDead = true;

playerAudio.clip = deathClip;
playerAudio.Play ();

playerShooting.enabled = false;
cameraFade.FadeOut (0.5f, false);
if (ScoreManager.score > MainController.topScore){
MainController.setTopScore (ScoreManager.score);
}
Invoke ("EndLevel", 1.5f);
}
}

29
Virtuelna realnost: Osnove i izrada igara

public void EndLevel (){


SceneManager.LoadScene ("EnterScene");
}
}

Na početku skripte imamo promenljivu startingHealth koja označava


maksimalnu vrednost igračeve energije. CurrentHealth je promenljiva koja čuva trenutnu
energiju igrača nakon napada čudovišta. Nakon toga imamo dve slike, healthSlider je
zelena slika za energiju igrača koja se nalazi na ruci, a damageImage je transparentna slika
koja se nalazi preko celog ekrana. Ova slika se pri napadu neprijatelja na kratko zacrveni
kako bi signalizirala igraču da je napadnut.
Funkcija TakeDamage kao parametar prima vrednost štete koju čudovište nanosi
igraču. Ukoliko štit na igraču nije uključen, njegova trenutna energija se umanjuje za
vrednost parametra koji je prosleĎen funkciji. TakoĎe se i slika koja predstavlja energiju
igrača skraćuje i u zavisnosti od preostale količine energije menja boju iz zelene u
narandţastu i kasnije u crvenu.
Ukoliko je trenutna energija igrača jednaka nuli, poziva se funkcija Death. Ova
funkcija završava trenutnu igru tako što pušta muziku za kraj igre sa playerAudio objekta
funkcijom Play. Nakon toga ekran se zatamnjuje kako se ne bi video prelazak sa trenutne
scene na Enter scenu. Pre samog prelaska na drugu scenu beleţi se rezultat igrača ukoliko je
on veći od trenutno najvećeg rezultata.

6.2. Pojačanja igrača (power up)

U igri postoje tri vrste pojačanja za igrača. To su pojačanje za napad, štit i lečenje
(slika 6.3). Ova pojačanja se nasumice stvaraju u polju izmeĎu četiri markera koji se nalaze
na sceni na plafonu prostorije. Pojavljuju se na razmaku izmeĎu četiri i osam sekundi i
nestaju sa scene dve sekunde nakon pojavljivanja. Ove vrednosti su podesive iz skripte kao i
iz Editora u toku igre.

Slika 6.3: Pojačanja za igrača - dupli napad, štit i lečenje

Pojačanje za napad daje igraču dupli napad, što znači da nanosi duplo veću štetu
čudovištima nego inače i to traje tri sekunde. Drugo pojačanje je štit koji na tri sekunde štiti
igrača od napada čudovišta. Vreme trajanja pojačanja je podesivo. Treće pojačanje je lečenje
pri čijem sakupljanju se dopunjuje igračeva energija.
Pojačanja su regulisana uz pomoć dve skripte: PowerUpManager.cs i
PowerUpScript.cs. Sva tri objekta za pojačanja se nalaze u prefabovima i sva tri na sebi
imaju komponentu PowerUpScript.

30
Virtuelna realnost: Osnove i izrada igara

public class PowerUpScript : MonoBehaviour {


/*
* 1 - heal
* 2 - crit
* 3 - shield
*/
public float selfDestructTimer = 2.0f;
float timer;
PowerUpManager powerUpManager;
Image powerUpImage;
public float doubleDamageScale = 2f;
public Sprite doubleDamage;
public Sprite shield;
VRInput input;

void Awake () {
PowerUpManager.powerUpIsSpawned = true;
timer = selfDestructTimer;
powerUpManager = GameObject.Find("PowerUpArea").GetComponent<PowerUpManager>();
}

void Update () {
if (timer >= 0){
timer -= Time.deltaTime;
}else{
DestroyPowerUp();
}
}

private void DestroyPowerUp(){


powerUpManager.spawnPowerUp();
Destroy(gameObject);
}

public void PickUpPowerUp(){


timer = 0;
if (gameObject.name.Contains("HealPotion")){
powerUpManager.activateHeal();
}else if (gameObject.name.Contains("Axes")){
powerUpManager.activateAtack();
}else if (gameObject.name.Contains("Shield")){
powerUpManager.activateShield();
}
}
}

Ova skripta je veoma kratka i jasna. Pri instanciranju objekta za pojačanje na samom
početku se aktivira tajmer pri čijem će se isteku objekat uništiti. Ukoliko igrač pogodi ovaj
objekat, u zavisnosti od tipa pojačanja poziva se neka od tri funkcije iz PowerUpManagera,
tajmer se prekida i objekat uništava. Pri uništavanju objekta poziva se funkcija za stvaranje
novog iz PowerUpManager skripte.
Glavna skripta za kontrolu pojačanja je PowerUpManager.cs:
public class PowerUpManager : MonoBehaviour {
#region SPAWN_POINTS
public Transform frontLeft;
public Transform frontRight;
public Transform backLeft;
public Transform backRight;
#endregion
[SerializeField]
public GameObject[] powerUpObjects;
public Vector2 spawnTime = new Vector2(4, 8);

31
Virtuelna realnost: Osnove i izrada igara

public static bool powerUpIsSpawned = false;


int randomObjectIndex = 0;
Vector3 newPosition;
public float doubleDamageScale = 2.0f;
public float powerUpTimer = 3.0f;
public int healAmount = 20;
public float timerAtack = 0f;
float timerShield = 0f;
public static float atackOn;
public static bool shieldOn;
PlayerShooting playerShootingScript;
PlayerHealth playerHealthScript;
public Image powerUpAtackImage;
public Image powerUpShieldImage;
Color transparent = new Color(0, 0, 0, 0);
Color atackColor = new Color(133, 0, 0, 255);
Color shieldColor = new Color(38, 38, 38, 255);

void Awake () {
Invoke("spawnPowerUp", spawnTime.y);
atackOn = 1.0f;
shieldOn = false;
playerHealthScript = GameObject.Find("Player").GetComponent<PlayerHealth>();
playerShootingScript = GameObject.Find("ShootingPoint").GetComponent<PlayerShooting
>();
}

void Update () {
if(atackOn>1.0f && timerAtack > 0){
timerAtack -= Time.deltaTime;
}else{
timerAtack = 0;
atackOn = 1.0f;
powerUpAtackImage.color = transparent;
}
if(shieldOn && timerShield > 0){
timerShield -= Time.deltaTime;
}else{
timerShield = 0;
shieldOn = false;
powerUpShieldImage.color = transparent;
}
}

public void spawnPowerUp(){


powerUpIsSpawned = true;
randomObjectIndex = Random.Range(0, powerUpObjects.Length);
newPosition = new Vector3(
Random.Range(frontLeft.localPosition.x, frontRight.localPosition.x),
frontLeft.position.y,
Random.Range(frontLeft.localPosition.z, backLeft.localPosition.z)
);
Invoke("spawn", Random.Range(spawnTime.x, spawnTime.y + 1));
}

private void spawn(){


Instantiate(powerUpObjects[randomObjectIndex],
newPosition, powerUpObjects[randomObjectIndex].transform.rotation,
gameObject.transform);
}

public void activateHeal(){


playerHealthScript.healPlayer(healAmount);
}

public void activateAtack(){

32
Virtuelna realnost: Osnove i izrada igara

atackOn = doubleDamageScale;
timerAtack = powerUpTimer;
powerUpAtackImage.color = atackColor;
}

public void activateShield(){


shieldOn = true;
timerShield = powerUpTimer;
powerUpShieldImage.color = shieldColor;
}
}

U Awake funkciji ove skripte poziva se na odloţeno vreme funkcija spawnPowerUp


koja nakon nekog vremena nasumice bira jedno od tri pojačanja i instancira ga na nasumično
izabranoj tački u polju izmeĎu četiri markera na sceni. Ista ova funkcija se poziva sa samog
objekta pri uništenju kako bi stvaranje pojačanja bilo kontinuirano. Vremenski razmak
izmeĎu instanciranja pojačanja se odreĎuje promenljivom spawnTime koja je tipa Vector2
i u sebi čuva dve vrednosti (minimalnu i maksimalnu).
Ovde se nalaze i funkcije za aktiviranje pojačanja kada ih igrač pogodi. Funkcija
activateHeal() igraču povećava trenutnu energiju za odreĎeni iznos i pomera sliku za
energiju za isti iznos. Energija igrača se ne moţe povećati više od maksimalne energije
odreĎene na početku.
Povećanje napada se aktivira uz pomoć funkcije activateAttack(). Ona povećava
vrednost parametra koji se mnoţi sa igračevim napadom i tako igrač dobija dupli napad.
Funkcija takoĎe aktivira tajmer koji odbrojava u Update funkciji pri čijem isteku se gasi
pojačanje.
Štit se aktivira funkcijom activateShield() koja boolean vrednost shieldOn
postavlja na true i samim tim aktivira zaštitu igrača od čudovišta. Ovde se takoĎe pali tajmer
koji odbrojava trajanje pojačanja.

6.3. Neprijatelji

Modeli neprijatelja su besplatno preuzeti sa Unity asset stora na adresi


https://www.assetstore.unity3d.com/en/#!/content/40756 (slika 6.4).

Slika 6.4: Modeli neprijatelja

Pri instanciranju, čudovišta odmah počinju da se kreću ka igraču sa ciljem da ga


napadnu čim dodju u kontakt sa njim. Modeli su sačuvani u tri različita prefaba: Zombunny,
Zombear i Hellephant.

33
Virtuelna realnost: Osnove i izrada igara

Svako od čudovišta ima svoju energiju, brzinu kretanja, raspon jačine napada, broj
poena koji donosi igraču, brzinu napada i tip specijalnog pojačanja. Sve ove vrednosti nalaze
se u skripti EnemyScript.cs koja se nalazi na prefabovima. Pored skripte svako čudovište
ima i kolajder koji registruje pogodak igrača i kada ono doĎe u dodir sa igračem.
Osim toga što postoje 3 tipa čudovišta, svako od njih moţe imati neku od četiri
specijalne moći: dvostruka energija, dvostruka šteta, ubrzano kretanje i cik-cak kretanje. Pri
instanciranju neprijatelja poziva se funkcija setSpecialType koja podešava specijalnu moć
čudovišta. Ona se poziva iz EnemyManager skripte koju ćemo videti kasnije, a kao
parametar se dodeljuje nasumice izabrana vrednost od nula do četiri. Ukoliko čudovište ima
specijalnu moć pored njegove energije se prikazuje sličica koja označava koja je moć
uključena.
public void setSpecialType(int type){
specialType = type;
switch (specialType){
case 1:
startingHealth *= 2;
currentHealth = startingHealth;
specialImage.sprite = health;
specialImage.color = new Color(1, 1, 1, 1);
break;
case 2:
atackMultiplier = 1.5f;
specialImage.sprite = atack;
specialImage.color = new Color(1, 1, 1, 1);
break;
case 3:
nav.speed *= bonusSpeed; ;
specialImage.sprite = speed;
specialImage.color = new Color(1, 1, 1, 1);
break;
case 4:
hasZigZag = true;
specialImage.sprite = zigZag;
specialImage.color = new Color(1, 1, 1, 1);
break;
}}

Svako čudovište ima odreĎenu početnu energiju koja se smanjuje kada ga igrač
pogodi. Početne energije sva tri tipa čudovišta se razlikuju. Ukoliko čudovište ima specijalnu
moć za povećanje energije, ona se duplira na početku. Kada igrač puca i pogodi objekat
čudovišta, iz njegove skripte se poziva funkcija TakeDamage koja kao parametre uzima
jačinu napada igrača i tačku u koju je čudovište pogoĎeno. Ova funkcija smanjuje energiju
čudovišta sve dok ona ne doĎe do nule. Osim toga pusta zvuk kada se čudovište pogodi, kao i
partikle koji izlaze iz njega. Kada energija čudovišta doĎe do nule, poziva se funkcija Death.
public void TakeDamage(int amount, Vector3 hitPoint){
if (isDead)
return;
enemyAudio.Play();
currentHealth -= amount;
enemyHPBar.fillAmount = currentHealth / 100f;
hitParticles.transform.position = hitPoint;
hitParticles.Play();
if (currentHealth <= 0){
Death();
}
}

34
Virtuelna realnost: Osnove i izrada igara

Funkcija Death gasi kolajder na čudovištu i pusta zvuk i animaciju za smrt čudovišta.
Tada ono počinje da tone kroz pod kako bi se sklonilo sa scene.
void Death() {
isDead = true;
capsuleCollider.isTrigger = true;
anim.SetTrigger("Dead");
enemyAudio.clip = deathClip;
enemyAudio.Play();
}

Da bi čudovište počelo da tone, poziva se funkcija StartSinking koja isključuje


njegovo horizontalno kretanje, uključuje vertikalno da bi ono potonulo, dodaje igraču
odreĎeni broj poena i uništava instancirani objekat nakon dve sekunde.
public void StartSinking(){
GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
GetComponent<Rigidbody>().isKinematic = true;
isSinking = true;
ScoreManager.score += scoreValue;
Destroy(gameObject, 2f);
}

Za kretanje neprijatelja potrebno je uključiti navigaciju. Prva stvar je postavljanje


NavMeshAgent komponente na sva tri prefaba za čudovišta. Druga stvar je bejkovanje
NavMesh-a, postavljanje prostora po kome će neprijatelji moći da se kreću. Kada se to
podesi, dovoljno je u Update funkciji pozvati funkciju SetDestination kojoj se
prosleĎuje pozicija igrača kao cilj.
if (currentHealth > 0 && playerHealth.currentHealth > 0){
nav.SetDestination(player.transform.position);
} else{
nav.enabled = false;
}

Ukoliko čudovište ima specijalnu moć za brţe kretanje, to se postiţe mnoţenjem


trenutne brzine NavMeshAgenta ţeljenim uvećanjem.
Specijalna moć cik-cak kretanje moţemo videti u Update funkciji i ona radi tako što
na odreĎeni vremenski period pomera neprijatelja prvo desno pa onda levo. Udaljenost
pomeranja se odreĎuje povećavanjem i smanjivanjem tajmera za pomeranje zigZagTiming.
if(hasZigZag && !playerInRange){
timer += Time.deltaTime;
if (timer < zigZagTiming.x)
zigzag = 3 * player.transform.right;
if (timer >= zigZagTiming.x && timer < zigZagTiming.y)
zigzag = -3 * player.transform.right;
if (timer > zigZagTiming.y)
timer = 0;
transform.position = transform.position + zigzag * Time.deltaTime;
}

35
Virtuelna realnost: Osnove i izrada igara

Slika 6.5: SphereCollider IsTrigger

Neprijatelj se kreće sve dok ne doĎe u dodir sa igračem. Na prefabovima čudovišta


nalazi se SphereCollider, komponenta koja detektuje koliziju, koji na sebi ima štikliranu
opciju IsTrigger (slika 6.5). To označava da će objekat detektovati kada doĎe u dodir sa
nekim drugim kolajderom ali neće napraviti koliziju sa njim. Detekcija dodira vrši se u
funkciji OnTriggerEnter koja kao parametar dobija kolajder sa kojim se objekat sudario (u
ovom slučaju igrač).
void OnTriggerEnter(Collider other){
if (other.gameObject == player)
{
playerInRange = true;
}
}

Kada neprijatelj doĎe u dodir sa igračem, on počinje da ga napada. Napad se vrši


pozivanjem funkcije Attack i izmeĎu napada se pravi pauza onoliko koliko je namešteno na
početku skripte kao brzina napada čudovišta. Attack poziva funkciju TakeDamage iz
skripte PlayerHealth i prosleĎuje nasumice odreĎenu vrednost napada iz intervala koji je
unapred odreĎen za svako čudovište.
timer += Time.deltaTime;
if (timer >= timeBetweenAttacks && playerInRange && currentHealth > 0){
Attack();
}
void Attack(){
timer = 0f;
if (playerHealth.currentHealth > 0){
playerHealth.TakeDamage(
Mathf.FloorToInt(atackMultiplier * Random.Range(
attackDamage.x, attackDamage.y + 1)));
}
}

Stvaranje ili instanciranje neprijatelja vrši se skriptom EnemyManager.cs koja se


nalazi na istoimenom objektu na sceni. Neprijatelji se stvaraju kontinuirano sa pauzom koja
je odreĎena intervalom spawnTime na nasumice izabranoj tački koja se nalazi na Bezierovoj
krivoj. Tip čudovišta koji će se stvoriti zavisi od količine poena koju igrač trenutno ima. Što
više poena, to će se stvarati jača čudovišta sve brţe i brţe.
public class EnemyManager : MonoBehaviour
{
public PlayerHealth playerHealth;
[SerializeField]
public GameObject[] enemies;
public Vector2 spawnTime = new Vector2(3, 5);
public BezierScript bezier;

void Start ()
{
StartCoroutine(spawnHelper());

36
Virtuelna realnost: Osnove i izrada igara

void Spawn ()
{
if (playerHealth.currentHealth <= 0f)
{
return;
}
Vector3 spawnPoint = bezier.getRandomPoint ();
int random = 0;
int specialType = 0;

if (ScoreManager.score <= 50)


{
random = 0;
} else if (ScoreManager.score <= 100)
{
spawnTime = new Vector2(2, 4);
random = Mathf.FloorToInt(Random.Range(0, 2));
specialType = Random.Range(0, 5);
}
else
{
spawnTime = new Vector2(1, 2);
random = Mathf.FloorToInt(Random.Range(0, 3));
specialType = Random.Range(0, 5);
}
GameObject spawnedEnemy = Instantiate(enemies[random], spawnPoint, enemies[random]
.transform.rotation);
spawnedEnemy.SendMessage("setSpecialType", specialType);
}

IEnumerator spawnHelper()
{
while (true)
{
yield return new WaitForSeconds(Random.Range(spawnTime.x, spawnTime.y+1));
Spawn();
}
}
}

Poslednja stvar koju je bitno pomenuti je lokacija instanciranja neprijatelja. Na


početku igre na sceni se stvara Bezierova kriva linija izmeĎu dveju tačaka. Zakrivljenje
linije se podešava trećom (kontrolnom) tačkom. Linija se prostire preko pedeset tačaka čije se
pozicije dobijaju funkcijom CalculateQuadraticBezierPoint. Na kraju funkcija
getRandomPoint vraća jednu od prethodno pomenutih pedeset tačaka.
public class BezierScript : MonoBehaviour
{
public LineRenderer lineRendered;
public Transform p0;
public Transform p1;
public Transform p2;
private int numberOfPoints = 50;
private Vector3[] positions = new Vector3[50];

void Start ()
lineRendered.positionCount = numberOfPoints;
}

void Update (){


DrawQuadraticCurve ();
}

37
Virtuelna realnost: Osnove i izrada igara

private Vector3 CalculateQuadraticBezierPoint (float t, Vector3 p0, Vector3 p1, Vector3


p2) {
return (1-t)*(1-t)*p0 + 2*(1-t)*t*p1 + t*t*p2;
}

private void DrawQuadraticCurve (){


for (int i = 0; i < numberOfPoints; i++)
float t = i / (float)numberOfPoints;
positions [i] = CalculateQuadraticBezierPoint (t, p0.position, p1.position, p2.
position);
}
lineRendered.SetPositions (positions);
}

public Vector3 getRandomPoint (){


int x = Random.Range (0, numberOfPoints);
return positions [x]; }}

7. Oculus prodavnica i developer konzola

Nakon završetka razvoja aplikacije potrebno je dobro testiranje i ispravljanje greški


ukoliko postoje. Najbolje bi bilo da igru testiraju osobe koje ne koriste VR ureĎaj često jer su
developeri navikli na njih i manja je šansa da se javi mučnina ili nelagodnost.
Sledeći korak je objavljivanje igre na Oculus store uz pomoć developer konzole koja
se nalazi na adresi https://dashboard.oculus.com. Ovde imamo opciju za dodavanje nove
aplikacije nakon koje imamo mogućnost odabira platforme na kojoj će se aplikacija ili igra
koristiti (slika 7.1).

Slika 7.1: Odabir platforme

Nakon toga unosimo ime aplikacije i završavamo proces kreiranja nove aplikacije na
konzoli. Da bi se aplikacija objavila potrebno je ispratiti osam koraka na konzoli:
 Build - uploadujemo prethodno zapakovanu aplikaciju i dodajemo testere za nju.
 Specs - odreĎujemo kategoriju u kojoj će se aplikacija nalaziti. Tu su i podešavanja za
internet, kontroler i mogućnost igranja više igrača.
 About - u ovom delu unosimo podatke developera ili kompanije.
 Content Rating - odreĎuje uzrast za koji će aplikacija biti dostupna.
 Translations - ovde unosimo naslov, kratak i dugačak opis aplikacije. Osim toga
moţemo dodati jezike na koje će ova aplikacija biti prevedena.
 Assets - predstavlja korak gde unosimo ikonicu, logo i reklamne slike aplikacije.

38
Virtuelna realnost: Osnove i izrada igara

 Pricing - odreĎuje da li je naša aplikacija besplatna ili ne i njenu cenu ukoliko nije.
 Submit - poslednji korak proverava da li su svi prethodni uslovi ispunjeni i odavde se
aplikacija šalje na proveru.

Ukoliko aplikacija proĎe proveru, biće vrlo brzo dostupna za skidanje na Oculus
storu. Ako iz nekog razloga bude odbijena, biće objašnjeno šta treba da se ispravi. Nakon
ispravke, aplikacija se ponovo šalje na proveru.

8. Zaključak
U ovom radu smo videli neke od osnovnih koncepata programiranja igre za virtuelnu
realnost. Upoznali smo se sa vrstama korisničkog interfejsa, kontrolama i načinom interakcije
korisnika sa virtuelnim svetom. Pomenuti su načini kretanja korisnika kroz svet, kao i veoma
bitna optimizacija da bi to kretanje bilo neometano. Kroz primer smo videli ceo ţivotni ciklus
jedne VR aplikacije, od njenog otvaranja na Oculusu, preko razvoja i dodavanja korisnih
servisa kao što je Firebase, do samog objavljivanja aplikacije u prodavnici. Primer je pravljen
u game engine-u Unity koji tek od skoro ima ugraĎenu podršku za izradu virtuelnih igara.
Bez sumnje Unity i Oculus će raditi na unapreĎivanju razvojnog okruţenja kao i samog
software development kit-a kako bi programerima olakšali izradu aplikacija za virtuelnu
realnost i povećali njene potencijale.

Projekat koji smo videli u ovom radu je samo zagrebao površinu mogućnosti
virtuelnih igara. Daljim radom igra se moţe proširiti dodavanjem novih neprijatelja sa novim
logikama, novih i izmenjenih nivoa gde bi igrač mogao da se naĎe u kabini neke letelice
odakle će se dalje boriti. Firebase nudi mogućnost praćenja statistike gde se moţe videti šta
se korisnicima sviĎa, a šta ne, radi unapreĎivanja igre. Na kraju, Oculus nudi mogućnost
pravljenja “soba” za više igrača gde će nekoliko prijatelja zajedno moći da učestvuju u borbi
protiv neprijatelja.

Izrada kvalitetnih VR igara i uopšte VR produkata predstavlja veliki izazov


programerima današnjice. TakoĎe predstavlja i novi smer u kome se programiranje razvija.
Inovativnost, kreativnost, ali i zabava, svakako su jedne od komponenti VR-a.

Iako savremeni ureĎaji za virtuelnu realnost još uvek nisu dovoljno rasprostranjeni i
postoje tek par godina, imaju veliki potencijal da postanu veoma korišćen posrednik za
izraţavanje, komunikaciju, edukaciju, rešavanje problema i pričanje priča. Naše bake i deke
su učile da koriste pisaće mašine. Našim roditeljima je trebalo da koriste PowerPoint
prezentacije i pretraţuju internet. Naša deca će moći da prave dvorce i teleportuju se sa
jednog na drugo virtuelno mesto. Virtuelna realnost neće zameniti pravi svet i našu ljudskost
već će je samo poboljšati.

39
Virtuelna realnost: Osnove i izrada igara

9. Literatura

[1] Learning Virtual Reality - Tony Parisi


[2] Unity Virtual Reality Projects - Jonathan Linowes
[3] https://en.wikipedia.org/wiki/Virtual_reality
[4] https://www.vrs.org.uk/virtual-reality/history.html
[5] https://en.wikipedia.org/wiki/Unity_(game_engine)
[6] https://en.wikipedia.org/wiki/Oculus_VR
[7] https://developer.oculus.com/
[8] https://dshankar.svbtle.com/performance-optimization-for-vr-apps
[9] https://unity3d.com/learn/tutorials/topics/virtual-reality/vr-overview
[10] http://www.theappguruz.com/blog/bezier-curve-in-games
[11] https://firebase.google.com/docs/unity/setup
[12] http://www.theappguruz.com/blog/unity-xml-parsing-unity

40
Прилог 5/1
ПРИРОДНO - MАТЕМАТИЧКИ ФАКУЛТЕТ
НИШ

КЉУЧНА ДОКУМЕНТАЦИЈСКА ИНФОРМАЦИЈА

Редни број, РБР:


Идентификациони број, ИБР:
Тип документације, ТД: монографска
Тип записа, ТЗ: текстуални / графички
Врста рада, ВР: мастер рад
Аутор, АУ: Филип Стојановић
Ментор, МН: Марко Петковић
Наслов рада, НР:
Виртуелна реалност: Основе и израда игара

Језик публикације, ЈП: српски


Језик извода, ЈИ: енглески
Земља публиковања, ЗП: Р. Србија
Уже географско подручје, УГП: Р. Србија
Година, ГО: 2017.
Издавач, ИЗ: ауторски репринт
Место и адреса, МА: Ниш, Вишеградска 33.
Физички опис рада, ФО: 40 стр. ; граф. прикази
(поглавља/страна/ цитата/табела/слика/графика/прилога)

Научна област, НО: рачунарске науке


Научна дисциплина, НД: развој игара
Предметна одредница/Кључне речи, ПО: виртуелна реалност, Unity, израда игара
УДК 005.311.7
004.42
519.83
Чува се, ЧУ: библиотека
Важна напомена, ВН:

Извод, ИЗ: У овом раду смо видели неке од основних концепта програмирања
игара за виртуелну стварност. Упознали смо се са врстама корисничких
интерфејса, контролама и начином интеракције корисника са
виртуелним светом. Поменути су начини кретања корисника кроз свет,
као и врло битна оптимизација да би то било неометано. Кроз пример
смо видели цео животни циклус једне ВР апликације, од њеног
отварања на Oculus-у, преко развоја и додавања корисних сервиса као
што је Firebase, до објављивања апликације у продавници. Пример је
прављен у game engine-у Unity који тек од скоро има уграђену подршку
за израду виртуелних игара.
Датум прихватања теме, ДП:

Датум одбране, ДО:


Чланови комисије, КО: Председник:
Члан:
Члан, ментор:

Образац Q4.09.13 - Издање 1


Прилог 5/2
ПРИРОДНО - МАТЕМАТИЧКИ ФАКУЛТЕТ
НИШ

KEY WORDS DOCUMENTATION

Accession number, ANO:


Identification number, INO:
Document type, DT: monograph
Type of record, TR: textual / graphic
Contents code, CC: university degree thesis (master thesis)
Author, AU: Filip Stojanović
Mentor, MN: Marko Petković
Title, TI:
Virtual reality: Basis and game development

Language of text, LT: Serbian


Language of abstract, LA: English
Country of publication, CP: Republic of Serbia
Locality of publication, LP: Serbia
Publication year, PY: 2017.
Publisher, PB: author’s reprint
Publication place, PP: Niš, Višegradska 33.
Physical description, PD: 40 p. ; graphic representations
(chapters/pages/ref./tables/pictures/graphs/appendixes)

Scientific field, SF: computer science


Scientific discipline, SD: game development
Subject/Key words, S/KW: virtual reality, Unity, game development

UC 005.311.7
004.42
519.83
Holding data, HD: library

Note, N:

Abstract, AB: In this paper, we have seen some of the basic virtual reality game development
concepts. We have been acquainted with types of user interfaces, controls and
ways of interaction of the user with the virtual world. Types of movements of the
user through the world have been mentioned, as well as optimization, which is of
great importance and ensures that the movements are unobstructed. Through the
example, we have seen an entire life cycle of a VR application, from its opening in
Oculus, through the development and adding of the useful services such as
Firebase, to the application publishing on the Store. The example was developed
in Unity game engine, which has just recently obtained a built-in support for the
development of virtual games.

Accepted by the Scientific Board on, ASB:


Defended on, DE:
Defended Board, DB: President:
Member:
Member, Mentor:

Образац Q4.09.13 - Издање 1

You might also like