Quick viewing(Text Mode)

Development of a Game Engine and Editor for Creation of 2D Games

Development of a Game Engine and Editor for Creation of 2D Games

Fakulteta za elektrotehniko, računalništvo in informatiko Smetanova ulica 17 2000 Maribor, Slovenija

Bojan Kerec

IZDELAVA IGRALNEGA POGONA IN UREJEVALNIKA ZA IZDELAVO 2D IGER

Magistrsko delo

Maribor, november 2014

i

IZDELAVA IGRALNEGA POGONA IN UREJEVALNIKA ZA IZDELAVO 2D IGER Magistrsko delo

Študent: Bojan Kerec Študijski program: Računalništvo in informacijske tehnologije (MAG) Mentor: red. prof. dr. Borut Žalik Somentor: doc. dr. Gregor Klajnšek

ii

iii

Zahvala

Zahvaljujem se mentorju red. prof. dr. Borutu Žaliku in somentorju doc. dr. Gregorju Klajnšku za pomoč in vodenje pri izdelavi magistrskega dela.

Zahvaljujem se tudi družini za podporo in strpnost.

Zahvala gre tudi pristojnim organizacijam, da me niso vpisale v register nepremičnin, zaradi neštetih ur, preživetih za računalnikom.

iv

Izdelava igralnega pogona in urejevalnika za izdelavo 2D iger

Ključne besede: igralni pogon, urejevalnik, računalniška igra

UDK: 004.354.7:004.9(043.2)

Povzetek:

V tem magistrskem delu predstavimo postopek izdelave igralnega pogona. Nalogo začnemo z opsiom razvoja igralnih pogonov skozi čas in pregledom obstoječih rešitev. Nato podamo prednosti in slabosti izdelave lastnega igralnega pogona in ovrednotimo smotrnost izbire že obstoječega igralnega pogona. Nadaljujemo s predstavitvijo igralnega pogona, ki smo ga razvili. Predstavimo arhitekture in organizacije sistemov igralnega pogona, podamo kratek pregled implementacije najpomembnejših sistemov in opišemo izdelavo urejevalnika nivojev. Zmogljivost razvitega igralnega pogona prikažemo z izdelavo preproste 2D igre.

v

Development of a and editor for creation of 2D games

Keywords: game engine, editor, computer game

UDK: 004.354.7:004.9(043.2)

Abstract:

In this work we present the process of development of a game engine. Thesis begins with description of evolution of game engines and with an overview of the existing solutions. After that an analysis of advantages and disadvantages of development of a proprietary game engine is given together with evaluation of expedience of using an existing game engine. Thesis continues with description of development of our proprietary game engine. The architecture of the engine and organization of core system is presented at first, followed by specific implementation details and description of development of the editor. The power and capacity of the developed game engine is presented through development of a simple 2D game.

vi

Kazalo vsebine

1 Uvod ...... 1

2 Obstoječe rešitve ...... 4

3 Izbira ali izdelava igralnega pogona ...... 7

4 Arhitektura ...... 9

4.1 Aplikacijski nivo ...... 10

4.2 Igralna logika ...... 11

4.3 Igralni pogledi ...... 12

5 Organizacija akterjev ...... 14

6 Implementacija ...... 17

6.1 Razred GameApp ...... 18

6.2 Upravljanje z oknom ...... 20

6.3 Viri ...... 20

6.4 Vhodne naprave ...... 21

6.5 Sistem za upodabljanje ...... 23

6.6 Dogodki ...... 24

6.7 Mrežna komunikacija ...... 26

6.8 Igralna logika ...... 27

6.9 Glavna zanka ...... 28

6.10 Akterji...... 29

6.11 Scena ...... 31

6.12 Igralni pogledi ...... 32

6.13 Avdio sistem ...... 32

6.14 Grafični uporabniški vmesnik ...... 33

vii

6.15 Podpora uporabi skriptnega jezika ...... 34

7 Urejevalnik ...... 37

8 Uporaba v praksi ...... 43

9 Sklep ...... 48

10 Literatura ...... 49

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 1

1 Uvod

Izraz igralni pogon (angl. game engine) izvira iz sredine devetdesetih let z referenco na prvoosebne strelske igre, kot je bil takrat izjemno popularen , izdelek podjetja . Doom je bil zasnovan z zelo dobro ločitvijo temeljnih komponent (sistem za upodabljanje, sistem za zaznavanje trkov) in komponent igre (viri, svetovi in pravila igre). Vrednost ločitve se je pokazala, ko so razvijalci začeli obstoječe produkte preurejati in iz tega izdelovati nove produkte tako, da so ti dobili novo grafično podobo, nove svetove, orožja, vozila, zgolj z minimalnimi spremembami temeljnih komponent. Proti koncu devetdesetih let so bile nekatere igre ( 3 Arena, Unreal) že zasnovane s ponovno uporabo in z mislijo na bodoče spremembe in nadgradnje v mislih. Temelji teh iger, imenovani igralni pogoni, so bili narejeni tako, da so omogočali izdelavo in prilagajanje vsebine igre s posebno namenskimi urejevalniki in skriptnimi jeziki. Takrat je postalo licenciranje igralnih pogonov dobra alternativa za zaslužek.

Meja med igro in njenim pogonom je pogosto zamegljena. Nekateri pogoni jasno nakažejo ločnico, pri drugih pa te ločnice ne moremo določiti. Primer tega je, da v enem pogonu lahko prikažemo le točno določeno pošast, v drugem pa imamo na voljo orodja za risanje, postopek upodabljanja določene pošasti pa je definiran ločeno. Razliko med igralnim pogonom in igro v grobem določi podatkovno- usmerjena arhitektura. Kadar igra vsebuje zakodirano logiko ali pa vsebuje specifične elemente, izvorno kodo take igre zelo težko uporabimo za razvoj drugačne igre ali pa je ponovna uporaba povsem nemogoča. Iz tega spoznamo, da je igralni pogon programski produkt, ki je razširljiv in ga je moč uporabiti brez velikih sprememb kot temelj za mnogo različnih iger [1].

