RAZVOJ IGRE S POMOČJO UREJEVALNIKA TILED IN KNJIŽNICE LIBGDX

Velikost: px
Začni prikazovanje s strani:

Download "RAZVOJ IGRE S POMOČJO UREJEVALNIKA TILED IN KNJIŽNICE LIBGDX"

Transkripcija

1 Smetanova ulica Maribor, Slovenija Gregor Mohorko RAZVOJ IGRE S POMOČJO UREJEVALNIKA TILED IN KNJIŽNICE LIBGDX Diplomsko delo Maribor, junij 2016

2 RAZVOJ IGRE S POMOČJO UREJEVALNIKA TILED IN KNJIŽNICE LIBGDX Diplomsko delo Študent: Študijski program: Mentor: Gregor Mohorko Univerzitetni študijski program prve stopnje, Računalništvo in informacijske tehnologije doc. dr. Matej Črepinšek

3 I

4 ZAHVALA Rad bi se zahvalil mentorju doc. dr. Mateju Črepinšku za strokovno pomoč in svetovanje pri izdelavi diplomskega dela. Posebej bi se zahvalil svoji družini, za vso podporo in dodatno motivacijo skozi celoten študij. Zahvaljujem se tudi Katji Škorjanc za narisane slike, ki so uporabljene v diplomskem delu. II

5 Razvoj igre s pomočjo urejevalnika Tiled in knjižnice LibGDX Ključne besede: Java, igra, urejevalnik stopnje, Tiled, oblikovanje, implementacija, Android, grafika, Android Studio, LibGDX UDK: 004.4'232(043.2) Povzetek Pri razvoju iger je potrebnih veliko različnih znanj. Igre ne potrebujejo samo programsko kodo, ampak tudi narisane objekte, glasbo, zgodbo ipd. Veliki projekti vključujejo tudi po več sto ljudi. Za učinkovitejše usklajevanje vseh, ki sodelujejo na projektu, se po navadi celoten razvoj razdeli na več korakov. Ločeno, vendar hkratno delo je včasih nujno za dosego časovnih omejitev projekta. Eden izmed načinov, kako delo razvoja ločiti pri ustvarjanju iger, je z uporabo urejevalnika Tiled. V njem lahko razvijalci oblikujejo stopnje brez kakršnega koli programiranja. Medtem pa seveda programerji vzporedno delajo na aplikaciji, ki bo pognala stopnjo iz urejevalnika. V delu smo predstavili funkcionalnost in delo z urejevalnikom Tiled. Praktična uporaba orodja je prikazana na implementaciji naše igre, ki poganja stopnje iz urejevalnika. Igra je narejena s pomočjo knjižnice LibGDX. Za podporo hitremu razvoju smo implementirali možnost nalaganja in prenosa stopnje na strežnik, kar omogoča hkratno testiranje stopenj iz različnih naprav. III

6 Game development using Tiled editor and LibGDX library Key words: Java, game, map editor, Tiled, design, implementation, Android, graphics, Android Studio, LibGDX UDK: 004.4'232(043.2) Abstract Game development requires a lot of different skills. Games do not only need program code, but also art, music, story etc. Big projects can include over a hundred people. In order to effectively coordinate all collaborators, the whole development process is usually split into multiple stages. Working separately, but simultaneously is sometimes necessary to reach the deadlines. One of the ways, how to separate development is by using Tiled editor. In it, developers can design levels without using any kind of programming. Meanwhile, programmers work on the application which will run the level from the editor. In thesis we presented functionality and work with the Tiled editor. Its practical use is showed on implementation of our game, which runs its levels. The game is created using LibGDX library. To support faster development, we implemented the ability to upload and download the level on our server, which enables simultaneous testing from various devices. IV

7 KAZALO VSEBINE 1 UVOD POMEMBNI KORAKI PRI RAZVOJU IGER Koncept Oblikovanje Programiranje UREJEVALNIK TILED Funkcionalnosti Tlakovanje Plasti Slike Beleženje Objekti Ukazi Risanje stopnje KNJIŽNICA LIBGDX Priprava okolja IZDELAVA IGRE Načrt Implementacija Zasloni Opravila Kontrole Grafika Animacija Igra V

8 Objekti Igralec Objekti iz urejevalnika Stopnja SKLEP VIRI VI

9 KAZALO SLIK SLIKA 1: PRIMERJAVA KONCEPTNE IN DEJANSKE SLIKE GLAVNEGA JUNAKA... 2 SLIKA 2: KONCEPTNA SKICA OBLIKE TESTNE STOPNJE... 4 SLIKA 3: PRAZNO DELOVNO OKOLJE UREJEVALNIKA TILED... 5 SLIKA 4: SLIKE PLOŠČIC RAZLIČNIH VELIKOSTI... 6 SLIKA 5: TRI POSAMEZNE PLASTI IN NJIHOVA ZDRUŽITEV... 7 SLIKA 6: OKENCE ZA NOVO STOPNJO SLIKA 7: OKENCE ZA NOVO ZBIRKO PLOŠČIC SLIKA 8: PRIMER ZBIRKE PLOŠČIC SLIKA 9: ŽIG ČOPIČ ZA RISANJE 1X1 GRADNIKOV SLIKA 10: STOPNJA, NARISANA V UREJEVALNIKU TILED SLIKA 11: OKENCE ZA NAMESTITEV NOVEGA LIBGDX PROJEKTA SLIKA 12: POTEK DELA ZAGONA APLIKACIJE V PRIVZETEM NAČINU SLIKA 13: RAZREDNI DIAGRAM DELEGIRANJA APLIKACIJSKIH DOGODKOV ZASLONU SLIKA 14: DIAGRAM RAZREDOV, KI PREDSTAVLJAJO ZASLON SLIKA 15: RAZREDNI DIAGRAM OPRAVIL SLIKA 16: RAZREDNI DIAGRAM KONTROL SLIKA 17: SLIKE ANIMACIJE NETOPIRJA MED LETENJEM SLIKA 18: RAZREDNI DIAGRAM OBJEKTOV SLIKA 19: POSNETEK IZ IGRE, KO JE IGRALEC IZVEN SOVRAŽNIKOVEGA DOMETA VIDA SLIKA 20: POSNETEK IZ IGRE, KO JE IGRALEC ZNOTRAJ SOVRAŽNIKOVEGA DOMETA VIDA SLIKA 21: PRIMERJAVA MEJE, PRIDOBLJENE IZ SLIKE, IN ŽELENE MEJE SLIKA 22: POSNETEK IZ IGRE, KJER JE KAMERA CENTRIRANA NA CENTER IGRALCA VII

10 SEZNAM UPORABLJENIH SIMBOLOV IN KRATIC Simbol/Kratica Pomen CSV LibGDX OpenGL ES TMX XML Comma-Separated Values Knjižnica za razvoj iger Open Graphics Library for Embedded Systems Tile Map XML Extensible Markup Language VIII

11 1 UVOD Razvoj igre je razdeljen na več korakov, ki se med seboj različno prepletajo. Velikokrat jih neodvisni razvijalci iger sploh ne ločijo, zaradi česar se pri obsežnejših projektih v nadaljevanju razvoja»izgubijo«oz. traja razvoj dlje časa, kot bi sicer. Obstaja veliko različnih tipov iger, pri večini pa se igra dogaja v nekem okolju, pri čemer je na takšen ali drugačen način prisotna stopnja (angl. level). Kakovost takšnega tipa igre je odvisna od načrta stopnje in same implementacije, še posebej kadar se v igri zelo veliko skače in je tekoče delovanje zelo pomembno. Oba koraka sta torej nadvse pomembna in se prepletata. Z razčlenitvijo oblikovanja stopnje in implementacije bomo poskušali preplet teh dveh korakov olajšati in izboljšati. V diplomskem delu smo opisali in predstavili razvoj igre s pomočjo urejevalnika Tiled in knjižnice LibGDX. Podrobneje smo predstavili urejevalnik Tiled, njegove funkcionalnosti in kako v njem oblikovati stopnjo. Opisali smo tudi implementacijo igre tipa»staro-šolski side-scrolling platformer«, pri čemer smo uporabili knjižnico LibGDX. V drugem poglavju smo opisali tri ključne korake pri razvoju iger in vključujejo stopnje. V naslednjem poglavju smo podrobneje predstavili urejevalnik Tiled, opisali njegove funkcionalnosti in predstavili primer stopnje. V četrtem poglavju smo na kratko predstavili knjižnico LibGDX in kako si pripraviti okolje za začetek dela. V petem poglavju smo izdelali igro. Najprej smo sestavili načrt, nato pa začeli z implementacijo in podrobneje opisali uporabljene metode iz knjižnice, prav tako pa tudi naše lastne ustvarjene razrede. V zadnjem poglavju smo podali zaključne misli in ideje za nadaljnje delo. 1