Igralni pogoni so običajno specifični za določen žanr. Igralni pogon za izdelavo športnih iger (Fifa) je povsem drugačen kot igralni pogon za izdelavo prvoosebnih

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 2

strelskih iger (Quake). Vendar pa imajo tudi veliko skupnega. Vsak igralni pogon mora tako znati izrisovati geometrijo, predvajati zvok, obdelovati in analizirati vhodne podatke iz različnih naprav (tipkovnica, miška, igralni plošček) in opravljati še veliko drugih funkcij. V nadaljevanju bomo izpostavili ključne lastnosti igralnih pogonov, ki so pomembne za specifičen žanr.

Prvoosebne strelske igre (angl. first person shooter - FPS) vsebujejo dokaj počasno pešačenje po notranjih ali zunanjih prostorih, vožnjo z vozili (po zemlji, zraku in vodi) in običajno veliko izbiro orožja ter balistiko. Tipični predstavniki te skupine so igre Quake, Unreal Tournament, Half Life in druge podobne igre. Običajno so tehnološko najbolj razvite in se osredotočajo na učinkovito upodabljanje 3D svetov, odzivno premikanje po svetu, kakovostne animacije in dobro umetno inteligenco.

Ploščadne igre (angl. platformer) so tretjeosebne ali 2D stransko pomične (angl. side scroller) igre, pri katerih je glavna mehanika skakanje iz ploščadi na ploščad. Tipični predstavniki so Donkey Kong, Super Mario Bros ter Rachet & Clank. Ta žanr se osredotoča na premične platforme, vrvi, lestve, uganke z uporabo okolijskih elementov ter napredni nadzor nad kamero.

Pretepaške igre so običajno dvoigralske igre, pri katerih se humanoidni liki mikastijo med sabo v ringu ali areni. Predstavniki so Soul Calibur, Tekken in Mortal Kombat. Igre pretepaškega žanra se osredotočajo na veliko število pretepaških animacij, natančno zaznavo trkov ter zmožnost vhodnega sistema, da procesira kompleksne kombinacije vhodnih podatkov.

Dirkaški žanr zajema vse igre, pri katerih je glavni cilj vožnja avta ali kakšnega drugega vozila. Žanr ima podzvrsti, kot so simulacije in arkadne igre. Osredotoča se na uporabo posebnih podatkovnih struktur za prikazovanje prog, umetno inteligenco in iskanje poti, uporabo trikov upodabljanja manj pomembne geometrije (ozadje) ter postavitev kamere (sledenje avtu, pogled iz avta).

Realno-časovne strategije so igre, pri katerih igralec strateško postavlja bojne enote po velikem bojnem polju, da bi premagal svojega nasprotnika. Predstavniki so Warcraft, Command & Conquer in Age of Empires. Te igre običajno uporabljajo

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 3

pogled iz višav. Pri tem žanru je pomembno, da imajo enote sorazmerno nizko kakovostno geometrijo, da jih lahko na ekranu predstavimo v ogromnem številu. Igralec lahko postavlja enote in zgradbe, interakcija pa običajno poteka z miško.

V uvodnem poglavju smo definirali pojem igralni pogon in nato predstavili nekaj najpomembnejših lastnosti igralnih pogonov. V nadaljevanju bomo najprej predstavili obstoječe rešitve in nato navedli, kdaj je izbira obstoječega igralnega pogona ustrezna rešitev in kdaj se je smiselno posvetiti razvoju lastnega igralnega pogona. V poglavju 2 bomo tako predstavili nekaj najbolj znanih in razširjenih igralnih pogonov, v poglavju 3 pa se bomo posvetili analizi razlogov za oziroma proti izdelavi lastnega igralnega pogona. V poglavjih 4 in 5 bomo predstavili arhitekturo našega igralnega pogona, v poglavju 6 pa dejansko implementacijo igralnega pogona. V poglavju 7 bomo nadaljevali z prestavitvijo razvoja urejevalnika nivojev in v poglavju 8 zaključili z izdelavo preproste igre, ki bo kot osnovo uporabljala razvit igralni pogon. Nalogo zaključimo s poglavjem 9.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 4

2 Obstoječe rešitve

Na trgu obstaja že veliko obstoječih rešitev. V nadaljevanju bomo izpostavili nekaj popularnih igralnih pogonov. Veliko igralnih pogonov je narejenih kot skupek raznih orodij, združenih v en celovit program (urejevalnik). Med najbolj znanimi so , CryEngine, , Engine in idTech, vsi znani po tem, da so bili z njimi narejeni naslovi AAA. Izdelujejo jih podjetja, ki se bolj ali manj osredotočajo na izdelavo igralnih pogonov.

Igralni pogon Unreal Engine [2] je razvilo podjetje Epic Games. Njegovi začetki segajo v devetdeseta leta z razvojem igre Unreal Tournament. Skozi čas je postajal vedno bolj razvit z vedno več funkcijami ter tako postal celovit programski produkt za izdelavo iger. Med najbolj prepoznavnimi igrami, narejenimi z igralnim pogonom Unreal Engine, so franšize Unreal Tournament, Gears of War, Bioshock, Batman: Arkham in še mnogo posameznih naslovov, razvitih tako s strani največjih razvojnih studijev kot tudi neodvisnih razvijalcev. Igralni pogon CryEngine [3] podjetja je prav tako celovita rešitev za razvoj iger, znana po zmožnostih prikazovanja ogromnih in detajlnih pokrajinah. Postal je testni program za ocenjevanje grafičnih zmožnosti računalnikov. Najbolj znane igre, izdelane s pogonom CryEngine, so , in Ryse. Igralni pogon Source Engine [4] podjetja Valve je znan po tem, da se zelo veliko uporablja v skupnosti "modding". Z njim je narejenih na stotine različnih modifikacij (angl. ). Najbolj je znan po igrah Half Life 2, Counter Strike: Source, Left4Dead in Portal. Igralni pogon Unity [5] podjetja Unity Tehcnologies je postal zelo popularna izbira med neodvisnimi razvijalci. Vsebuje vse potrebno tako za razvoj 2D kot tudi 3D iger brez potrebe po dodatkih. Igralni pogon idTech [6] (znan tudi kot ) je igralni pogon, razvit s strani podjetja id Software. Znan je predvsem po inovativnih pristopih izrisovanja geometrije, saj je kot prvi uvedel binarno delitev prostora (angl. binary space partitioning), osvetlitev

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 5

na nivoju pikslov (angl. per-pixel lighting) in MegaTexture (celoten teren nivoja na eni veliki teksturi). Najbolj znane igre, ki uporabljajo pogon idTech, so serije Doom, Quake in . Vsi našteti pogoni imajo podporo za več ciljnih platform (PC, konzole in mobilne naprave). Obstaja še veliko bolj ali manj znanih igralnih pogonov s podobnimi funkcionalnostmi. Med njimi najdemo:

- Engine [7] (Orcs Must Die!, Stronghold 4, The Settlers 7),

- [8] (Battlefield 3 in 4, Army of Two),

- Leadwerks [9],

- Torque3D [10],

- ShiVa [11].

Nekaj igralnih pogonov je narejenih posebej za specifične žanre. Med njimi najdemo SAGE, in . SAGE [12] (angl. Strategy Action Game Engine) je igralni pogon, ki ga uporablja podjetje skupaj z za izdelavo realno-časovnih strateških iger. Uporabljen je bil za izdelavo iger iz serije Command & Conquer. Igralni pogon Ignite [13] je nastal pod okriljem Electronic Arts in je namenjen izdelavi športnih iger. Njegove posebnosti so dobra umetna inteligenca in natančen fizikalni model igralcev. Z njim so narejene najnovejše igre iz serij Fifa, Madden, NBA Live, UFC in NHL. Igralni pogon EGO [14] je bil razvit v podjetju in se uporablja za izdelavo dirkaških iger. Njegova posebnost je zelo podroben poškodbeni in fizikalni model. Najbolj znane igre, izdelane s tem pogonom, so Race Driver: , serija Colin McRae: Dirt in serija F1.

Čeprav lahko z vsakim 3D igralnim pogonom naredimo 2D igro, ponuja le peščica teh pogonov pravo podporo izdelavi 2D iger. Večina do sedaj omenjenih igralnih pogonov se osredotoča predvsem na tehnološke rešitve, ki jih lahko popolnoma izkoristijo le osebni račnunalniki in igralne konzole. Vendar pa je v zadnjem času ponovno postala popularna tudi izdelava 2D iger, posebej pri neodvisnih razvijalcih, ki v večini izdelujejo igre za mobilne naprave, redkeje pa tudi za računalnike in konzole. Igralni pogoni, ki se osredotočajo na izdelavo iger za mobilne naprave (2D,

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 6

3D ali oboje), so naslednji: GameMaker, Project Anarchy, App Game Kit, , Gamesalad, in 2. GameMaker [15] so razvili v podjetju YoYo Games in je postal zelo popularna izbira za izdelavo 2D iger. Namenjen je tako začetnikom, saj je z njim možno izdelati igre brez programerskega znanja, kot tudi profesionalcem, ki jim je na voljo skriptni jezik GML, posebej razvit za ta igalni pogon. Igralni pogon Project Anarchy [16] je izdelalo podjetje Havok in je za razliko od pogona Havok Vision Engine posebej namenjen za razvoj iger za mobilne naprave. Izmed tehnologij, ki jih je Havok razvil, uporablja Physics, Animation Studio in AI. Igralni pogon App Game Kit [17] je razvilo podjetje TGC z namenom, da poenostavi razvoj iger za več mobilnih platform hkrati. Za pisanje izvorne kode uporablja skriptni jezik BASIC. Marmalade [18] je igralni pogon istoimenskega podjetja. Razvoj iger omogoča s programskim jezikom ++ ali skriptnim jezikom (LUA) in nima lastnega razvojnega okolja. Enake funkcionalnosti omogoča tudi Cocos2D - odprtokodni projekt [19], pri katerem je na voljo preprosto orodje za izdelavo nivojev ter uporabniškega vmesnika. Uporablja skriptni jezik LUA, s pomočjo katerega lahko v posebej prirejenim razvojnim okoljem izdelamo preprosto igro. Igralni pogon Gamesalad [20] za razvoj iger ponuja lasten urejevalnik, pri katerem za izdelavo igre ne potrebujemo programerskega znanja. Enako nudi tudi Construct 2 [21] podjetja Scirra, pri katerem za izdelavo logike uporabljamo vnaprej definirane dogodke.

V tem poglavju seveda nismo predstavili vseh igralnih pogonov, saj je seznam preobsežen. Zato smo izpostavili le najbolj znane igralne pogone ter tiste, ki so posebni na določenem področju.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 7

3 Izbira ali izdelava igralnega pogona

V prejšnjem poglavju smo navedli, da danes na trgu obstaja že veliko uporabnih rešitev. Preden se lotimo izdelave lastne igre nas torej najprej čaka odločitev, ali bomo igro izdelali s pomočjo kakšnega obstoječega igralnega pogona ali se bomo lotili izdelave lastnega pogona [22, 23]. Vsaka od možnosti ima svoje dobre in slabe lastnosti. Razlogi, zakaj bi bila izbira obstoječega igralnega pogona ustrezna rešitev, so:

- pomanjkanje tehničnega kadra (znanja programiranja),

- prihranek pri času in