12 2 POMEMBNI KORAKI PRI RAZVOJU IGER Proces razvoja igre se danes zelo razlikuje od tistega izpred dvajsetih let. Danes je industrija iger precej večji posel, kar se izraža na kvaliteti in dovršenosti produktov. Igra potrebuje ne samo programsko kodo, ampak tudi narisane objekte, teksture, glasbo, posnete govore ipd. Proces razvoja iger se je torej zelo razširil in pri velikih projektih vključuje po več sto ljudi, ki delajo hkrati. Za učinkovitejše usklajevanje vseh, ki sodelujejo na projektu, se po navadi celoten razvoj razdeli na več korakov [1]. Kjer se celoten razvoj ne razdeli na korake in se nasploh slabo načrtuje, lahko pride do prekoračitve proračuna ali pa časovne omejitve, zaradi česar po navadi končni produkt vsebuje veliko programskih napak (t. i. hroščev). Da bi se temu izognili, smo v nadaljevanju opisali tri najpomembnejše korake pri razvoju iger. 2.1 Koncept Koncept predstavlja opis igre: zgodba, tip, opis igralnih značilnosti, posebnosti itd. Umetniki narišejo grobe slike okolice in karakterjev. Programerji razvijejo hiter in grob prototip, ki predstavlja glavne značilnosti, ki naj bi zaznamovale končni produkt. V tem koraku se torej zamisli ideja o igri, njen splošen občutek in motiv. Če zgodba vključuje večje in pomembnejše protagoniste in/ali antagoniste, se le-ti vedno narišejo, za lažje poosebljanje v nadaljnjih korakih. Primer konceptno narisanega glavnega junaka iz naše igre je viden na Slika 1. Slika 1: Primerjava konceptne in dejanske slike glavnega junaka 2

13 2.2 Oblikovanje Oblikovanje igre vključuje načrtovanje več stvari, ki skupaj sestavljajo celotno vsebino igre: zgodbo, zvočne elemente, glasbo, grafični stil, način igranja, pravila ipd. V tem koraku se pravzaprav zamisli in začrta, kako naj bi izgledal končni produkt. Velikokrat potem v nadaljnjih korakih pride do kakšnih manjših sprememb, ampak načeloma se je dobro držati začrtane poti. Skoraj vse igre imajo stopnje. Gre za celotno igralno območje, po katerem se igralec lahko premika. Večinoma so stopnje območja nekega večjega igralnega sveta, skozi katerega potuješ med zgodbo. Med seboj so lahko povezane ali pa tudi ne. Če so povezane, to pomeni, da ko dosežeš konec neke stopnje, potem na navidezno enakem mestu začneš pri naslednji. Torej obe stopnji skupaj pravzaprav sestavljata neko večjo lokacijo. Oblikovanje stopenj je zelo pomembno, saj zagotavlja igralcem nek namen in prijetno izkušnjo igranja. Kvalitetna stopnja je zanimiva, razgibana, skrivnostna, zabavna, napeta, vsebuje različne zaporedne animacije, se prepleta z zgodbo in jo dopolnjuje. Vsaka stopnja ima torej nek namen, po navadi je to najmanj en cilj, ki ga je potrebno doseči. V naši igri bo cilj vsake navadne stopnje doseči izhodna vrata. Za večjo kompleksnost je potrebno najprej pridobiti še ključ za izhodna vrata. Slika 2 prikazuje primer skice testne stopnje za našo igro. Igralec začne na levi strani in se mora prebiti do desne strani. Najprej pa mora iti še v jamo oz. ječo pod površjem, v kateri se nahaja ključ. 3

14 Slika 2: Konceptna skica oblike testne stopnje 2.3 Programiranje Igre potrebujejo zahtevne algoritme in dobro razumevanje kompleksnih tehnik. Najosnovnejša potrebna znanja vključujejo razumevanje računalniške grafike, zvoka, animacije ter branje iz vhoda. Dodatna znanja pa so matematika, fizika, umetna inteligenca, simulacije ipd., pri večigralskih igrah pa tudi spletno programiranje in podatkovne baze. Programiranje video iger je torej postalo kar kompleksno in vključuje različne sklope računalniških in drugih tehnologij. Za programerje ni nujno, da sodelujejo pri oblikovanju stopenj in pisanju zgodbe. Lahko le sledijo začrtanim oblikovalskim zamislim in jih poskušajo na najboljši način implementirati. Tako se ne potrebujejo obremenjevati z vsebino, ampak le s praktično izvedbo ideje. Kadar pride pri implementaciji do kakšnih omejitev, se z oblikovalci dogovori o alternativi, načeloma pa se skuša čim učinkoviteje sprogramirati vse zamisli. 4

15 3 UREJEVALNIK TILED Tiled je odprtokoden program za oblikovanje stopenj pri dvodimenzionalnih igrah [2]. Njegova uporaba za sam razvoj igre ni nujna, je pa zelo priporočljiva, saj se z njegovo pomočjo lažje in hitreje oblikuje vsebino igre. Njegova največja prednost je ta, da je zelo preprost za uporabo. Oblikovalci lahko brez vsakršnega zahtevnega znanja preprosto oblikujejo stopnje s pomočjo enakih grafičnih sličic, kot se uporabijo tudi v sami igri. Grafični vmesnik je dokaj enostaven. Ustvarjen je bil s pomočjo Jave, zato deluje na vseh namiznih platformah. Prazno delovno okolje na operacijskem sistemu Windows je videno na Slika 3. Slika 3: Prazno delovno okolje urejevalnika Tiled 3.1 Funkcionalnosti Glavna značilnost urejevalnika Tiled je oblikovanje stopenj s pomočjo tlakovanja ploščic, omogoča pa tudi prosto pozicioniranje slik in beleženje dodatnih lastnosti, ki se nato upoštevajo v sami igri. 5

16 3.1.1 Tlakovanje Tlakovanje s ploščicami (angl. tiles) v mreži je najbolj pogost in preprost način opisa stopnje. Ploščice so po navadi pravokotne, zaradi česar je sama implementacija v igri zelo preprosta, saj se lahko mreža ploščic predstavi kot preprosta dvodimenzionalna tabela. Velikost celotne mreže se opiše s pomočjo ploščic, ki je torej najmanjša enota. Objekti v stopnji so lahko različnih velikosti, mora pa velikost biti deljiva s ploščicami, videno na Slika 4. Osnovna in tudi najmanjša velikost je 1x1 ploščica, lahko pa je tudi 1x2, 2x2, 3x2 itd., pri čemer se seveda vse ploščice, ki jih sličica večjega objekta zapolni, pojmujejo kot zasedene. Slika 4: Slike ploščic različnih velikosti Plasti S pomočjo plasti lahko stopnjo razdelimo na več nivojev, ki se med seboj prekrivajo. V dvodimenzionalnih svetovih (risanke, igre, stripi ipd.) se plasti uporabljajo iz več razlogov: vsaka plast ima različno globino, ki predstavlja navidezno razdaljo od gledalca in določa vrstni red izrisa (Slika 5), s tem dosežemo občutek globine in imamo lahko izrisano ozadje, nad njim pa ostale objekte, vsaka plast lahko predstavlja neko določeno funkcionalnost, tako imamo npr. v eni plasti ozadja, v drugi sovražnike, v tretji zidove, v četrti prožilce itd., ploščice znotraj neke plasti so ločene od ploščic v ostalih plasteh, zato oblikovalec laže ureja neko specifično območje, npr. kadar pozicionira samo sovražnike, se ne obremenjuje, da bi s tem na kakršen koli način po pomoti izbrisal kaj drugega, 6

17 ker se plasti med seboj prekrivajo po površini, lahko imamo na enaki poziciji več različnih sličic, kar drugače ne bi bilo mogoče. Slika 5: Tri posamezne plasti in njihova združitev Tiled pozna tri vrste plasti: Plast ploščic (angl. Tile Layer): ta tip je najbolj običajen, v njem se rišejo ploščice. Plast objektov (angl. Object Layer): v njega lahko rišemo različne like in vstavljamo slike. Objekte lahko prosto pozicioniramo po prostoru (ni jih potrebno zakleniti na mrežo) in jim spreminjamo velikost in razmerje slike. Plast slike (angl. Image Layer): celotno plast predstavlja ena sama velika slika. Ta tip bomo uporabili za ozadja, saj so po navadi sestavljena iz več plasti velikih slik Slike Večje slike, ki niso ploščice (v našem primeru npr. začetna zastavica, izhodna vrata itd.) lahko dodamo kot Zbirko slik (angl. Collection of Images) in v njo dodajamo»ploščice«, ki so lahko različne velikosti in jih enako kot druge ploščice rišemo na mrežo. Lahko jih uporabimo tudi kot objekte znotraj plasti objektov in jim nato še spremenimo velikost. 7