- neposredno osredotočanje na vsebino igre.

Razloge, zakaj bi bila ustrezna rešitev izdelava lastnega igralnega pogona, pa lahko strnemo v:

- uporaba lastnih tehnologij, ki jih ne ponuja noben drug igralni pogon,

- igralni pogon ne podpira določenih funkcionalnosti, ki jih potrebujemo,

- stroški licenc in

- želja po učenju.

Kadar imamo idejo o igri in se ne želimo preveč obremenjevati s tehničnimi stvarmi, takrat je izbira obstoječega igralnega pogona prava odločitev. Dandanes je na trgu že precej različnih rešitev in ena izmed teh bi skoraj zagotovo podpirala želene funkcionalnosti igre. Tudi iz finančne plati položaj ni kritičen. Veliko igralnih pogonov je brezplačnih ali odprtokodnih, zraven tega pa tudi glavni igralci ponujajo licenčne modele, ki so prilagojene neodvisnim razvijalcem (Epic, CryTek in Unity ponujajo mesečno naročnino z nizkimi cenami). Velikokrat pa se lahko zgodi, da

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 8

obstoječi igralni pogoni ne podpirajo določenih funkcionalnosti, ki so unikatne pri določeni igri. V takem primeru pa smo primorani izdelati lasten pogon. Motiv za to potezo pa je lahko tudi pridobivanje novega znanja. Kadar želimo razumeti tehnologijo, ki se skriva za igralnim pogonom, ali pa se želimo izpopolniti na določenem področju, je izdelava lastnega pogona prava odločitev. Pri izdelavi lastnega igralnega pogona je pomemben tudi pristop. Napačen pristop bi bil, da bi začeli izdelovati igralni pogon, ne da bi vnaprej vedeli, za kakšno igro bo ta uporabljen. V takšnem primeru lahko veliko časa zapravimo za implementacijo funkcionalnosti, ki jih v igri sploh ne bi potrebovali. Takšen pristop bi bil ustrezen le v primeru, ko bi skupina izkušenih programerjev začela izdelovati igralni pogon z namenom, da ga kasneje trži.

Predstavili bomo dva možna pristopa k izdelavi igralnega pogona. Prvi pristop je takšen da se odločimo za izdelavo igre, ko imamo sestavljeno že vso razvojno dokumentacijo. Nabor funkcionalnosti je torej definiran, zato se lahko pri izdelavi igralnega pogona osredotočimo na implementacijo teh funkcionalnosti. Z dobrim načrtovanjem in ločitvijo splošnih funkcionalnosti lahko izdelamo igralni pogon, ki ga bo možno uporabiti tako za izdelavo zasnovane igre kot tudi za razvoj drugih iger s podobnimi funkcionalnostmi. Pri drugem pristopu se na začetku osredotočimo samo na izdelavo iger. Ko smo izdelali nekaj iger, po možnosti čim bolj različnih, začnemo opažati določene funkcionalnosti, ki so skupne vsem igram. Te funkcionalnosti nato združimo v celoto in tako dobimo igralni pogon.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 9

4 Arhitektura

Obstaja mnogo načinov, kako lahko posamezne sisteme igralnega pogona organiziramo. Izbrali smo trinivojsko arhitekturo, ki vsebuje aplikacijski nivo, nivo igralne logike in nivo igralnih pogledov [24, 25, 26]. Zastavljeno arhitekturo prikazuje slika 4.1. Aplikacijski nivo skrbi za komunikacijo s strojno opremo in operacijskim sistemom. Kadar bomo igro prenašali na druge platforme, bomo morali ponovno napisati večino kode v aplikacijskem nivoju. Igralna logika se ukvarja z upravljanjem stanja igre in je povsem neodvisna od strojne opreme naprave, na kateri bomo igro igrali in načina, kako je igra predstavljena igralcu. V idealnem primeru bo koda, napisana v tem nivoju, prenosljiva med platformami brez kakršnekoli spremembe. Igralni pogled je odgovoren za prikaz trenutnega stanja igre. V igri lahko imamo več igralnih pogledov in vsak lahko ima drugačno implementacijo. Glavni pogled je pogled, ki stanje igre prikazuje na prikazovalnik in predvaja zvok. Naslednji tip pogleda je pogled umetne inteligence. Tretji pa je lahko pogled omrežnega igralca v večigralskem načinu.

Aplikacijski nivo

Igralna logika

Igralni pogled

Slika 4.1: Pregled 3-nivojske arhitekture

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 10

Uporaba trinivojske arhitekture, pri kateri je igralni pogled povsem ločen od igralne logike, ni preprosta, je pa zato zelo fleksibilna. V igralni logiki so podatki, ki opisujejo vse akterje v igri (ljudi, vozila, zgradbe). Akter predstavlja osnovni gradnik scene in ga bomo podrobneje opisali v pogavjih 5 in 6.11. Igralna logika vsebuje tudi fizikalni sistem, ki skrbi za obnašanje akterjev. Vhodi v igralno logiko so povezani z glavnimi akterji, npr. premikanje glavnega lika, skok in podobno. Izhodi iz logike pa so sprememba stanj in dogodki. Pod te spada položaj akterjev, proženje raznih akcij, dogodki trkov (iz fizikalnega sistema) ipd.

Igralne poglede smo razdelili v tri kategorije: igralčev pogled, pogled umetne inteligence in mrežni pogled. Igralčev pogled predstavi stanje igre skozi igralčevo perspektivo. Izrisati mora sceno, prikazati razne vizualne učinke in predvajati zvok. Ta pogled tudi zajema podatke iz raznih vhodnih naprav (miška, tipkovnica, igralni plošček, volan, kamera, pospeškometer) in jih prevede v ukaze – dogodke, ki se pošljejo igralni logiki. Pogled umetne inteligence je nekoliko drugačen. Sprejema enake spremembe stanj in dogodke kot igralčev pogled. Na osnovi teh podatkov izračuna ukaze, ki določajo obnašanje računalniško-krmiljenih akterjev, in jih posreduje igralni logiki. Ti ukazi so lahko popolnoma enaki, kot pri igralčevem pogledu. Pri mrežnem pogledu se stanja in dogodki posredujejo oddaljenemu igralcu v omrežju. Zaradi takšne razporeditve se igralni logiki ni treba ukvarjati z vprašanjem ali igralec igra igro na lokalnem računalniku ali na oddaljeni napravi v omrežju.