18 3.1.4 Beleženje Tiled nam omogoča, da beležimo dodatne lastnosti celotni stopnji, posameznim plastem in ploščicam. Prav zaradi te funkcionalnosti lahko vse o stopnji zabeležimo že kar v urejevalniku Tiled: označimo, za kakšno vrsto stopnje gre, označimo, ali se določene plasti premikajo z igralcem ter kako hitro se premikajo, označimo, katere ploščice predstavljajo sovražnike, ob katere se igralec zaleti ipd. Kadar imamo neko stvar izbrano, se v okencu Lastnosti (angl. Properties) prikažejo njene lastnosti. Tukaj lahko pod sekcijo Lastnosti po meri (angl. Custom Properties) dodamo nove lastnosti. Vsaki lastni lastnosti dodelimo ime, tip in vrednost. Tip je lahko bool, int, float ali string. Primer lastnosti tipa string je lastnost»kontrola_?_akcija«(vprašaj zamenjamo z zaporedno številko kontrole). Ta lastnost pove, katero akcijo ta kontrola predstavlja. Dovoljene vrednosti so»premik-levo«,»premik-desno«in»skok« Objekti Objekti se dodajajo v plast objektov in so lahko različnih oblik in velikosti. Prazen objekt v sami igri ne bo viden igralcu. Razlog za uporabo teh objektov je ta, da jim lahko dodelimo nek vnaprej pripravljen tip, ki služi določenemu namenu. Recimo, dva osnovna tipa objekta sta lahko začetek in konec, ki ponazarjata, kje se stopnja začne in konča. Ostali tipi so lahko prožilci, nadzorna točka, skratka, karkoli. Vsak tip ima svojo barvo, lahko pa ima tudi že vnaprej določene lastnosti po meri, da jih ni potrebno vedno znova ustvarjati. Tipe objektov definiramo tako, da v glavnem meniju izberemo 'View -> Object Types Editor'. Pokaže se nam okence za dodajanje tipov in urejanje njihovih lastnosti Ukazi Ukazi v lupino operacijskega sistema nam bodo omogočili, da bomo našo igro pognali kar iz urejevalnika Tiled [3]. Ustvarimo si lahko poljubno mnogo ukazov, vsakemu ukazu pa dodelimo argumente. Tako lahko imamo npr. ukaze, ki poženejo igro iz določene nadzorne točke. 8

19 Novi ukaz ustvarimo tako, da v orodni vrstici pri ukazih izberemo Uredi ukaze (angl. Edit Commands). Odpre se nam okence, v katerem je seznam ukazov. Tukaj lahko spreminjamo in/ali dodajamo nove ukaze. Ukaz za zagon naše aplikacije v načinu poženi izgleda takole:»java -jar ImeIgre.jar pozeni %mapfile«. Ta ukaz bo pognal našo aplikacijo ImeIgre.jar z dvema argumentoma: prvi pove način, drugi pa je pot do datoteke stopnje. 3.2 Risanje stopnje Preden lahko začnemo risati stopnjo, jo moramo najprej ustvariti. To storimo tako, da v glavnem meniju izberemo možnost 'File -> New...'. Pokaže se okence (videno na Slika 6), kjer izberemo nastavitve nove stopnje: Orientacija (angl. Orientation): Tiled omogoča ortogonalno in izometrično orientacijo. Pri ortogonalni ima mreža pravilne kote, kar je primerno za igre, kjer je kamera usmerjena pravokotno proti dogajanju, kot, recimo, v naši igri. Pri izometrični pa je mreža diagonalna, kar je primerno za igre, kjer gledalec opazuje iz ptičje perspektive in je kamera usmerjena proti dogajanju pod kotom. Format plasti ploščic (angl. Tile layer format): način zapisa ploščic v posamezni plasti v končni datoteki. Omogočena sta formata CSV, v katerem so ploščice znotraj ene plasti predstavljene kot številke, ki so ločene z vejico, in format Base64, v katerem so ploščice zapisane v binarni obliki. Zaporedje izrisovanja ploščic (angl. Tile render order): Tiled privzeto izrisuje ploščice tako, da začne pri najvišji vrstici, od leve proti desni. Lahko pa se zgodi, da takšno zaporedje ni najboljše. To naredimo takrat, ko želimo ustvariti občutek, da je kamera usmerjena proti dogajanju malce z leve in so tudi teksture tako narisane. Takrat izberemo možnost, pri kateri izrisovanje poteka z desne proti levi. Velikost stopnje (angl. Map size): velikost stopnje v ploščicah. Velikost ploščice (angl. Tile size): velikost ploščice v pikslih. Naša igra bo imela zelo pikslasto grafiko, zato je velikost 8 pikslov dovolj. 9

20 Slika 6: Okence za novo stopnjo Zbirke ploščic Sedaj imamo prazno mrežo, nimamo pa še naloženih sličic, s katerimi bomo risali. Tiled omogoča zbirke ploščic. To je pravzaprav večja slika, ki je sestavljena iz več enako velikih sličic oz. ploščic. Novo zbirko ploščic naložimo tako, da v glavnem meniju izberemo možnost 'Map -> New Tileset...'. Pokaže se okence (videno na Slika 7), v katerem nastavimo ime zbirke, tip, izvirno sliko, velikost ploščic, debelino robov, razmike, ali želimo, da se določena barva prezre. Primer ene izmed zbirk, ki bo uporabljena v naši igri, je viden na Slika 8. Velika je 4x4 ploščice, sestavljena pa je iz 6-ih različnih ploščic opek, 3-eh ploščic ploščadi in 6-ih ploščic zemlje. Pri tej zbirki se»roza«barva ignorira. Na desni so z zeleno označene meje med ploščicami in pa številke ploščic. Številčenje se vedno začne zgoraj in gre z leve proti desni. 10

21 Slika 7: Okence za novo zbirko ploščic Slika 8: Primer zbirke ploščic Orodja za risanje Glavno orodje za risanje ploščic po mreži je Žig čopič (angl. Stamp Brush), s katerim učinkovito polagamo ploščice. Žig čopič polaga tisto ploščico, ki jo imamo trenutno izbrano v zbirki ploščic. V primeru, da imamo v zbirki ploščic izbranih več ploščic, omogoča dva načina tlakovanja: Privzeti način: čopič bo risal vse izbrane ploščice naenkrat, v enaki razporejenosti kot na zbirki ploščic. Naključni način (angl. Random Mode): čopič bo risal le eno ploščico naenkrat, pri čemer bo za vsak korak naključno izbral eno izmed vseh izbranih. Pri lastnostih posameznih ploščic lahko nastavimo tudi njeno verjetnost, če želimo, da se določena ploščica pojavlja večkrat ali manjkrat. 11

22 Lahko si ustvarimo in shranimo čopiče oz. lastne nastavitve za Žig čopič. Recimo, da želimo risati samo gradnike velikosti 1x1. Iz zbirke ploščic na Slika 8 izberemo najprej vse opeke (ploščice od 1 do 6), v okencu Žigi ploščic (angl. Tile Stamps) kliknemo na gumb 'Add New Stamp' in že imamo lasten Žig čopič, s katerim bomo risali opeke. Čopič lahko ima tudi več variacij: naš pravkar ustvarjeni Žig čopič, s katerim želimo risati vse gradnike velikosti 1x1, ima zaenkrat samo eno variacijo, s katero lahko rišemo samo opeke. Lahko pa si ustvarimo novo variacijo, s katero bomo risali ploščice zemlje. To storimo tako, da v zbirki ploščic izberemo vse ploščice zemlje (ploščice od 10 do 15), izberemo že ustvarjeni čopič in kliknemo na gumb Dodaj variacijo (angl. Add Variation). Sedaj imamo čopič, viden na Slika 9, s katerim lahko rišemo opeke, zemljo ali pa oboje hkrati. Slika 9: Žig čopič za risanje 1x1 gradnikov Poleg Žig čopiča, najdemo v orodni vrstici še nekaj ostalih orodij: Sektorsko polnjenje (angl. Bucket Fill): zapolni vsa označena polja s ploščicami, prav tako podpira naključni način. Radirka (angl. Eraser): briše posamezne ploščice. Pravokotno označevanje (angl. Rectangular Select): označi več polj v obliki pravokotnika. Magična palica (angl. Magic Wand): iz označene ploščice navzven označi vse ploščice, ki so ji podobne. To je uporabno v več primerih, recimo, kadar imamo prazno polje, ki bi ga želeli na hitro označiti in sektorsko zapolniti, saj bo magična palica avtomatsko označila celotno prazno polje. 12