4.1 Aplikacijski nivo

Vsebina aplikacijskega nivoja je razdeljena na različna področja, ki se ukvarjajo z vhodnimi in izhodnimi napravami, komunikacijo z operacijskim sistemom in življenjsko dobo igre [24]. Glavna področja, ki jih pokriva aplikacijski nivo, so:

- Vhodni sistem: Igre lahko zajemajo vhodne podatke iz velikega števila vhodnih naprav. Branje podatkov iz teh naprav je vedno odvisno od operacijskega sistema.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 11

- Upravljanje z viri: Igre lahko vsebujejo veliko količino podatkov, ki morajo biti ustrezno urejeni, da jih lahko učinkovito uporabljamo.

- Upravljanje s pomnilnikom: Upravljalnik pomnilnika je eden izmed kritičnih sistemov, kadar razvijamo veliko in kompleksno igro. Podatkovne strukture so običajno majhne in zelo dinamične, pri takšni organizaciji pa privzeti upravljalnik pomnilnika postane hitro neučinkovit zaradi fragmentacije podatkov.

- Časovnik: Sledenje času je v igrah kritično, saj na podlagi časovne informacije sinhroniziramo animacije, zvok, fiziko, in vse dinamične elemente igre.

- Upravljanje z besedili: Ločena besedila za uporabniški vmesnik olajšajo lokalizacijo iger.

- Nitenje: Izvajanje igre v več nitih je dandanes že obvezno zaradi vedno večje kompleksnosti iger.

- Mrežna komunikacija: Mrežna komunikacija je storitev, ki jo zagotavlja operacijski sistem. Skrbi za medsebojno povezovanje računalnikov.

- Skriptiranje: Večina iger uporablja skriptne jezike. Njihova uporaba pohitri razvoj in omogoča naknadno modificiranje igre.

4.2 Igralna logika

Igralna logika predstavlja glavnino igre in upravlja z vsem, kar ta igra vsebuje [24]. Tako kot aplikacijski nivo, je igralna logika razdeljena na področja:

- Podatkovne strukture: Vsaka igra ima zbirko akterjev. Preproste igre lahko imajo seznam, kompleksnejše igre pa potrebujejo bolj fleksibilno podatkovno strukturo. Ta mora biti optimizirana za hitro iskanje in razširljiva.

- Fizika in trki: Fizika definira vse od premikanja akterjev, kadar na njih deluje gravitacija, do dogajanja ob medsebojnih trkih akterjev.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 12

- Dogodki: Kadar igralna logika izvede spremembo stanja, morajo drugi sistemi reagirati. Komunikacija med njimi je zagotovljena z uporabo dogodkov. Arhitektura, ki temelji na dogodkih, se nagiba k učinkovitejšim sistemom.

- Upravljanje procesov: Izvajanje igre je običajno razdeljeno na majhne dele kode, ki se izvajajo neki določen čas. Take dele kode lahko predstavimo kot procese. Procesi se izvajajo znotraj upravitelja procesov in se sami uničijo, ko končajo z delom.

- Odzivi na ukaze: Igralna logika se mora odzivati na razne ukaze, ki jih dobiva od drugih sistemov. Ukazi so lahko odzivi na smerne tipke, kadar želi igralec premakniti svoj virtualni lik, postavitev novih akterjev ob nekem dogodku in podobno.

4.3 Igralni pogledi

Igralni pogled je skupek sistemov, ki komunicirajo z igralno logiko in predstavijo igro določenemu tipu opazovalca [24]. Ta je lahko človek, umetna inteligenca ali oddaljen sistem. Človeški pogled se mora odzivati na razne dogodke, izrisovati sceno na zaslon, predvajati zvok in opravljati še nekatere druge funkcije.

- Grafična predstavitev: Izrisovanje scene na zaslon je eden izmed procesorsko najzahtevnejših postopkov. Pri upodabljanju kompleksnih scen se moramo posluževati raznih optimizacijskih tehnik, če želimo prikazati veliko sceno z ogromno detajli. Optimizacijske tehnike zajemajo uporabo geometrije z več stopnjami podrobnosti (angl. Level of Detail – LOD) in filtriranje nevidne geometrije (angl. visible geometry culling).

- Avdio: Zvoki v igrah se običajno delijo na tri skupine: zvočni efekti, glasba in govor. Zvočni efekti so najpreprostejši, le naložimo zvok in ga predvajamo. Glasba se ne razlikuje veliko od zvočnih efektov. Najtežje pri njej je določitev ustrezne ambientne glasbe za določene dogodke v igri. Najzahtevnejša je uporaba govora, saj moramo poskrbeti še za sinhronizacijo ustnic.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 13

- Uporabniški vmesnik: Uporabniški vmesnik v igrah ima drugačen stil kot uporabniški vmesniki pri standardnih programih. Običajno ne potrebujemo kompleksnih kontrol, le gumbe, tekstovna polja in slike. Moderna orodja, kot so Iggy in Scaleform, nam omogočajo, da v igro neposredno uvozimo celoten uporabniški vmesnik, narejen s tehnologijo Flash.

Igralni pogled umetne inteligence je sestavljen iz dveh delov, s pomočjo katerih nadzira akterje. Prvi del analizira vhodne dogodke (premiki, trki, napadi). Naloga programerja je, da na tem mestu definira, kako bo umetna inteligenca reagirala na te dogodke. Drugi del je odločitveni sistem, ki je v celoti prirejen točno določeni igri.

Pri uporabi večigralstva mrežni pogled sodeluje skupaj z mrežno igralno logiko. Mrežna igralna logika je specializacija igralne logike. Od igralnega pogleda prejema dogodke in jih posreduje strežniku. Na strežniku se oddaljeni igralec prek mrežnega pogleda predstavlja enako kot agent umetne inteligence. Prejema dogodke, poslane s strani mrežne igralne logike, in jih posreduje igralni logiki.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 14

5 Organizacija akterjev

Igro sestavlja ogromno statičnih in interaktivnih objektov, ki jih med igranjem vidimo, slišimo, ali jih na kak drugačen način zaznamo. Objekti so pogosto imenovani tudi entitete, agenti ali akterji. Odločili smo se, da bomo v našem igralnem pogonu uporabljali izraz akterji.

Izbira ustrezne arhitekture za predstavitev akterjev je ključnega pomena pri izdelavi igre [24, 27]. V preteklosti so programerji za predstavitev akterjev zelo pogosto uporabljali tradicionalno hierarhijo z globokim dedovanjem razredov. Ta način postaja z večanjem števila akterjev prveč zahteven in težak za vzdrževanje. V zadnjih letih se trend nagiba proti drugim, bolj fleksibilnim arhitekturam. Ena izmed teh je arhitektura, temelječa na komponentah, ki smo jo izbrali za naš igralni pogon.

Primerjava tradicionalnega pristopa in komponentne arhitekture bo razkrila razlog, zakaj smo se osredotočili za komponente. V večini primerov je akter nek objekt v igri, ki je najverjetneje viden igralcu in se običajno lahko premika. Pri tradicionalnem pristopu ponavadi začnemo z osnovnim razredom za akterje, v katerem definiramo osnovne lastnosti, ki jih mora imeti vsak akter (kot npr. identifikator in položaj). Nadaljujemo s postopnim dodajanjem podrazredov, v katerih implementiramo dodatne funkcionalnosti. Primer takšne hierarhije prikazuje slika 5.1.

Čeprav na videz takšna razporeditev izgleda v redu, ima veliko slabih lastnosti. Z večanjem števila različnih funkcionalnosti začne graf rasti in postaja vedno težji za vzdrževanje. V primeru, da želimo imeti nekje v ozadju igre animiran objekt, ki nima nobenega vpliva na igro, potrebuje pa vizualno predstavitev, moramo imeti zraven tudi vse fizikalne lastnosti, čeprav le-teh sploh ne potrebujemo. Nekaj

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 15

podobnega bi se zgodilo, če bi želeli imeti animiran predmet, ki ga lahko poberemo. V takšnem primeru bi morali uporabiti večkratno dedovanje, ki lahko vodi do problema diamanta in podvojenih podatkov. Lahko poskušamo zgraditi drugačno drevo dedovanja, vendar nam nikoli ne bo uspelo narediti zadeve tako fleksibilne, da akterji ne bi na neki način vsebovali podatkov, ki jih v danem trenutku ne potrebujejo.

Akter

Grafika Točka pojavitve

Fizika

Animacija Predmet pobiranja

Človek Strelivo zdravje

Slika 5.1: Razporeditev razredov s tradicionalno metodo

Če dobro pogledamo graf na sliki 5.1, opazimo, da podrazredi dodajajo nove funkcionalnosti. Namesto da za dodajanje funkcionalnosti uporabimo dedovanje, se lahko reševanja problema lotimo tako, da posamezne funkcionalnosti združimo v komponente in z njimi sestavimo akterje; namesto dedovanja torej raje uporabimo kompozicijo. Tako lahko dobimo akterje z enakimi funkcionalnostmi kot s klasično arhitekturo, ki pa omogočajo veliko mero prilagodljivosti. Akter tako postane le mesto, kjer se shranjujejo komponente. Na sliki 5.2 vidimo razredni diagram, ki prikazuje komponentno usmerjeno arhitekturo. V tem modelu si akter lasti seznam komponent. Sam po sebi ne dela ničesar posebnega. Ima le identifikator, ime, seznam komponent in metode za njihovo dodajanje, odstranjevanje in dostop.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 16

Komponente so organizirane v skupine (družine) glede na skupno funkcionalnost. Komponente imajo skupen vmesnik, preko katerega komunicirajo z akterjem. Vmesnik vsebuje identifikator, ime komponente, starša in ime družine. Velikokrat morajo komponente komunicirati med seboj. Komunikacija je zagotovljena prek akterja, pri katerem kličemo metodo za dostop do posamezne komponente.

Akter Komponenta

Vmesnik fizikalne Vmesnik poberljive komponente komponente

Kvader Krogla Strelivo zdravje

Slika 5.2: Predstavitev razredov s komponentno arhitekturo

Gradnja akterja poteka v posebnih objektih imenovanih tovarne. Tovarna akterjev zgradi akterja na podlagi njegovega opisa. Pri gradnji si pomaga s tovarno komponent. Ta deluje enako kot tovarna akterjev, le da prejme opis komponente in vrne zgrajeno komponento. Komponente se po gradnji posredujejo upravitelju komponent. Njegova naloga je združevanje komponent po določenih merilih in njihovo posodabljanje.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 17

6 Implementacija

Pri implementaciji igralnega pogona smo najprej definirali seznam funkcionalnosti, ki jih bomo kasneje potrebovali za izdelavo različnih iger. Cilj je bil izdelati igralni pogon, s katerim bo mogoče izdelovati 2D igre za osebni računalnik. Ciljne igre so stransko pomikajoče ploščadne igre (angl. side-scrolling platformers), igre s pogledom iz ptičje perspektive (angl. top down view), nameri in klikni igre (angl. point and click) ter razne izpeljanke naštetih. To so igre, ki predstavljajo dosegljiv cilj za malo številčno ekipo neodvisnih razvijalcev.