23 Izberi enake ploščice (angl. Select Same Tile): izbere vse ploščice na celotni mreži, ki so enake kot izbrana. To je uporabno, kadar želimo vse pojavitve neke ploščice zamenjati z drugo. Narisana stopnja S pomočjo opisanih tehnik in orodij smo v urejevalniku Tiled narisali prvo stopnjo (videno na Slika 10), ki je bila oblikovana po testni stopnji s Slika 2. Slika 10: Stopnja, narisana v urejevalniku Tiled 13

24 4 KNJIŽNICA LIBGDX Za implementacijo bomo uporabili knjižnico LibGDX. Ta knjižnica je odprtokodna, podpira razvijanje za več platform hkrati in je v glavnem namenjena za neodvisne razvijalce iger. Veliko diplomskih del je že uporabilo to knjižnico in podrobneje opisalo njene glavne lastnosti. Če želite izvedeti več, si to lahko preberete v kateri izmed omenjenih diplomskih del [4] [5] [8] ali pa na uradni spletni strani knjižnice [7]. Jaz bom na kratko opisal samo, kako si pripraviti delovno okolje, da lahko začnemo. 4.1 Priprava okolja Integrirano razvojno okolje Knjižnica se programira v programskem jeziku Java, zatorej potrebujemo urejevalnik, ki ga podpira. Odločili smo se za Android Studio, ki je uraden urejevalnik za razvoj aplikacij v operacijskem sistemu Android [9]. Je zastonj in se lahko prenese z uradne spletne strani, kjer so tudi navodila za namestitev. Projekt knjižnice LibGDX Sedaj si z uradne spletne strani knjižnice LibGDX lahko prenesemo njeno izvršljivo datoteko za namestitev [10]. Odpre se nam okence za namestitev novega projekta, videno na Slika 11. Tukaj si uredimo nastavitve našega novega projekta: ime, ime paketa, ime glavnega razreda igre, destinacijo, različico knjižnice LibGDX, izberemo, za katere platforme želimo razvijati (v našem primeru samo za Desktop in Android) ter katere razširitve želimo zraven. 14

25 Slika 11: Okence za namestitev novega LibGDX projekta Sedaj imamo ustvarjen projekt in ga lahko odpremo v izbranem integriranem razvojnem urejevalniku Android Studiu. V glavnem meniju izberemo 'File -> Open...', izberemo mesto, kjer smo v prejšnjem koraku ustvarili projekt in že lahko začnemo. LibGDX vedno ustvari projekt, v katerem je mapa z imenom»core«. V njej je poglavitna koda, ki je skupna vsem platformam. Na začetku je v njej samo razred z imenom naše igre, ki jo predstavlja. Poleg mape»core«ustvari še mapo za vsako posamezno platformo, ki smo jo izbrali pri ustvarjanju projekta. V vsaki mapi platforme pa so specifične datoteke, ki so potrebne za izbrano platformo. V našem primeru sta to mapi»desktop«in»android«. V prvi je samo en razred, imenovan»desktoplauncher«, v katerem definiramo nastavitve za aplikacijo na računalniku. V drugi pa so poleg razreda»androidlauncher«še ikone, manifest datoteka, dve datoteki XML za shranjevanje besedil in mapa»assets«, v katero dodamo vse dodatne datoteke, ki jih bomo potrebovali v igri (recimo, pisave). 15

26 5 IZDELAVA IGRE Veliko diplomskih nalog je že bilo napisanih na temo implementacije iger, kjer so podrobno opisane vse nujne strukture iger. Pri tem poglavju se bom omejil na tiste dele razvoja igre, ki so specifični pri razvoju iger s stopnjo. Igra torej ne bo vsebovala vseh funkcionalnosti, ki jih po navadi srečamo pri igrah (npr. meni, nastavitve, izbira stopenj ipd.), saj te funkcionalnosti presegajo okvirje te diplomske naloge. Nekaj o teh funkcionalnostih si lahko preberete v knjigi LibGDX Game Development Essentials [6]. 5.1 Načrt Ideja naše igre je ta, da se vse potrebne vsebine stopnje ustvarijo že v urejevalniku Tiled, brez potrebnega znanja programiranja. Sama aplikacija nato pridobi vse potrebne datoteke, jih naloži in požene. S tem dosežemo, da se programer ne obremenjuje s samo vsebino, pač pa samo z abstraktno implementacijo, medtem ko oblikovalec samo z vsebino stopnje. Naš končni izdelek seveda ne bo tisti, ki bi ga kot razvijalec iger dali v produkcijo, pač pa bo izdelek, s katerim bi lahko oblikovalec oblikoval neomejeno število različnih stopenj. In medtem ko oblikovalec oblikuje stopnje, lahko programer implementira druge elemente igre, ki niso povezani s samo stopnjo in dogajanjem v njej (npr. menu, sistem izbiranja stopenj, točkovanja, shranjevanje, povezljivost ipd.). V zadnjem odstavku Priprava okolja sem omenil, da je v projektu prisotna mapa»assets«, v katero naj bi dodali vse dodatne datoteke. Pod te datoteke načeloma sodi tudi naša stopnja in slike. To mapo bi v končnem izdelku, ki bi ga nato dali v produkcijo, seveda uporabili. Na žalost pa smo za naš projekt prisiljeni poiskati alternativo, saj se datoteke iz te mape zapakirajo skupaj s končno izvršljivo datoteko le pri prevajanju projekta. Mi pa seveda nočemo, da bi oblikovalec moral vedno, ko bi karkoli spremenil, ponovno prevajati celoten projekt in ga zaganjati. Za dosego neodvisnosti od platforme smo se odločili, da bomo vse potrebne datoteke iz urejevalnika Tiled s pomočjo ukaza najprej naložili na naš strežnik, nato pa se lahko igra požene od kjerkoli in s katerekoli platforme, saj se bo vse potrebno preneslo s strežnika. 16

27 Slika 12: Potek dela zagona aplikacije v privzetem načinu S Slika 12 lahko vidimo potek dela ob privzetem načinu zagona. Najprej se prenesejo vse datoteke s strežnika. Nato se prebere datoteko z opisom stopnje in preveri, če so prisotne vse datoteke, ki jih stopnja potrebuje. Če niso ali pa če stopnja ne izpolnjuje vseh nujnih zahtev (npr. ne vsebuje objekta za pozicijo starta in/ali konca), se izpiše napaka in njen razlog. V primeru, da stopnja izpolnjuje vse nujne zahteve in nima drugih napak, se prikaže in igra se lahko začne. Različica za računalnik bo poleg osnovnega načina vsebovala še način»naloži na strežnik«ter»poženi«. Prvi bo vse potrebne datoteke stopnje naložil na strežnik, slednji pa bo stopnjo zagnal kar iz datotek na računalniku, namesto tistih na strežniku. 5.2 Implementacija Knjižnica LibGDX je predvsem uporabna zaradi lažjega komuniciranja z okoljem. V ta namen ima implementirane vmesnike, ki enkapsulirajo delo z okoljem: Aplikacija (angl. Application). Grafika (angl. Graphics): komunikacija z grafičnim procesorjem. Zvok (angl. Audio): upravljanje zvočnih virov. Datoteke (angl. Files): dostop do datotečnih sistemov. Vhod (angl. Input): vmesnik za vhodne naprave. 17

28 Instance vseh teh vmesnikov vsebujejo (kot statične lastnosti) statičen razred Gdx. Načeloma je to napačna zasnova, ampak v tem primeru je ta način boljši kot pa alternative. Zaradi statičnosti objektov je delo z okoljem preprosto in dosegljivo vsepovsod. Ob stvaritvi projekta je bil ustvarjen razred z imenom naše igre ImeIgre. Ta razred privzeto implementira vmesnik ApplicationListener. Le-ta poskrbi za urejanje aplikacijskih dogodkov in vsebuje vse potrebne metode za izvajanje aplikacije: Ustvari (angl. Create): se pokliče, ko je aplikacija zagnana. Spremeni velikost (angl. Resize): se pokliče, ko se aplikaciji spremeni velikost. Izris (angl. Render): se pokliče, ko naj bi se aplikacija izrisala (vsako iteracijo glavne zanke). Pavza (angl. Pause): se pokliče, ko operacijski sistem prekine delovanje aplikacije (npr. prejet klic na telefonu) ali preden se aplikacija zapre. Nadaljuj (angl. Resume): se pokliče, ko igra spet pridobi poglaviten poudarek v operacijskem sistemu in naj bi se igra nadaljevala iz stanja pavze. Odstrani (angl. Dispose): se pokliče, ko se aplikacija zapre (po klicu metode Pavza). Znotraj tega razreda bi lahko napisali celotno logiko igre, ampak to bi seveda povzročilo velik nered. Kadar je igra v meniju, je dogajanje povsem različno od dogajanja med igranjem, zato je zaželena ločitev kode. V knjižnici zato obstaja abstrakten razred Game, ki implementira vmesnik ApplicationListener na način, da posamezne metode vmesnika delegira trenutno aktivnemu zaslonu (angl. Screen), videno na Slika 13. Posamezno dogajanje se tako omeji na posamezni objekt zaslona. To omogoči lažje in bolj urejeno implementacijo ločenih dogajanj. Primer uporabe zaslonov za implementacijo menija med igranjem Za meni ustvarimo razred ZaslonMeni, za igranje stopnje pa ZaslonIgra. Oba implementirata vmesnik Screen. Če je trenutno aktiven zaslon ZaslonIgra in igralec pritisne tipko za prikaz menija, se bo zaslon ZaslonIgra pavziral, kot aktiven zaslon pa se bo postavil ZaslonMeni. Ko se bo igralec odločil, da želi nadaljevati, se bo kot aktiven zaslon postavil ZaslonIgra. 18

29 Slika 13: Razredni diagram delegiranja aplikacijskih dogodkov zaslonu V našem razredu ImeIgre, ki sedaj razširja abstraktni razred Game, imamo tako namesto nereda le metodo ustvari. Ta razred pravzaprav predstavlja našo igro, zato mu lahko kot lastnosti nastavimo objekte, ki se bodo uporabljali čez celotno igro: Pisave različnih velikosti (angl. Font). Grafični paket (angl. SpriteBatch): za hitrejše izrisovanje velike količine pravokotnih tekstur, saj jih vse skupaj najprej združi v paket in optimizira za procesiranje grafičnega procesorja. Deluje z OpenGL ES 2.0 vmesnikom in uporablja lasten privzet senčilnik (lahko bi ustvarili tudi lasten senčilnik in mu ga nastavili). 19

30 Kamera (se uporablja samo za izris pisave): obstajata perspektivna in ortografska. Ker je naša igra dvodimenzionalna, so vse uporabljene kamere ortografske. Kadar kameri spremenimo velikost vidnega polja, posodobimo njene matrice. Če želimo, da se objekti na ekran izrisujejo s koordinatami te kamere, grafičnemu paketu nastavimo projekcijsko matrico na skupno matrico te kamere. Te lastnosti ne inicializiramo v konstruktorju kot po navadi, ampak v metodi ustvari. Do njih nato dostopamo preko statičnega objekta instance, saj je razred oblikovan po modelu načrtovalskega vzorca»singleton«. Ob zagonu igre ni aktivnega zaslona, zato moramo znotraj metode ustvari to storiti mi in kot aktiven zaslon postavimo ZaslonOpravilo Zasloni Vmesnik Screen vsebuje podobne metode kot vmesnik ApplicationListener: Pokaži (angl. Show): se pokliče, ko zaslon postane aktiven. Spremeni velikost (angl. Resize). Izris (angl. Render). Pavza (angl. Pause). Nadaljuj (angl. Resume). Odstrani (angl. Dispose). Skrij (angl. Hide): se pokliče, ko se drugi zaslon postavi kot aktiven. Metode brez dodatnega opisa imajo enako funkcijo kot pri vmesniku ApplicationListener, pokličejo pa se samo, kadar je ta zaslon aktiven. Če je, recimo, trenutno aktiven zaslon z1, nato pa postavimo kot aktiven zaslon z2, se zgodi sledeče: pokliče se metoda skrij v zaslonu z1, nato se pokliče metoda pokaži znotraj zaslona z2. Nato se vse ostale metode (spremeni velikost, izris, pavza in nadaljuj) kličejo samo nad zaslonom z2. Metoda odstrani se nikoli ne pokliče avtomatsko in jo moramo poklicati sami, kadar vemo, da zaslon ne bo nikoli več uporabljen. Na Slika 14 so prikazani razredi, ki izhajajo iz vmesnika Screen. Abstrakten razred OsnovniZaslon je prazen razred, ki implementira nekatere metode, vendar v njih ne naredi 20

31 ničesar. Implementira jih samo zato, ker teh metod v dejanskih zaslonih ne bomo nikoli uporabili. Uporabili bi jih kasneje, pri implementaciji ostalih funkcionalnostih igre, ki pa se jih v tem diplomskem delu ne bomo dotaknili. Slika 14: Diagram razredov, ki predstavljajo Zaslon ZaslonOpravilo Zaslon ZaslonOpravilo opravlja neko večje in zahtevnejše opravilo. Zaradi večje odzivnosti aplikacije med izvajanjem opravila se opravila opravljajo v odzadnji niti. V naši igri imamo tri različna opravila: Naloži: nalaganje datotek na strežnik. Prenesi: prenašanje datotek s strežnika. Poženi: pripravljanje igre. 21

32 Katero opravilo se bo opravljalo, se določi glede na način zagona aplikacije. Nato v metodi pokaži poženemo opravilo. Dokler se opravilo izvaja, se bo v metodi izris izpisovalo ime opravila in pa trenutni proces. Ko se opravilo zaključi, preveri, ali je bilo uspešno zaključeno. V primeru, da je prišlo do napake, se kot aktiven zaslon postavi ZaslonNapaka. V nasprotnem primeru pa se glede na trenutno opravilo zgodi sledeče: če je trenutno opravilo nalaganje datotek na strežnik, izpiše "Uspešno končano", če je trenutno opravilo prenašanje datotek iz strežnika, se kot aktiven zaslon ponovno postavi ZaslonOpravilo, le da bo v tej instanci opravilo pripravljanje igre, če pa je trenutno opravilo pripravljanje igre, se kot aktiven zaslon postavi ZaslonIgra. ZaslonNapaka Preprost zaslon, ki samo izpiše, da je prišlo do napake. ZaslonIgra V zaslonu ZaslonIgra se odvija igranje stopnje. Na začetku inicializiramo stopnjo. Nato pa vsako iteracijo glavne zanke stopnjo posodobimo in izrišemo Opravila Ustvarili smo abstrakten razred Nit (predstavljen na Slika 15), ki razširi razred Thread, vsebuje pa naslednje javne metode: getnaslov (abstraktna), ki vrne ime opravila, sešeizvaja, ki določi, ali se nit še izvaja ali ne, gettrenutenproces, ki vrne trenuten proces opravila, rezultatuspešen, ki pove, ali je bilo opravilo uspešno zaključeno. Nato smo za vsako opravilo posebej ustvarili podrazred razreda Nit, v katerem smo iz razreda Thread povozili metodo run in v njej opravili opravilo. Prenašanja in nalaganja datotek na strežnik nismo podrobneje opisali. Če želite izvedeti več, si lahko to preberete na spletu [11]. 22

33 Slika 15: Razredni diagram opravil Naloži Opravilo naloži je najpreprostejše. Datoteka stopnje je tipa TMX in se v njej skriva XML koda. To kodo najprej razčlenimo, nato poiščemo vsa vozlišča z imenom»image«in iz njih pridobimo pot do slike iz atributa»source«. Sedaj ko smo prebrali lokacije vseh slik, najprej na strežnik naložimo samo datoteko stopnje, nato pa še vse slike. Prenesi Opravilo prenesi je podobno kot naloži, le da tukaj ne nalagamo ampak prenašamo s strežnika. Najprej prenesemo samo datoteko stopnje, nato enako kot pri opravilu naloži iz stopnje preberemo vse slike in vsako posebej prenesemo s strežnika. Poženi Opravilo poženi je malce zahtevnejše, saj mora iz datoteke stopnje ustvariti objekt stopnje. Najprej razčlenimo vsebino datoteke. Nato ustvarimo prazen objekt razreda Stopnja. Potem pa moramo iz vozlišč prebrati vse podatke in jih nastaviti temu objektu. Najprej so podatki o sami stopnji: orientacija, zaporedje izrisovanja ploščic, širina in višina ploščic ipd. Nato sledijo zbirke ploščic. Nekatere zbirke imajo podano samo glavno sliko, pri drugih pa ima vsaka ploščica lastno sliko. 23

34 Na koncu pa so na vrsti plasti. Naša igra podpira dve vrsti plasti: navadne (angl. layer) in plasti slik (angl. imagelayer). Slednji način je preprostejši, saj vsebuje samo vozlišče»image«, ki predstavlja najverjetneje zelo veliko sliko, po navadi za ozadje. Navadne plasti pa so malce kompleksnejše. V njih se skriva vozlišče»data«, ki vsebuje podatke o narisanih ploščicah v formatu CSV. Število vrstic je enako višini stopnje, številu številk v posamezni vrstici pa je enako širini stopnje. Vsaka številka pa predstavlja ID ploščice, ki je»narisana«na tisti lokaciji. Če pa je številka 0, to pomeni, da tam ni nobene ploščice in je prazen prostor. Seveda ne smemo pozabiti na lastnosti po meri. V primeru, da stopnja, plast ali pa ploščica vsebuje dodatne lastnosti, se znotraj njenega vozlišča ustvari vozlišče z imenom»properties«, znotraj njega pa za vsako lastnost vozlišče»property«, ki vsebuje v argumentih vse podatke o lastnosti. Ob koncu opravila poženi objekt stopnje vsebuje vse podatke in je pripravljen na inicializacijo Kontrole Za procesiranje vhodnih dogodkov moramo statičnemu vmesniku za vhodne naprave nastaviti instanco razreda, ki implementira vmesnik InputProcessor. To storimo z metodo setinputprocessor. Vmesnik za vhodne naprave mu bo nato ob vsakem začetku glavne zanke podal vse vhodne dogodke: tipkapritisnjena (angl. keydown), ki se pokliče, ko se tipka pritisne, tipkasproščena (angl. keyup), ki se pokliče, ko se tipka sprosti, dotikpritisnjen (angl. touchdown), ki se pokliče, ko zaslon zazna nov dotik oz. ko se miškin gumb pritisne, dotiksproščen (angl. touchup), ki se pokliče, ko se prst odstrani od zaslona oz. ko se miškin gumb sprosti, dotikpovlečen (angl. touchdragged), ki se pokliče, ko se prst ali miška vleče po zaslonu, drsenje (angl. scrolled), ki se pokliče, ko je bil miškin drsnik podrsan, premikmiške (angl. mousemoved), ki se pokliče, ko je bila miška premaknjena (ne da bi bil katerikoli njen gumb pritisnjen), 24

35 vtipkanznak (angl. keytyped), ki se pokliče, ko je bil vtipkan znak. Vmesnik za vhodne naprave dovoli, da je aktiven samo en vhodni procesor naenkrat. Zato smo ustvarili razreda Krmilnik in Kontrola, predstavljena na Slika 16. Krmilnik implementira InputProcessor in izbrane vhodne dogodke delegira vsem kontrolam, ki jih nadzoruje. Pri tem namesto podajanja x in y koordinat glede na velikost zaslona podamo vektor, ki ima koordinate nastavljene glede na velikost resolucije. Ustvarimo torej en krmilnik in več kontrol, ki jih nato dodelimo krmilniku. Kontrola vsebuje podatke o svoji meji na zaslonu in/ali tipki, ki jo sproži. Prav tako lahko ima kontrola svoj grafični prikaz, če ji ga dodelimo v lastnostih stopnje. Slika 16: Razredni diagram kontrol 25

36 5.2.4 Grafika V dvodimenzionalnem prostoru je glavni vizualni vir slika, ki jo naložimo kot teksturo. Razred Texture ovije standardno OpenGL ES teksturo. Za izris teksture moramo poklicati metodo nariši (angl. draw) v objektu grafičnega paketa v našem razredu ImeIgre. Poleg teksture moramo metodi podati še koordinati, kjer se naj tekstura nariše. Po želji pa lahko podamo tudi še druge parametre, npr. velikost, koordinate iz teksture ipd. Tekstura je osnovni objekt za grafiko, ki je pridobila podatke z ene slike. Načeloma bi lahko za vse operacije uporabljali samo teksture. Ker pa je nalaganje različnih tekstur na grafično enoto relativno počasno, velikokrat želimo na eni sami sliki imeti več regij, ki naj bi predstavljale različne teksture. Tako se lahko na grafično enoto naloži le ena tekstura, ki pa vsebuje več regij, ki predstavljajo različne teksture. V ta namen obstaja razred TextureRegion, ki definira pravokotno mejo neke teksture. Objekt tipa TextureRegion lahko enako uporabimo za izris kot objekt tipa Texture. Omenil sem, da lahko ima kontrola svoj grafični prikaz (in ne teksturo ali regijo teksture). Grafični prikaz je lahko tekstura, regija teksture ali pa celo animacija, zato smo ustvarili lasten razred GrafPrikaz, ki lahko vsebuje eno izmed teh stvari. Tako se vsi objekti, ki se na kakršen koli način želijo izrisati, ne potrebujejo obremenjevati s tem, kakšen tip prikaza so, saj za vse to poskrbi naš razred GrafPrikaz Animacija Animacija je zaporedje slik. Primer slik, ki sestavljajo animacijo netopirja med letenjem, je viden na Slika 17. Ne definirajo je samo slike, temveč tudi dolžine prikaza posameznih slik ter tip predvajanja. Knjižnica LibGDX nam za 2D animacijo ponudi razred Animation, ki pa ima dve pomanjkljivosti: ne omogoča različnih dolžin prikaza posameznih slik in ne dovoljuje uporabe tekstur, temveč samo regij teksture. Zato smo ustvarili lastni razred Animacija, ki pa podpira naslednja dva tipa predvajanj: Normalno: predvaja vse slike od začetka do konca in se ustavi pri zadnji. Zanka (angl. Loop): predvaja vse slike v neskončni zanki (iz zadnje skoči nazaj na prvo). 26

37 Slika 17: Slike animacije netopirja med letenjem Animacija je sestavljena iz korakov. Vsak korak vsebuje čas začetka, trajanje in pa teksturo ali regijo teksture. Trajanje celotne animacije (oz. enega kroga animacije) je seštevek trajanja vseh korakov. Vsakič, ko animaciji dodamo nov korak, moramo poleg slike dodati tudi trajanje. Dodani korak se doda na konec animacije, njegov začetek je prejšnje celotno trajanje animacije, novemu trajanju animacije pa se doda trajanje dodanega koraka. Za predvajanje animacije jo je potrebno vsako iteracijo posodobiti, s čimer ji povemo, koliko časa je minilo od prejšnjega izrisa. S tem animacija izračuna trenutno trajanje in tako ugotovi, kateri korak animacije je trenutno aktiven Igra Stopnja poleg igralca vsebuje veliko različnih objektov, ki se v njej gibljejo oz. v njej»živijo«. Ti objekti so lahko živa bitja (sovražniki, ptice, premikajoče platforme...), ozadje (sonce, oblaki, gore...), objekti za pobrati (steklenice, ključi...), interaktivne lokacije (končna vrata, vzvodi...) ipd. Vse objekte drži in povezuje stopnja,»razmišlja«pa vsak zase Objekti Implementacija vsakega interaktivnega objekta posebej bi bila potratna, zato smo ustvarili abstrakten razred Objekt, ki ga bodo razširili razredi bolj specifičnih objektov. Vsak objekt ima svoj ID (ki je enak ID-ju ploščice, ki ga predstavlja) in pa velikost objekta. Prav tako mora vsak podrazred Objekta implementirati metodi odstrani in dotik. Metoda odstrani odstrani objekt iz stopnje. Metoda dotik pa se pokliče, kadar se igralec dotakne objekta. Tako bomo npr. pri sovražniku v tej metodi igralcu zmanjšali število življenj, medtem ko bomo pri nagradi igralcu povečali rezultat. 27

38 Slika 18: Razredni diagram objektov Kot je razvidno s Slika 18, smo objekte razdelili na dva tipa: statične in premikajoče. Statični objekti Abstrakten razred ObjektStaticen predstavlja statičen objekt se ne premika. Vsebuje koordinati, kjer se nahaja v mreži ter pa obseg objekta v mreži, ki se izračuna glede na pozicijo in velikost objekta. Če se igralec v mreži stopnje pomakne v območje tega objekta, se bo poklicala metoda dotikvmrezi, ki bo preverila, če se igralec dejansko dotika objekta ali ne. V primeru, da se, bo poklicala metodo dotik, ki je implementirana v podrazredu. 28

39 Implementacija dejanskih statičnih objektov je sedaj zelo preprosta, saj moramo le definirati, kaj se zgodi, ko se igralec dotakne objekta. Primer za implementacijo ključa Ustvarimo razred z imenom Kljuc, ki razširi ObjektStaticen. Vse, kar moramo storiti, je implementirati abstraktno metodo dotik. V njej nad objektom igralca pokličemo metodo pobralkljuc, nato pa še metodo odstrani, ki iz igre odstrani objekt ključa (ker smo ga ravnokar pobrali). Premikajoči objekti Abstrakten razred ObjektPremikajoc predstavlja premikajoč objekt. Vse stvari, ki se premikajo oz. ki živijo, je potrebno posodabljati, zato je tudi tukaj prisotna metoda posodobi. Posodabljanje objektov, kadar so izven vidnega polja, je potrata procesorja, zato javna metoda posodobi najprej preveri, če je objekt znotraj vidnega polja kamere. Če ugotovi, da je, pokliče zaščiteno metodo posodobi, ki opravi dejansko posodobitev. Implementacija dejanskega premikajočega objekta je sedaj podobno preprosta kot pri statičnemu. Sovražniki Večina sovražnikov so živa bitja, ki se premikajo na različne načine. V ta namen smo ustvarili abstrakten razred SovraznikPremikajoc, ki predstavlja vse premikajoče se sovražnike. Vsebuje lastnosti o stanju premikanja (nedejaven premikanje), hitrosti, dometu vida oz. ali se vedno premika, obrnjenosti (levo desno). Prav tako morajo biti za vsako stanje premikanja določene ploščice, saj sovražnik ob različnih stanjih premikanja različno izgleda. Domet vida pove, kako daleč sovražnik vidi. Pred sabo vidi celotno razdaljo vida, za seboj pa samo polovico. To pomeni, da če je igralec dovolj blizu sovražnika, ga slednji»vidi«oz.»sliši«, drugače pa ne. Ta podatek se lahko pametno uporabi pri implementaciji premika posameznega tipa sovražnika. Metodo dotik (iz nadrazreda Objekt) smo implementirali tukaj, saj za vse sovražnike stori enako: pokliče metodo dotikzsovraznikom nad objektom igralca. Vsebuje pa zato abstraktno metodo premakni, v kateri morajo podrazredi definirati, kako se sovražnik vsako iteracijo premakne. Ta metoda se pokliče na začetku posodobitve, po njej pa se analizira stanje premikanja in obrnjenost. Glede na slednje se nato tudi ob izrisu ugotovi, katera ploščica se naj izriše. 29

40 Implementacija posameznih tipov premikajočih se sovražnikov je sedaj zelo preprosta: ustvarimo nov razred, ki razširi razred SovraznikPremikajoc, v njem pa implementiramo metodo premakni. Tako, recimo, za hodečega sovražnika v metodi premakni napišemo logiko, da se v primeru, da je igralec znotraj vidnega polja, sovražnik premakne proti njemu. Seveda so prisotne še druge lastnosti, ki opišejo premikanje hodečega sovražnika. Npr. ali se sovražnik premika tudi, kadar ne vidi igralca, ali se pri robu obrne ali pade s ploščadi ipd. Te lastnosti lahko oblikovalec stopnje nastavi ploščici, ki predstavlja tega sovražnika, z uporabo lastnosti po meri. Na Slika 19 je prikazan posnetek zaslona med igro v primeru, ko je igralec tik pred tem, da bi ga opazil sovražnik. Z zeleno je označena meja igralca, z rdečo pa sovražnikov domet vida. Sovražnik igralca ne vidi, zato sovražnik»počiva«na ploščadi. Slika 19: Posnetek iz igre, ko je igralec izven sovražnikovega dometa vida Na Slika 20 pa je igralec skočil znotraj sovražnikovega dometa vida, zato se je sovražnik odzval in začel leteti proti igralcu. Na sliki je tudi razvidno, da je za sovražnikom (v tem primeru na desni strani) domet vida za polovico manjši. 30

41 Slika 20: Posnetek iz igre, ko je igralec znotraj sovražnikovega dometa vida Igralec Igralec je pravzaprav tudi objekt znotraj stopnje, vendar je igralec poseben objekt. Poseben je v tem, da ne»razmišlja«sam (kot, recimo, sovražniki), ampak namesto njega razmišlja oseba, ki igra igro. Igralec je torej nekakšna marioneta, ki se jo nadzoruje s tipkovnico in/ali miško. Implementacija igralca je zato zelo pomembna. Med igranjem se moramo počutiti kot eno z objektom igralca v igri. Vsakršno zatikanje ali pa nepričakovano obnašanje igralca nam povzroči občutek nepristnosti, kar podzavestno povzroči vrnitev zavesti nazaj v realnost, namesto da bi se povsem prepustili domišljiji in se resnično vživeli. Naš razred Igralec vsebuje naslednje pomembnejše lastnosti: Stanje premikanja: nedejaven, tek, padanje, dvigovanje. Stanje skoka: ozemljen, skočil prvič, skočil drugič. Obrnjenost: levo, desno. Meja: pravokotnik za pozicioniranje, velikost in zaznavo dotikov. Hitrost: vektor hitrosti. Kontrole: vsaka kontrola predstavlja neko določeno akcijo (premik levo/desno ali skok). 31

42 Enako kot pri premikajočem sovražniku moramo tukaj za izris vsakemu stanju premikanja podati ploščice. Prisotne so javne metode, ki se pokličejo ob stiku z nekim interaktivnim objektom oz. nekim dogodkom, recimo, pobralkljuc, dotikzsovraznikom, pobralsteklenico ipd. Posodabljanje igralca Najpomembnejša metoda v igralcu je posodobi. V njej se najprej glede na stanje kontrol nastavi hitrost. Če je npr. pritisnjena kontrola za premik v levo, se bo horizontalna hitrost nastavila na negativno vrednost hitrosti premikanja. V primeru, da kontrola za skok ni bila ravnokar sprožena, se vertikalni hitrosti doda hitrost gravitacije. Recimo, da je gravitacija nastavljena na 100: to pomeni, da se bo vertikalna hitrost povečala za 100 na sekundo v negativno smer, in sicer dol. Igralec bo torej padal vedno hitreje oz. se dvigoval vedno počasneje. To je podobno kot v realnem svetu. Seveda pa ne smemo pustiti, da se hitrost padanja v nedogled povečuje, saj lahko to privede k napačni zaznavi robov ob trku s tlemi. V ta namen je prisotna konstanta, ki definira maksimalno hitrost padanja. Nato sledi dejanski premik igralca znotraj mreže zidov. Implementacija premika je napisana v metodi premakniinpopravi znotraj statičnega razreda PripomocekMreza, saj jo uporabljajo tudi drugi objekti, ki se premikajo po mreži. Metoda sprejme pravokotnik oz. mejo objekta, ki ga želimo premakniti ter hitrost premika. V njej se mejo najprej premakne po horizontali, nato se preveri, ali je meja zadela ob zid (ali ob rob stopnje) in ob potrebi naredi popravek. Nato se igralec premakne po vertikali in enako preveri meje ter ob potrebi naredi popravek. Vrne pa objekt notranjega razreda RezultatPremika, ki vsebuje lastnosti o podatkih premika: ali je bilo karkoli popravljeno in kje (levo,desno,spodaj,zgoraj) so bili zadetki. Po premiku se le-ta analizira. Recimo, če je bil zadetek spodaj, se stanje skoka nastavi na ozemljen. Nato se pregleda trenutna pozicija v mreži in preveri, ali se prekriva s katerim izmed interaktivnih statičnih objektov. Če se, se nad njim pokliče metodo dotikvmrezi. Na koncu se še analizira stanje premikanja in obrnjenost, saj se nato ob izrisu glede na stanje premikanja in obrnjenost določi, katera ploščica je trenutno aktivna. 32

43 Objekti iz urejevalnika Naša aplikacija je pravzaprav delujoča različica stopnje iz urejevalnika Tiled, zatorej smo ustvarili razrede, ki predstavljajo objekte iz urejevalnika. Vse entitete (razen zbirke ploščic) vsebujejo seznam lastnosti po meri, ki jih oblikovalec lahko zapiše znotraj urejevalnika, zato smo ustvarili abstrakten nadrazred vseh teh entitet, imenovan TiledEntitetaZLastnostmi. Vse entitete se ustvarijo v opravilu poženi in podajo stopnji. Ploščica Ploščica predstavlja eno ploščico znotraj zbirke ploščic. Vsebuje ročico do slike in grafični prikaz za izris. Lastnosti o velikosti ne potrebuje, saj jih lahko pridobi iz velikosti grafičnega prikaza. Prav tako se iz njega pridobi velikost interaktivne meje ploščice. Seveda lahko oblikovalec tudi sam (z uporabo lastnosti po meri) definira velikost in pozicijo interaktivne meje. To je potrebno narediti, kadar je grafični prikaz večji kot pa želena interaktivna meja (glej Slika 21). Slika 21: Primerjava meje, pridobljene iz slike, in želene meje Zbirke ploščic Obstajata dve različici zbirke ploščic: zbirka, ki je sestavljena iz ene slike oz. več regij iste slike, zbirka, ki je sestavljena iz več različnih slik. Pri inicializaciji prvega tipa se slika, glede na velikost ploščic, razcepi na več regij (glej Slika 8). 33

44 Oba tipa lahko vsebujeta tudi animacije. Dodajanje novih ploščic je dovoljeno samo pri drugem tipu, dodajanje animacij pa pri obeh. Pri inicializaciji zbirke nato animacije prekrijejo ploščice z enako ID številko. Plasti Urejevalnik Tiled pozna tri vrste plasti: Plast ploščic (angl. Tile Layer). Plast slike (angl. Image Layer). Plast objektov (angl. Object Layer). Naša implementacija podpira samo prva dva, saj se nevidni objekti uporabljajo predvsem za skriptiranje določenih dogodkov, česar pa v naši igri zaenkrat še ni. Ustvarili smo torej abstrakten razred Plast, ki vsebuje ime in abstraktni metodi posodobi ter izrisi. Razred PlastSlika predstavlja plast slike in vsebuje ročico do slike ter njeno teksturo. Glavni namen plasti slik je ozadje, pri čemer se slika premika skupaj oz. obratno sorazmerno z igralcem. Zaradi tega razloga vsebuje lastnost faktor premikanja, ki definira, kako hitro se slika premika v razmerju z igralcem. Če je npr. faktor premikanja nastavljen na 0,5, igralec pa se nahaja na lokaciji 20, se bo slika izrisala na lokaciji 20 * 0,5 = 10. Slika ozadja se torej premika dvakrat počasneje kot igralec, s čimer navidezno ustvarimo občutek, kot da se ozadje nahaja nekje daleč zadaj. Faktor premikanja nastavi oblikovalec. Razred PlastPloscice pa predstavlja plast ploščic in vsebuje mrežo ter premikajoče objekte. Pri izrisu se najprej narišejo ploščice v mreži, nato pa premikajoči objekti Stopnja Stopnja je pravzaprav tudi Tiled entiteta, vendar je njena zelo razširjena različica in si zatorej zasluži svoje poglavje. 34

45 Vse dogajanje igre se dogaja znotraj stopnje. V zaslonu ZaslonIgra potrebujemo tako le objekt stopnje, ki ga ob prikazu zaslona inicializiramo, nato pa vsako iteracijo posodobimo in izrišemo. Lastnosti Razred Stopnja mora omogočati podporo različnim nastavitvam iz urejevalnika Tiled: orientacija (angl. orientation), zaporedje izrisovanja ploščic (angl. renderorder), širina in višina mreže, širina in višina ploščice, barva ozadja. Te lastnosti so vedno prisotne v datoteki stopnje. Poleg teh pa mora oblikovalec dodati še lastnosti po meri: gravitacija, resolucija, kontrole in tip igranja. Edini tip igranja, ki je v različici za to diplomsko nalogo podprt, je»side-scrolling platformer«. Za podporo več tipov iger bi morali definirati več tipov in napisati njihovo logiko. Poleg že opisanih pa stopnja vsebuje še naslednje lastnosti: Igralec: instanca igralca. Kamera: stopnja ima lastno kamero, saj se le-ta premika skupaj z igralcem. Krmilnik: vsebuje vse igralčeve kontrole. Statični objekti: instance statičnih objektov. Mreža: dvodimenzionalna tabela zidov in statičnih objektov, po kateri se igralec premika. Plasti: plasti se delijo na tiste, ki so pod igralcem, in tiste, ki so nad njim. Kam določena plast spada, se določi ob dodajanju nove plasti. Sovražniki so lahko znotraj samo ene plasti in ta plast je tista, ki je najvišja izmed tistih, ki so pod igralcem. Vse dodane plasti po plasti sovražnikov so nad igralcem. Inicializacija V inicializaciji se najprej preveri, če so bile podane vse nujne lastnosti za delovanje igre. Nato se glede na tip igranja preveri kompatibilnost nastavljenih lastnosti. Recimo, pri tipu»side-scrolling platformer«je dovoljena le ortogonalna orientacija. Nato sledi priprava. 35

46 Priprava Najprej je na vrsti priprava ploščic in zbirk. Vse zbirke se inicializirajo, poiščejo in nastavijo se ploščice igralca. Nato se pregleda ploščice, če morda predstavljajo kakšne interaktivne objekte. Sledi priprava plasti. Plasti slike se inicializirajo. Plasti ploščic pa se ločijo med navadne in tiste, ki predstavljajo zidove. Priprava stopnje pa je sestavljena iz sledečih korakov: nastavi lastnosti glede na lastnosti po meri, inicializira kamero glede na ločljivost, v mreži zapolni kvadratke, ki so v katerikoli izmed plasti zidov, preveri še mreže vseh ostalih plasti, če se v kateri izmed njih nahaja kakšen statičen objekt, ki ga je potrebno dodati v seznam statičnih objektov, iz mreže v plasti sovražnikov se ugotovi, kateri sovražniki so prisotni in kje se nahajajo. Če sovražnik ne vsebuje lastnosti o premikanju, se doda kot statičen objekt, drugače pa kot premikajoč. V primeru premikajočega se prebere vse lastnosti o sovražniku (hitrost, tip, slike...) in jih nastavi. Priprava igralca je prav tako sestavljena iz več korakov: nastavi lastnosti glede na lastnosti po meri, ustvari krmilnik, glede na lastnosti po meri (akcija, tipka, velikost...) ustvari objekte kontrol in jih doda krmilniku ter igralcu, statičnemu vmesniku za vhod nastavi kot aktiven procesor vhoda pravkar ustvarjeni krmilnik. Posodabljanje stopnje V primeru, da stopnja še ni končana, jo je potrebno posodabljati. V njej posodobimo vse objekte znotraj stopnje v naslednjem vrstnem redu: krmilnik, igralec, plasti, ploščice. Takšen vrstni red je pomemben, saj drugače lahko pride do nepričakovanega obnašanja v sami igri. Ta vrstni red posodabljanja je pravzaprav zelo podoben psevdokodi glavne zanke igre, ki je dosegljiva v viru [12] : 36

47 dokler (uporabnik ni prekinil izvajanja): preglej vhod uporabnika, poženi umetno inteligenco, premakni sovražnike, izriši grafiko in predvajaj zvok. Naš vrstni red posodabljanja je torej zelo podoben psevdokodi zgoraj: najprej posodobimo krmilnik, ki preveri vhod uporabnika, nato posodobimo igralca, ki se glede na vhod uporabnika premakne, nato posodobimo plasti, v katerih se nahajajo sovražniki in drugi objekti, nato pa zaradi animacij posodobimo še ploščice. Grafika se tako ali tako izriše kasneje v metodi izris, zvoka pa naša igra ne vsebuje. Izris V izrisu stopnje je potrebno najprej postaviti kamero. V večini primerov je kamera centrirana glede na igralca. Kadar pa je igralec ob robu stopnje, ne želimo, da gre vidno polje kamere izven igralnega polja, zato kamero takrat fiksiramo glede na rob igralnega polja. Na Slika 22 je z modro barvo označeno vidno polje kamere, medtem ko je preostali del igralnega polja igralcu trenutno ne viden. Nato preverimo, ali so trenutno prisotni kakšni posebni efekti. Recimo, kadar se igralec dotika sovražnika, nastavimo barvo ozadja in barvni odtenek grafičnega paketa na rdeče. Sledi izris objektov v naslednjem vrstnem redu: plasti pod igralcem, igralec, plasti nad igralcem. Če je aplikacija odprta na telefonu, se izrišejo še kontrole. 37

48 Slika 22: Posnetek iz igre, kjer je kamera centrirana na center igralca 38