Izdelava igralnega pogona je zahtevno opravilo, velikokrat preveliko za eno osebo. Obseg funkcionalnosti smo zato zelo omejili in se osredotočili samo na tiste, ki so ključne za delovanje igralnega pogona. Implementirali smo naslednje fukcionalnosti:

- ogrodje aplikacije,

- glavno zanko,

- osnovno nalaganje virov,

- osnovno risanje geometrije,

- osnovno predvajanje zvokov,

- igralno logiko,

- igralčev pogled,

- podporo uporabi skriptnega jezika,

- komunikacijo med sistemi z uporabo dogodkov in

- fizikalno simulacijo.

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 18

Ker smo se odločili, da bomo naš igralni pogon ponujal podporo le za prikazovanje 2D grafike, smo lahko močno oklestili nabor funkcionalnosti. Pri implementaciji smo izpustili naslednje pomembnejše funkcionalnosti:

- napredne funkcionalnosti za delo z viri (predpomnilnik, arhivi),

- napredno upodabljanje geometrije (uporaba senčilnikov),

- večnitnost,

- upravljalnik pomnilnika,

- boljše tehnike optimiziranja upodabljanja scene in

- večja razširljivost uporabe skriptnega jezika.

Pri naboru izpuščenih funkcionalnosti smo poudarili le pomembnejše. Seznam želenih funkcionalnosti bi se lahko raztezal čez več strani, saj igralni pogon predstavlja programski produkt, ki ni nikoli končan.

Uporabili smo programski jezik C++, ki je zaradi svojih lastnosti (hitrost, nadzor nad pomnilnikom) postal zelo popularen pri razvoju iger. Produktivnost smo povečali z uporabo novosti v standardu C++11, ki ga podpira že večina prevajalnikov. Za izdelavo urejevalnika smo izbrali programski jezik C# in tehnologijo WPF, kar nam je omogočilo lažjo in hitrejšo izdelavo uporabniškega vmesnika. Uporabili smo razvojno okolje MS Visual Studio, saj je bil MS Windows glavna razvojna platforma, to pa je vplivalo tudi na izbiro knjižnic, s katerimi smo si olajšali razvoj igralnega pogona.

V nadaljevanju bomo na kratko opisali implementirane sisteme igralnega pogona. Zaporedje sistemov sledi zaporedju arhitekture. Najprej so opisani sistemi v aplikacijskem nivoju, nato sistemi v igralni logiki in na koncu igralni pogledi.

6.1 Razred GameApp

Razred GameApp je glavni razred igralnega pogona in uporabniku navzen predstavlja aplikacijski nivo. V njem se izvajajo platformsko specifične naloge,

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 19

upravljanje z življenjsko dobo aplikacije in inicializacija logike igre. Ta razred je zasnovan kot vmesnik, ki naj ga določena igra deduje in tako razširi njegovo funkcionalnost s stvarmi, ki so specifične zanjo. Med te funkcionalnosti spada inicializacija logike igre, igralnih pogledov ter začetnega stanja igre.

Znotraj inicializacije aplikacijskega nivoja se inicializirajo naslednji sistemi:

- upravitelj z viri (razred ResourceManager),

- upravitelj dogodkov (razred EventManager),

- upravitelj okna (razred WindowHandler),

- upravitelj vhodnih naprav (razred InputManager),

- grafični uporabniški vmesnik (razred GuiSystem),

- upravitelj skript (razred ScriptManager),

- sistem za upodabljanje (razred Renderer),

- igrana logika (razred GameLogic) in

- omrežni upravitelj (razred SocketManager).

Inicializacija sistemov mora potekati v točno določenem vrstnem redu, saj so nekateri sistemi odvisni od drugih. Enako je tudi z njihovo ustavitvijo. Večina sistemov je implementiranih z uporabo načrtovalskega vzorca edinec (angl. singleton). Razred GameApp skrbi za njihovo življenjsko dobo. V aplikacijskem nivoju teče tudi glavna zanka, ki skrbi za posodabljanje stanja igre. Primer specializacije razreda GameApp prikazuje naslednji odsek kode:

// aplikacija igre class SuperIgra : public GameApp { protected: // metoda za inicializacijo igralne logike, specifične za trenutno igro // metodo moramo obvezno implementirati virtual BaseGameLogic* VCreateGameLogic() override; };

BaseGameLogic* SuperIgra::VCreateGameLogic() {

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 20

// inicializacija logike m_gameLogic = new SuperIgraLogic(); m_gameLogic->Init();

// inicializacija človeškega igralnega pogleda shared_ptr humanView(new SuperIgraHumanView()); humanView->VInit(); m_gameLogic->VAddView(humanView);

return m_gameLogic; }

6.2 Upravljanje z oknom

Upravitelj oken (razred WindowHandler) je manjši sistem v aplikacijskem nivoju, ki skrbi za funkcije, povezane z oknom aplikacije. Nabor funkcij obsega kreiranje in uničenje okna aplikacije, spreminjanje velikosti okna, zaznavo sporočil operacijskega sistema (zaustavitev sistema, spanje in spremembo zaslona) in posredovanje informacij iz vhodnih naprav (tipkovnica, miška in druge vhodne naprave) v sistem za analizo vhodnih podatkov (razred InputHandler).

Objekt nima globljega pomena. Obstaja predvsem zato, da imamo bolje organizirano kodo in smo v ta namen premaknili prej naštete funkcionalnosti iz glavnega razreda pogona v ta razred. Razred je platformsko odvisen in ga moramo v celoti na novo spisati, če želimo podpreti druge platforme.

6.3 Viri

Vire oz. resurse (angl. resources), ki jih bo igra vsebovala (teksture, zvoke), moramo nekako naložiti. Za to nalogo skrbi upravitelj virov (razred ResourceManager). Sestavljen je iz dveh glavnih delov: lokatorja virov (razred ResourceLocator) in nalagalnika virov (razred ResourceLoader).

Lokator virov skrbi za lociranje določenega vira. Razred ResourceLocator je spisan kot abstraktni razred, katerega specializacija določi način lociranja. V igralnem pogonu imamo implementiran razred FileLocator, ki locira določene datoteke na disku. Zaradi abstrakcije so lokatorji razširljivi na druge načine, npr. lokator za vire

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 21

na mrežni lokaciji ali lokator za vire iz arhiva (zip). Le novo specializacijo lokatorja moramo napisati.

Nalagalnik virov skrbi za nalaganje virov določenega tipa. Prav tako kot razred ResourceLocator, je tudi razred ResourceLoader spisan kot abstraktni razred in zanj velja enaka mera razširljivosti. Igralni pogon vsebuje nalagalnike za osnovne tipe virov (nekaj različnih tipov tekstur, wav za zvok, xml za razne podatke in lua za skripte).

Viri se po procesu nalaganja shranijo v pomnilnik in tam ostanejo na voljo drugim sistemom. Predstavljeni so z vmesnikom ResourceHandle, ta pa ima metodo, s katero iz njega pridobimo specifični tip vira.

Zahteva po viru poteka po naslednjem postopku. Upravitelj virov prejme zahtevo in preveri, ali je vir že naložen. Če je vir že naložen, vrne zahtevan vir, sicer pa nadaljuje z nalaganjem. Z uporabo lokatorja virov pridobi lokacijo vira. Nato, glede na tip zahtevanega vira, izbere ustrezen nalagalnik virov in mu posreduje lokacijo vira, da ga le-ta lahko naloži. Naložen vir se shrani v pomnilnik in vrne glede na zahtevo. Prikaz pridobitve vira je prikazan v naslednjem odseku kode:

// pridobimo vmesnik do vira z določenim imenom auto resourceHandle = ResourceManager::Get()->GetResource( Resource("ime vira"));

// vsi viri imajo skupen vmesnik za dostop do podatkov // iz vmesnika pridobimo zvok auto sound = resourceHandle->GetData(); // ali teksturo auto texture = resourceHandle->GetData()(); // ali skripto auto script = resourceHandle->GetData()();

6.4 Vhodne naprave

Nabor vhodnih naprav za igranje iger je zelo velik, zato smo se izdelave vhodnega sistema lotili premišljeno. Cilj je bil ustvariti robusten vhodni sistem, katerega uporaba bi bila neodvisna od vhodne naprave [28].

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 22

Osnovni gradnik našega vhodnega sistema (razred InputManager) tako predstavlja kontekst. V njem so definirani vhodni parametri, ki so igralcu v danem trenutku na voljo. Med potekom igranja igre lahko imamo na voljo več različnih kontekstov npr. kontekst za meni in kontekst za igranje. Različne kontekste pa lahko imamo tudi med samim igranjem igre, kot je to narejeno v akcijskih igrah z vozili (GTA, Battlefield), kjer so različni konteksti za igranje peš, vožnjo z avtom, vožnjo z letalom in podobno.

Kontekst vsebuje več različnih vhodnih tipov: akcije, stanja in razpon vrednosti. V našem igralnem pogonu smo se osredotočili le na prva dva tipa. V trenutni verziji igralnega pogona nismo podprli igralnih ploščkov, zato razpon vrednosti ni igral nobene vloge. Akcija je nekaj, kar se zgodi samo enkrat, kot npr. skok, vklop stikala in podobno. Akcija se sproži samo enkrat, ne glede na to ali igralec drži ustrezno tipko dlje časa. Stanja delujejo podobno, vendar so zasnovana za neprekinjena dejanja npr. tek ali streljanje. Stanja so predstavljena z binarnim stikalom, če je stanje aktivno, se nekaj izvaja, v nasprotnem primeru pa ne. Razpon vrednosti je vhodni tip, ki vsebuje numerično vrednost. Običajno so vrednosti normalizirane na razpon od 0 do 1.

Glavni proces, ki se izvaja znotraj vhodnega sistema, je preslikava vhodnih podatkov. To je postopek, pri katerem se podatki iz vhodnih naprav preslikajo v stanja ali akcije. Pravila preslikav so definirana znotraj konteksta. Vsak kontekst ima svoja pravila, kar nam omogoča, da lahko isti gumb predstavlja različno akcijo ali stanje glede na to, v katerem stanju igre smo (kateri kontekst je v danem trenutku aktiven). Proces se začne z zbiranjem vhodnih podatkov. Vhodni podatki so običajno odvisni od platforme, zato je ta del ločen in je implementiran znotraj upravitelja oken. V njem se v vsaki iteraciji zanke zberejo vhodni podatki in se posredujejo vhodnemu sistemu. Proces se nadaljuje s preslikavo vhodnih podatkov, kjer se posameznemu vhodnemu podatku določi identifikator gumba ali tipke. S trenutno aktivnim kontekstom preslikamo identifikatorje tipk v stanja ali akcije. Aktivna stanja in akcije se zbirajo v posebnem objektu – zbiralniku. Proces preslikave je končan. Med posodobitvijo stanja igre lahko pridobimo zbiralnik in

Izdelava igralnega pogona in urejevalnika za izdelavo 2D igrer 23

preverimo, ali je aktivna določena akcija ali stanje. Uporaba sistema vhodnih naprav je prikazana v naslednjem odseku kode: auto mappedInput = InputManager::Get()->GetMappedInput(); if (mappedInput->IsActionActive("skok")) { // izvedemo skok } if (mappedInput->IsStateActive("deso")) { // premikamo lik v desno }

Vhodni sistem je podatkovno usmerjen. Opis kontekstov in njihovih preslikav je definiran v datoteki XML in prikazan v naslednjem izpisu: