+ All Categories
Home > Documents > Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf ·...

Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf ·...

Date post: 01-Jun-2020
Category:
Upload: others
View: 2 times
Download: 0 times
Share this document with a friend
73
České vysoké učení technické v Praze Fakulta elektrotechnická Katedra počítačové grafiky a interakce Bakalářská práce Rozhraní pro tvorbu plošinových her Karel Mačalík Vedoucí práce: Ing. Michal Hapala Studijní program: Softwarové technologie a management, Bakalářský Obor: Web a multimedia 20. května 2011
Transcript
Page 1: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

České vysoké učení technické v PrazeFakulta elektrotechnická

Katedra počítačové grafiky a interakce

Bakalářská práce

Rozhraní pro tvorbu plošinových her

Karel Mačalík

Vedoucí práce: Ing. Michal Hapala

Studijní program: Softwarové technologie a management, Bakalářský

Obor: Web a multimedia

20. května 2011

Page 2: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

iv

Page 3: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

v

PoděkováníRád bych upřímně poděkoval Ing. Michalu Hapalovi za vedení práce, cenné rady a připo-mínky a v neposlední řadě za stanovení termínů, díky kterým jsem práci dokončil včas. Dálebych rád poděkoval své rodině za podporu během celého studia.

Page 4: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

vi

Page 5: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

vii

ProhlášeníProhlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedenév přiloženém seznamu.Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některýchzákonů (autorský zákon).

V Králíkách dne 19. 5. 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Page 6: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

viii

Page 7: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Abstract

Computer games are an important part of the entertainment industry, however their deve-lopment can be rather complex and expensive. The aim of this work is to describe an effortto create tools for developing simple platform games – game engine and editor.

The beginning of this thesis briefly aknowledges reader with computer games and nowa-days development tools and compares current commercial and free solutions. Then it conti-nues with examination of technologies for game engine and editor development.

Both Design and Implementation chapters provide insight into complicated developmentprocess with usage of modern programming paradigms such as event driven development,multithreading or scripting support. Included DVD contains developed application proto-type, which is being described within this document.

Abstrakt

Počítačové hry tvoří důležitou část zábavního průmyslu, ale jejich vývoj může být velicesložitý a nákladný. Cílem této práce bylo popsat úskalí vývoje nástrojů pro usnadnění tvorbyjednoduchých plošinových her – herního enginu a editoru.

Práce začíná úvodem do problematiky počítačových her a rozborem současných nástrojůpro jejich vytváření, porovnává současná komerční i zdarma distribuovaná řešení. Dále po-kračuje průzkumem aktuálních technologií pro vývoj herního enginu a editoru.

Návrhová a implementační část přináší náhled do leckdy komplikovaného procesu vývojes využitím moderních programovacích prostředků, jako je událostmi řízené programování,podpora více vláken nebo implementace skriptování. Na přiloženém DVD je prototyp vý-sledné aplikace, jejíž vývoj je v práci popisován.

ix

Page 8: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

x

Page 9: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Obsah

1 Úvod 11.1 Co je to hra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Jak hry dělíme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2.1 Logické hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2.2 Adventury . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2.3 Akční hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.4 Strategické hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.5 RPG (hry na hrdiny) . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.6 Rodinné a casual hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.7 Sportovní hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2.8 Plošinové hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.3 Kdo hry vytváří a jak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Nástroje pro tvorbu her a cíl BP 72.1 Herní engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.2 Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.3 Open source a low-cost alternativy . . . . . . . . . . . . . . . . . . . . . . . . 92.4 Technologická špička . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.5 Cíl práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3 Analýza technologií 153.1 Programovací jazyky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.2 Renderovací knihovny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.3 Fyzikální knihovny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.4 Skriptování . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4 Návrh aplikace 194.1 Událostmi řízená aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.2 Systémy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.3 Herní smyčka a třída Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.4 Graphics a ThreadedGraphics . . . . . . . . . . . . . . . . . . . . . . . . . . . 234.5 Task Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244.6 State a StateController . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.7 Načítání a ukládání dat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264.8 Struktura levelu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

xi

Page 10: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

xii OBSAH

4.9 Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5 Popis implementace 295.1 Reference counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295.2 Výjimky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305.3 Herní jádro, smyčka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315.4 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315.5 Zamykání (thread-safeness) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325.6 Binární serializace objektů a její záludnosti . . . . . . . . . . . . . . . . . . . 335.7 Fyzika Bullet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355.8 Umělá inteligence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

5.8.1 Vyhledávání cesty v prostoru, A* algoritmus . . . . . . . . . . . . . . 365.9 Skriptování a jazyk Lua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

5.9.1 Správa zásobníku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385.9.2 Boxing objectů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395.9.3 Eventy ve skriptech . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415.9.4 Debugger a krokování v editoru . . . . . . . . . . . . . . . . . . . . . . 425.9.5 Ukázka skriptování . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

5.10 Mezivrstva C++/CLI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435.11 Komunikace Engine / Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

6 Závěr 45

A Výpisy kódu 49

B UML diagramy 53

C Obrázky 57

D Instalační a uživatelská příručka 59D.1 Spuštění hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59D.2 Spuštění editoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

E Obsah přiloženého DVD 61

Page 11: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Seznam obrázků

1.1 Plošinová hra Trine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.1 Rozhraní editoru UnrealEd . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2 Game Maker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.3 Editor Hammer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4.1 Třídy související s událostmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.2 SystemManager sdružuje veškeré systémy . . . . . . . . . . . . . . . . . . . . 214.3 Herní smyčka událostmi řízeného enginu . . . . . . . . . . . . . . . . . . . . . 234.4 Životní cyklus vícevláknového rendereru ThreadedGraphics . . . . . . . . . . 244.5 Manažer stavů a zpracování vstupu . . . . . . . . . . . . . . . . . . . . . . . . 254.6 Třídy pro ukládání a načítání dat . . . . . . . . . . . . . . . . . . . . . . . . . 264.7 Rozvržení rozhraní editoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5.1 Editor obsahuje debugger pro krokování kódu . . . . . . . . . . . . . . . . . . 42

B.1 Třída Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53B.2 Rozhraní Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54B.3 Struktura TaskManageru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54B.4 Struktura základních LevelObjektů . . . . . . . . . . . . . . . . . . . . . . . . 55

C.1 Úprava cest AI v editoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

xiii

Page 12: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

xiv SEZNAM OBRÁZKŮ

Page 13: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 1

Úvod

V dnešní době tráví lidé čím dál více času konzumací multimediálního obsahu pomocí počí-tačů, mobilních telefonů, tabletů či herních konzolí. Moderní člověk 21. století tráví velkoučást volného času u svého osobního počítače prohlížením internetových stránek, poslechuhudby, sledováním filmů a hraním počítačových her. Právě počítačové hry zabírají větší avětší část. Podle průzkumu hrálo v roce 2007 nějakou počítačovou hry 72% Američanů[1]. Vroce 2010 byl průměrný věk hráčů 31 let[2] a v průměru strávili hraním 13 hodin týdně[2].V roce 2010 utratili Američané za počítačové hry více než 15 miliard dolarů[3]. Ve VelkéBritánii jsou tržby z her větší než tržby z filmů[4]. Ani Česká republika není v tomto ohledupříliš pozadu – obrat herního trhu České a Slovenské republiky dosáhl v roce 2010 rekordnívýše 2,189 miliardy korun[5].

Počítačové a konzolové hry evidentně tvoří velký byznys, kde se točí velké peníze. Vý-vojem her se zabývá spousta studií po celém světě, včetně České republiky. Nejslavnějšíherní vývojáři jsou považovány za celebrity ve svém oboru – jména jako John Carmack,Will Wright, Peter Molyneux nebo Ken Levine jsou známá milionům lidí z celého světa.Naproti tomu v technologicky nejvyspělejších státech, jako je Jižní Korea, jsou celebritamii „profesionální hráči“, jejichž zápasy vysílají místní televize v živém přenosu.

1.1 Co je to hra

Existuje několik definic toho, co je to hra. Podle IGDA1 je hra činnost s danými pravidly,která obsahuje konflikt nebo výzvu[13]. Počítačová hra je hra odehrávající se v digitálnímprostředí. Proto se počítačovým hrám přezdívá videohry. Pokud budu dále zmiňovat hry,budu myslet ty počítačové, ačkoliv většina věcí platí i pro ty klasické (stolní, karetní apodobně).

Většina her má cíle a úkoly, které musí hráč splnit či pokořit osvojením si a použitímherních prvků. Variabilita úkolů a herních prvků závisí na typu hry a cílové skupině hráčů.Jednodušší casual hry pro příležitostné hráče mají obecně minimum herních prvků a herníúkoly se u nich často opakují. Důvodem je, že hráči casual her u nich obecně tráví menšíčasové úseky, během kterých očekávají zábavu v co nejkratším čase – proto je snaha u

1International Game Developers Association je nezisková organizace, sdružující více než 10 000 herníchvývojářů z celého světa [http://www.igda.org/]

1

Page 14: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

2 KAPITOLA 1. ÚVOD

těchto her minimalizovat dobu učení se a co nejdříve hráče přenést do fáze zdokonalování se.Naopak třeba u strategických nebo RPG her trvá dokončení úkolu i několik hodin, běhemkterých si musí hráč osvojovat nové herní prvky.

Hry mívají jasně daný začátek a konec. Výjimku tvoří například on-linové hry, které majídaný konec jen zřídka a hráči je mohou hrát libovolně dlouho. I u nich ale hráči musí plnitdílčí ohraničené úkoly. Další výjimkou mohou být logické a arkádové hry, kde se hráč snažíhrát co nejdéle, aby tak dosáhl nejvyššího počtu bodů.

Videohry se snaží hráči zprostředkovat nějaký zážitek. Používají k tomu multimediálníobsah – obraz a zvuk. Drtivá většina her obsahuje příběh – některé jsou na vyprávěnípříběhu přímo založené. Uznávaná britská akademie BAFTA, která každoročně uděluje cenynejlepším filmům, od roku 2003 vybírá i nejlepší hry za daný rok a uděluje jim ceny za nejlepšípříběh, umělecké zpracování, zážitek z hraní a podobně[6].

Každá komerční hra musí před uvedením na trh projít kontrolou odborné komise, kteráhře udělí rating. Rating má za úkol sdělit potenciálnímu zákazníkovi pro koho je hra určena(věková kategorie), zda obsahuje násilné, sexuální či gamblerské motivy, a podobně[7]. Vestátech jako je USA, Austrálie nebo Německo je podobný rating vyžadován – bez něj senesmí hra prodávat v obchodech. Existuje několik ratingových systémů – například severoa-merický ESRB nebo evropský PEGI. Česká legislativa zatím nijak prodej her podle ratingůneupravuje, ale Asociace herního průmyslu České a Slovenské republiky o přijetí evropskéhoratingu PEGI v Česku usiluje[8].

1.2 Jak hry dělíme

Hry dělíme do několika herních žánrů. Hranice mezi nimi často bývá tenká – hry mohoukombinovat vlastnosti a prvky několika různých žánrů. Největší rozmach vývoje nastal v 80.a 90. letech 20. století, kdy vznikla jejich drtivá většina. Obecně se dá říci, že od té dobymoc nových druhů her nepřibylo. V poslední době vzrůstá obliba rodinných a casual her[10].

1.2.1 Logické hry

Nejde u nich v prvé řadě o vyprávění příběhu a málokdy obsahují násilí. Od hráče je vy-žadováno logické uvažování, často v kombinaci s rychlými reflexy. Těmto hrám se daří naméně výkonných zařízeních, jako jsou mobilní telefony, handheldy. Spoustu logických herjde spustit přímo v prostředí webového browseru. Díky své jednoduchosti (ve smyslu kom-plexnosti, ne obtížnosti) a přístupnosti dokáží zabavit i nehráče. Typickými zástupci jsou:Tetris, Puzzle Quest, Zuma.

1.2.2 Adventury

Adventury bývaly jednu dobu nejvíce oblíbeným druhem her, dnes jsou mírně na ústupu.Hráč prochází herní svět, komunikuje s jeho obyvateli a sbírá různé předměty, které musísprávně kombinovat pro další postup a odhalování příběhu. Adventury bývají klidné a ne-násilné a často obsahují logické prvky. Příklady: Siberia, Polda, Heavy Rain.

Page 15: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

1.2. JAK HRY DĚLÍME 3

1.2.3 Akční hry

Nejrozšířenější a nejprodávanější jsou akční hry. Od hráče vyžadují odvahu, rychlé reflexya za odměnu nabízí rychlou zábavu, intenzivní vtažení do herního světa a často preciznítechnické zpracování. V akčních hrách se nezřídka vyskytuje explicitní násilí, krev a prvkynepřátelství. Dělí se na hry z pohledu první osoby a hry z pohledu třetí osoby. Příklady:Call of Duty, Mafia, Halo.

1.2.4 Strategické hry

Poměrně starý žánr, který má nejlepší léta za sebou. Důležitým prvkem je strategické ataktické uvažování. Hraní většinou vypadá tak, že hráč buduje stavby a produkuje herníjednotky, se kterými útočí na nepřítele. Cílem je nepřítele porazit a obsadit jeho území.Existují i varianty bez boje – hráč staví virtuální město a s ostatními soupeří ekonomickya politicky. Některé strategické hry se dokonce používají ve školách při výuce historie (pronázornou ukázku slavných historických bitev). Příklady: série Command & Conquer, TotalWar, Anno.

1.2.5 RPG (hry na hrdiny)

Obdoba klasických deskových her převedených na monitory počítačů. Hráč prožívá různádobrodružství, během kterých si soustavně vylepšuje svou virtuální postavičku. Moderníodnoží jsou tzv. MMORPG – RPG hry pro více hráčů, kteří spolu hrají přes internet.

1.2.6 Rodinné a casual hry

Rodinné a casual hry zažívají nebývalý boom. Výrobci herních konzolí zjistili, jak obrovskýpotenciál mají příležitostní hráči a proto se jim snaží vyhovět – na všech moderních konzolícha handheldech se dají hrát hry pro sváteční hráče. Nejlépe se ale tomuto žánru daří naosobních počítačích – technicky neznalí lidé nemusí kupovat drahý a složitý hardware amohou hrát přímo v jejich webovém browseru. Tyto hry typicky nebývají příliš rozsáhlé anisložité – základním požadavkem je, aby hráč mohl začít hrát ihned bez přílišného studováníherních technik. Málokdy mají 3D grafické zpracování nebo náročné grafické efekty. Jejichrozmach souvisí s rozšiřování sociálních sítí – desítky milionů uživatelů lidí si na síti facebookoblíbilo hry jako FarmVille nebo MafiaWars, za jejichž hraní nemusí uživatel nic platit. Ziskgenerují z reklam a tzv. mikrotransakcí, kdy uživatelé nakupují drobné herní předměty avylepšení pro svou virtuální postavičku za reálné peníze.

1.2.7 Sportovní hry

Dnes má videoherní ztvárnění téměř každý sport. Nejúspěšnější jsou ztvárnění fotbalu, ho-keje a basketballu. Sportovní hry mohou pro ovládání využívat nestandartní periferie aovladače, včetně prvků pohybového ovládání. Příklady: série NHL, Fifa, Pro Evolution Soc-cer.

Page 16: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

4 KAPITOLA 1. ÚVOD

Obrázek 1.1: Plošinová hra Trine (Zdroj obrázku: http://trine-thegame.com)

1.2.8 Plošinové hry

Plošinové hry jsou kombinací žánrů akční hry z pohledu třetí osoby, adventury a logickéhry. Z každého žánru si berou určitou část. Hráč vidí avatara zboku a ovládá ho ve dvoudimenzích. Důležitým prvkem je skákání a překonávání překážek. Pro postup hrou můžebýt vyžadováno likvidování nepřátel, řešení logických hádanek nebo sbírání předmětů – tozáleží na konkrétní hře. Většinou u nich nejde o realistické zpracování. Ukázku plošinovéhry najdeme na obrázku 1.1. Příklady: Mario, Braid, Trine.

1.3 Kdo hry vytváří a jak

Proces vytváření her je rok od roku náročnější a nákladnější. Na počátku herního průmyslubyly hry vytvářeny několikačlennými týmy s minimálním rozpočtem. Dnešní vývoj největšíchher probíhá ve velkých herních studiích po několik let a stojí desítky až stovky milionůdolarů. Konkrétní rozpočty jednotlivých her vydavatelé neradi sdělují veřejnosti. Na hře sepodílí obrovská spousta lidí s různorodými profesemi – od programátorů, game designérů alevel designérů, přes 3D grafiky a animátory, až po zvukaře, hudební skladatele a scénáristy.Důležitou částí vývoje je testování kvality – tzv. QA (Quality assurance). Testování probíhápo celou dobu vývoje.Vývoj hry se může nacházet ve dvou fázích:

• Preprodukce

• Produkce

Page 17: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

1.3. KDO HRY VYTVÁŘÍ A JAK 5

Během preprodukce se plánuje, jak bude vývoj vypadat, co přesně se bude vytvářet azda to má smysl. V preprodukci vydavatel analyzuje trh a rozhodne se, zda bude po tituludostatečná poptávka, tak aby se zaplatily náklady na vývoj a hra generovala zisk. Designéři adalší členové týmu připraví podklady pro další vývoj – základ takzvaného Design dokumentu.

Design dokument má za úkol kompletně shrnout veškeré aspekty hry – od popisu herníchmechanik, přes artworky a náčrty postav a objektů, rozhovory postav až po rozdělení prácea časový harmonogram. Výsledná hra se může od tohoto dokumentu odlišovat – pokud senapříklad navržené mechaniky neosvědčí v implementovaných prototypech nebo pokud vý-vojáři nestíhají vše vypracovat do stanovené doby vydání. Přesto má ale design dokumentvelký význam – bez něj by nemuseli všichni členové týmu sdílet stejnou vizi. Velkým pří-nosem je pro členy, kteří se do procesu tvorby zapojí až v jeho průběhu. Design dokument(nebo jeho část) také může tvořit šablonu pro budoucí projekty (osvědčené nebo neimple-mentované mechaniky se převezmou do dalších her a podobně).

Během produkce studio implementuje herní mechaniky s pomocí herního enginu. V tétofázi se vývoje zúčastňují všichni členové studia. Vytvářejí se skripty, 3D modely, textury,zvuky a podobně. Dále se vytvářejí prototypy, na kterých se testují určité herní prvky. Hraběhem produkce prochází několika stádii ukončenými tzv. milestony. Posledním milesto-nem je distribuce zákazníkům. Většina her je vyvíjena i po začátku prodeje – opravují sedříve neobjevené chyby a připravuje se dodatečný herní obsah, leckdy placený (tzv. DLC –Downloadable Content).

Page 18: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

6 KAPITOLA 1. ÚVOD

Page 19: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 2

Nástroje pro tvorbu her a cíl BP

Velice důležité pro vývoj her jsou nástroje, se kterými členové týmu pracují a pomocí kterýchhru tvoří. Do těchto nástrojů se počítají zejména herní enginy a editory. To, zda zakoupithotové nástroje, nebo strávit čas s vývojem vlastních, si musí zodpovědět vývojový tým ještěpřed začátkem vývoje. Vždy záleží na dostupném rozpočtu a času, který s vývojem hodlajístrávit.

2.1 Herní engine

Herní engine je knihovna usnadňující vývoj počítačových her. Engine obsahuje základnínezbytné funkce, společné pro více her. Výsledné hry pak na těchto funkcích staví a rozšiřujíje o konkrétní herní mechaniky a specializované funkce, šité na míru danému hernímu žánru.Dobrý engine by také měl oprošťovat od závislosti na konkrétní platformě a řešit optimalizacea výkon. Se vzrůstajícími nároky na paralelizaci se v poslední době od moderního enginuočekává automatická distribuce výpočtů mezi více jader procesoru. Komerčně poskytovanéenginy jsou navrženy tak, aby s jejich pomocí šel vytvořit jakýkoliv typ hry. Vždy jsou aleprimárně optimalizovány pro jeden žánr – například dnes nejrozšířenější engine Unreal bylpoužit pro výrobu her snad všech možných žánrů, základ má ale v akčních střílečkách.

Engine poskytuje rozhraní pro ovládání scény, animací, fyziky, umělé inteligence, nasta-vení vykreslování nebo zpracování uživatelského vstupu. Měl by poskytovat rozhraní proskriptování pomocí skriptovacího jazyka. Některé využívají již hotových skriptovacích ja-zyků a některé přicházejí s jazykem vlastním, navrženým přímo pro typ hry, na který jeengine primárně zaměřen.

Nejaktuálnější enginy vždy tvoří technologickou špičku a posouvají hranice počítačovégrafiky. Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-ročnosti a novátorství používají jako benchmarky pro testování nového hardwaru. Každágenerace enginu idTech přináší něco nového do realtimové počítačové grafiky – napříkladtřetí generace (idTech 3), použitá v počítačové hře Quake III, vyžadovala jako jedna z prv-ních grafický akcelerátor a přinesla na svou dobu revoluční zpracování stínů a světelnýchefektů.

7

Page 20: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

8 KAPITOLA 2. NÁSTROJE PRO TVORBU HER A CÍL BP

2.2 Editor

Nároky na editor v posledních letech strmě vzrostly. Před několika lety k enginu existovaloněkolik samostatných úzce zaměřených nástrojů – například pro nastavení obalových tělesmodelů, pro nastavení textur a materiálu a podobně. Vývoj ale směřuje k integraci veškerýchnástrojů do jednoho programu – editoru.

Od moderního špičkového editoru se očekává, že bude fungovat na principu WISIWYG –What you see is what you get. Vývojář vidí v editoru hru naprosto stejně, jako bude vypadatna obrazovce u hráče. Tato vlastnost editorů se stává důležitou díky narůstajícímu množstvígrafických efektů, náročnosti renderované scény a celkovému důrazu na vizuální zpracování.Editor se v základu podobá klasickým modelovacím nástrojům jako je Autodesk Maya nebo3D Studio – hlavní část zabírá náhled scény, kterou uživatel editoru upravuje. Dále bývámožnost procházet assety (herní modely a textury), upravovat materiály a shadery nebopsát skripty. Ukázku rozhraní editoru UnrealEd nalezneme na obrázku 2.1.

Obrázek 2.1: Rozhraní editoru UnrealEd (Zdroj obrázku: http://unreal.com)

Nejvyspělejší editory poskytují i možnost upravovat cutscény podobně jako animace vsoftwaru pro střih videa – animátor nastavuje pro klíčové snímky transformace objektů neboanimace a okamžitě si může přehrávat vzniklé sekvence. Díky tomu, že vše probíhá v jednomprogramu, ušetří vývojáři spoustu času a navíc nemusí řešit podporu formátů, do kterýchse sekvence ukládají – editor je ukládá přímo do formátu, který podporuje hra.

S tím souvisí (dnes už běžný) požadavek na okamžité spuštění hry v editoru. Pokudvývojář navrhuje level nebo píše skript a nemá možnost hru okamžitě uvnitř editoru spustit,ztrácí spoustu času ukládáním práce v editoru a spouštěním hry. Spouštění hry přímo veditoru také přináší možnost lépe ladit skripty, za běhu hru pozastavovat a upravovat apodobně.

Dále najdeme v moderních editorech náznaky vizuálního programování – pomocí tzv.flowchartů vývojář definuje chování herních objektů (typicky umělé inteligence), animova-

Page 21: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

2.3. OPEN SOURCE A LOW-COST ALTERNATIVY 9

ných sekvencí nebo propojení materiálů a efektů. Tyto funkce umožňují na hře pracovat ineprogramátorům (designérům či grafikům).

Přestože výkon osobních počítačů nezadržitelně stoupá, stále nedokáží počítat vše vreálném čase. Spousta věcí souvisejících s osvětlováním a stínováním se počítá tzv. offline.Příkladem je předpočítání osvětlení pro velké části scény a jeho uložení do tzv. lightmapy.Velice často se podobné věci počítají právě v editoru. Grafik v editoru nastaví pozici světela řekne editoru, aby osvětlení spočítal a uložil. Hra poté za běhu spočítané osvětlení načtea použije a ušetřený procesorový čas může využít na něco jiného.

U editoru se předpokládá, že v něm budou tvořit i technicky méně zdatní lidé – gra-fici nebo level designéři. Proto by jeho uživatelské rozhraní mělo být co nejintuitivnější anejjednodušší.

Editor tvoří nadstavbu hotového enginu – využívá jeho funkce a přidává nástroje provytváření a testování herního obsahu. Hranice mezi enginem a editorem velice často splývá –pokud společnost nabízí vlastní engine k licencování, téměř vždy je součástí i editor. Editorytaké mohou být distribuovány společně s prodávanou hrou. Cílem je vybízet hráče k vytvá-ření vlastního obsahu – tzv. modů. Kolem takto podporovaných her pak může vzniknoutkomunita zapálených moderů, kteří ve volném čase tvoří nový herní obsah pro ostatní hráče.

2.3 Open source a low-cost alternativy

Existuje celá řada volně dostupných knihoven usnadňujících vývoj počítačových her. Avšakne každá se dá nazvat přímo herním enginem. Open-source knihovny jako Ogre nebo Irrlichtse primárně snaží usnadňovat vykreslování 3D scény a volitelně nabízejí propojení s dalšímipomocnými knihovnami - například pro načítání uživatelského vstupu nebo počítání fyziky.Nízká nebo nulová cena je vykoupena často nedostatečnou dokumentací a chybějící oficiálnípodporou. Také málokdy poskytují výkonné a široce použitelné editory. Výhodou je díkydostupnosti zdrojových kódů možnost si knihovnu dodatečně rozšířit podle vlastních před-stav. Některé původně proprietární bývají postupem času uvolněny pod volnou licencí – projejich použití pak může hrát rozsáhlejší dokumentace.

• Box2D1 – Volně dostupná knihovna primárně usnadňující počítání fyzikální simulaceve dvou dimenzích. Tuto knihovnu si zvolilo již několik vývojářů a použilo ji pro tvorbumenších komerčních her jako je Crayon Physics Deluxe nebo Rolando. Knihovna sedá použít na různých platformách – na osobních počítačích, konzoli Nintendo Wii,handheldu Nintendo DS či mobilních telefonech s operačními systémy Android a iOS.

• Crystal Space2 – Projekt Crystal Space se skládá ze dvou částí – knihovny pro vy-kreslování realtime 3D grafiky a pomocných systémů pro vývoj interaktivních aplikací,zejména her. Zahrnuje podporu pro skriptování pomocí jazyka Python, fyzikální si-mulaci, správu událostí (eventů), zpracování uživatelského vstupu, umělou inteligencinebo path finding.

1Box2D – oficiální stránky [http://www.box2d.org/]2Crystal Space – oficiální stránky [http://www.crystalspace3d.org/

Page 22: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

10 KAPITOLA 2. NÁSTROJE PRO TVORBU HER A CÍL BP

• IdTech 3 – V roce 2005 byl pod licencí GNU General Public Licence uvolněn slavný ave své době revoluční engine idTech třetí generace. Engine podoruje dynamické stíny,simulaci mlhy a odrazů zrcadel. 3D modely načítá z editory široce podporovanéhoformátu MD3. V roce 2011 má být podobně uvolněna i čtvrtá generace enginu, použitánapříklad v počítačové hře Doom 3.

• Torque3 – Cenově dostupný výkonný moderní engine použitý v celé řadě komerčníchher. Po zakoupení licence jsou poskytnuty kompletní zdrojové kódy a rozsáhlá doku-mentace. Existuje několik verzí: pro 2D hry nebo 3D hry na osobní počítače a pro 2Dhry na mobilní zařízení společnosti Apple. Součástí je i editor herního světa, skriptůa materiálů.

Obrázek 2.2: Game Maker je editor pro vytváření jednoduchých her (Zdroj obrázku:http://en.wikipedia.org)

• Game Maker – Proprietární editor, který je hojně používán pro vývoj freeware her.Umožňuje skriptování ve vlastním skriptovacím jazyku GML (Game Maker Langu-age). Základní osekaná verze editoru je k dispozici zdarma, rozšířenější stojí velicepřívětivých 25 dolarů. Z ceny je patrné, že editor míří na začínající vývojáře menšíchher. Game Maker je rozšířený i mezi českými vývojáři freeware her. Rozhraní GameMakeru si můžete prohlédnout na obrázku 2.2.

3Torque – oficiální stránky [http://www.garagegames.com/products/torque-3d]

Page 23: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

2.4. TECHNOLOGICKÁ ŠPIČKA 11

2.4 Technologická špička

Výběr mezi profesionálními enginy je o dost pestřejší. Každé větší herní studio má svůjvlastní a mnohé jej licencují dalším studiím. U některých se dokonce vývoj a prodej enginustal jejich primární činností. Pro začínající vývojáře a malá herní studia jsou tyto technologiefinančně nedostupné – ceny licencí za použití v komerční hrách se pohybují až v řádech stovektisíců dolarů.

Na druhou stranu ale tyto knihovny poskytují naprostou většinu potřebných funkcí,osvědčených použitím v už existujících komerčních hrách s miliony prodanými kusy. Před-stavují současnou technologickou špičku a nesrovnatelně převyšují drtivou většinu zdarmadostupných řešení. Určitou nevýhodou může být mírná vizuální podobnost her postavenýchna stejných enginech – každý si řeší stínování a nasvícení scény po svém (a používá pro tojiné optimalizace); osvětlení a stínování velice ovlivňuje tzv. grafický feeling.

• Unity – Moderní engine se vzrůstající oblibou u vývojářů. Vsází primárně na po-skytované Unity Development Environment – robustní editor pro vytváření herníhoobsahu. Chlubí se možností souběžného spuštění a editování hry. Součástí je modul dowebových prohlížečů, s jehož pomocí lze vytvořenou hru spustit přímo v prohlížeči.

Obrázek 2.3: Editor Hammer od společnosti Valve staví na enginu Source (Zdroj obrázku:http://www.thefullwiki.org/Valve_Hammer_Editor)

• Source + Hammer – Engine Source vyvinula společnost Valve pro svou hru Half-life2. Od té doby ho použila celé řada dalších her. I přes poměrné stáří (hra Half-Life

Page 24: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

12 KAPITOLA 2. NÁSTROJE PRO TVORBU HER A CÍL BP

byla vydána v roce 2004) se stále drží na špici a společnost Valve ho neustále vylep-šuje – přidána byla podpora pro výpočetně náročné osvětlování HDR, lepší obličejovéanimace a vícevláknové výpočty. Součástí je velice oblíbený editor Hammer. KolemSource enginu se utvořila silná základna lidí, kteří ve volném čase tvoří vlastní herníobsah ve formě modů. Valve dokonce umožňuje autorům takto vytvořené mody pro-dávat ostatním hráčům ve svém internetovém obchodu Steam – pro společnost jde ovýhodnou nabídku, protože veškeré mody pro spuštění vyžadují zakoupenou a nainsta-lovanou hru běžící na Source enginu (například Half-Life 2). Díky velikosti komunitymůžeme na internetu nalézt velké množství tutoriálů a návodů, jak s enginem a edi-torem pracovat. Ukázku z editoru najdete na obrázku 2.3.

• Unreal Engine + UnrealEd – Dnes nenajdeme používanější engine než Unreal Engine3. První generace byla určena pro hru Unreal a díky technologické vyspělosti se začalahojně používat i v dalších hrách. Seznam her, které pohání aktuální třetí generace, bybyl velice dlouhý. Cena za licenci oficiálně není veřejně známá, neoficiálně se hovoří o700 tisíci dolarech[9].

• Cryengine + SandBox – Technologicky nevyspělejší engine, který se snaží o fotorea-listickou počítačovou grafiku. Jako jeden z prvních přinesl podporu pro DirectX 10,třetí generace podporuje herní konzole a chlubí se stereoskopickým renderováním bezvýrazné ztráty výkonu.

2.5 Cíl práce

Cílem této bakalářské práce je vytvořit specializovaný herní engine (jádro hry), který budeprimárně pohánět plošinové hry, a nástroj pro vytváření herního obsahu (herní editor). Edi-tor bude umožňovat upravovat prostředí levelů, definovat herní pravidla, nastavovat fyzikuobjektů, skriptovat cut scenes sekvence a umělou inteligenci a také hru přímo spouštět atestovat v prostředí. Hra bude samostatně spustitelná i bez editoru. Pro demonstraci imple-mentovaných možností enginu a editoru bude vytvořena jednoduchá ukázková hra s několikaúrovněmi.Jádro hry by mělo podporovat:

• 3D grafické zobrazení

• Načítání 3D modelů, textur a materiálů z externích souborů a jejich správu v paměti

• Zpracování uživatelského vstupu

• Skriptovatelnou umělou inteligenci, s podporou pro vyhledávání cesty v 3D prostoru(tzv. pathfinding)

• Načítání herních levelů z externích souborů

• Fyzikální simulaci s nastavitelnými fyzikálními vlastnostmi herních objektů

• Animace modelů (včetně skeletální)

Page 25: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

2.5. CÍL PRÁCE 13

• Cut scenes – neinteraktivní skriptované sekvence

• Skriptovatelný Heads-up display (HUD) pro zobrazení informací o zdraví hráče, municiatd.

Editor bude nadstavbou herního jádra. Přidávat bude podporu pro:

• Načítání a ukládání herních levelů v editoru

• Přidávání, odebírání a rozmisťování herních objektů podobně jako v modelovacíchnástrojích

• Přímou úpravu herních skriptů – skriptování umělé inteligence, cut scenes, rozhovorůpostav, zpracování uživatelského vstupu atd.

• Editaci terénu

• Spouštění hry uvnitř editoru

• Debuggování skriptů s možností pozastavení hry pomocí breakpointů, její krokování,prohlížení obsahu proměnných, zásobníku volání atd.

Výsledkem budou 2 samostatné programy. Prvním bude spustitelné herní jádro, kterébude načítat a spouštět externě uložený herní obsah – assety, levely a skripty. Druhým pakeditor pro vytváření a testování tohoto herního obsahu.

Page 26: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

14 KAPITOLA 2. NÁSTROJE PRO TVORBU HER A CÍL BP

Page 27: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 3

Analýza technologií

Technologií a programovacích jazyků pro vytvoření herního enginu je celá řada, každá másvé výhody a nevýhody. Při výběru jsem se řídil mými dosavadními zkušenostmi a snažiljsem se zhodnotit budoucí potenciál každé technologie. Dalším vodítkem bylo, že engine ieditor budou sice primárně určeny pro platformu Microsoft Windows, ale zejména engineby mohl být v budoucnu portován na jiné platformy (Linux, MacOS).

3.1 Programovací jazyky

• Java – Objektově orientovaný jazyk s garbage collectorem běžící uvnitř virtual ma-chine. Kód napsaný v Javě se nejdříve překládá do bytecode a ten se kompiluje dostrojového kódu až na koncovém zařízení. Důvodem je maximální přenositelnost kódumezi platformami. Java je tedy multiplatformní, má dobrou dokumentaci a podporuvývojových nástrojů. Pro vývoj herního enginu se ale příliš nehodí kvůli omezené pod-poře grafických knihoven (omezeně se dá použít OpenGL), hodila by se spíše pro vývojeditoru.

• C#/.NET – C# je programovací jazyk v rámci softwarového frameworku Microsoft.NET. Podobně jako Java se C# překládá do obdoby bytecodu, nazývané CIL (Com-mon Intermediate Language). Přeložený kód se na koncovém zařízení optimalizujepro danou platformu a kompiluje do strojového kódu. Součástí .NETu je frameworkXNA, určený pro vývoj počítačových her. Nad použitím právě XNA jsem uvažoval,ale nakonec jsem ho vyřadil z důvodu nekompatibility s dalšími operačními systémy.Existuje sice implementace .NETu na jiné operační systémy nazvaná Mono, jde aleo implementaci neoficiální. Jazyk C# a platformu .NET jsem se rozhodl použít provytvoření editoru. Důvodem bylo, že vývoj v C# probíhá obecně jednodušeji a rych-leji než v klasickém C++ a také že framework .NET obsahuje z mého pohledu velicedobré API pro tvorbu uživatelského rozhraní. Podle mého názoru je ideální volbou provývoj windows-only aplikací, u kterých hraje důležitou roli uživatelské rozhraní a kdeje výkon aplikace až druhořadý.

• C++ – Jazyk C++ je považován za zatím nepřekonaného lídra, co se týče rychlosti apaměťové náročnosti. Jazyk se ihned kompiluje do strojového kódu, který může nativně

15

Page 28: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

16 KAPITOLA 3. ANALÝZA TECHNOLOGIÍ

běžet jen na kompatibilním stroji. Pokud chceme program spouštět na jiné platformě,musíme ho překompilovat. Jazyk umožnuje ovládat hardware na low-level úrovni, nemávestavěnou automatickou správu paměti a přináší několik mocných, ale nebezpečnýchnástrojů – ukazatele, přetěžování operátorů, vlastní alokace a uvolňování paměti nebodynamické knihovny. Vzhledem k tomu, že s ním mám bohaté zkušenosti a že v němje napsána drtivá většina profesionálních herních enginů, jsem se rozhodl zvolit právěC++.

3.2 Renderovací knihovny

Vykreslování scény může být v enginu řešeno pomocí externí hotové knihovny, nebo přímýmpoužitím některého API (OpenGL nebo DirectX). Vzhledem k tomu, že je tato práce zamě-řena na jiné věci než programování rendereru, jsem se rozhodl použít hotovou a osvědčenouknihovnu. Základním požadavkem byla možnost použití knihovny v C++, volná licence,dostačující dokumentace a případná přenositelnost mezi platformami.

• Irrlicht – Knihovnu Irrlicht jsem použil při vývoji jedné starší semestrální práce. Irrlichtje podle mého dostačující co se týče rychlosti vykreslování (pro menší hry), obsahujelíbivé moderní grafické efekty a optimalizace a dá se rozšířit celou řadou volně dostup-ných komponent (například rozšíření pro počítání fyzikální simulace). Bohužel jsembyl mírně zklamán rozsahem oficiální dokumentace a během vývoje zmíněné semest-rální práci jsem musel často studovat přímo zdrojové kódy Irrlichtu. Proto jsem chtěltentokrát zkusit knihovnu jinou.

• Ogre – Už z názvu Object-Oriented Graphics Rendering Engine lze usoudit, že je Ogreprimárně určeno k vykreslování scény. Nabízí i další dodatečné funkce jako správupaměťově náročných zdrojů v paměti (textury, modely atd.) a jejich načítání ze sou-borů, načítání uživatelského vstupu nebo vytváření uživatelského rozhraní. Ogre mávlastní formát materiálů, popsaných v textových souborech, včetně možnosti použítshadery. Komunita okolo Ogre vytvořila spoustu pluginů do existujících modelovacíchnástrojů pro export modelů a scén. Tuto knihovnu si k vývoji menších komerčních herzvolila už celá řada nezávislých studií. Podporuje vykreslování scény pomocí DirectX,OpenGL a díky tomu je přenositelné na jiné operační systémy a platformy. Ogre jsemse rozhodl použít pro vykreslování a správu scény.

3.3 Fyzikální knihovny

Jedním z vytýčených požadavků na engine je počítání fyzikální simulace. Vzhledem k tomu,že nemám s programováním fyzikálních výpočtů žádné zkušenosti, padlo opět rozhodnutína použití externí fyzikální knihovny. Požadavkem byl jazyk C++, volná licence a přenosi-telnost.

• ODE – S fyzikální knihovnou ODE mám lehké dřívější zkušenosti a bohužel ne úplněpříjemné. Přestože je uvolněna pod open-source licencí, tak ji používá celá řada vysoko-rozpočtových her. Díky open-source původu má jen minimální dokumentaci. ODE je

Page 29: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

3.4. SKRIPTOVÁNÍ 17

napsáno hlavně v jazyce C a využívá minimum výhod novějšího C++. Použití ODEjsem si nechal v záloze pro případ, že bych nenašel vhodnější alternativu.

• Bullet – Fyzikální knihovna uvolněná pod svobodnou licencí. Je používaná i pro po-čítání fyzikálních efektů ve filmech nebo renderovacích nástrojích. Velikou výhodou jeoptimalizace pro běh na více-jádrových systémech, část výpočtů umí přesunout i nagrafickou kartu. Použít se dá na osobních počítačích s různými operačními systémy,herních konzolích a mobilních telefonech. Bullet jsem zvolil jako hlavní knihovnu propočítání fyzikální simulace a zjišťování kolizí.

• PhysX – Proprietární komerční řešení fyzikálních výpočtů. Pro použití ve freewarehrách je PhysX zdarma, pro použití v komerčních hrách musí být zakoupena licence.V porovnání s knihovnami ODE nebo Bullet je PhysX zdaleka nejkomplexnější anejlépe zdokumentovanou. Nad jejím použitím jsem uvažoval, odradila mě uzavřenosta licencování u komerčních her.

3.4 Skriptování

Skriptování herní logiky, umělé inteligence a cutscén vyžaduje rychlý a flexibilní skriptovacíjazyk. Skriptovacích jazyků existuje celá řada a nedá se s klidným srdcem rozhodnout, kterýje lepší a který je horší. Každý má svá specifika a hodí se na něco jiného. Velice mě lákalozkusit navrhnout a implementovat jazyk vlastní. Bohužel v této oblasti nemám dostatečnézkušenosti a s vývojem bych strávil nezanedbatelné množství času. Proto padlo rozhodnutípoužít nějaké hotové a osvědčené řešení.

• Python – Python je díky své minimalističnosti a jednoduchosti velice používaný protvorbu rozšíření do existujících softwarů nebo pro vytváření webových stránek. Jakoskriptovací jazyk se ve hrách příliš nepoužívá.

• Lua – Pokud vývojáři neimplementují vlastní skriptovací jazyk, pak většinou volí právějazyk Lua. Je znám pro svou paměťovou nenáročnost a jednoduchost napojení naexistující aplikace. Lua má velice specifický objektový model, který nemusí vyhovovatkaždému. Dá se říci, že je tento jazyk dnes považován za standard v oblasti skriptováníher. Proto jsem se ho rozhodl použít.

• Vlastní – Pokud bych vytvářel vlastní skriptovací jazyk, musel bych navrhnout jehosyntaxi a implementovat virtual machine, který by ho vykonával. V implementovánívirtual machine se skrývá spousta záludností spojených s optimalizováním paměťovénáročnosti a rychlosti vykonávání skriptů. Toto téma by vydalo na samostatnou ba-kalářskou práci.

Page 30: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

18 KAPITOLA 3. ANALÝZA TECHNOLOGIÍ

Page 31: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 4

Návrh aplikace

Při vytváření aplikace bych rád použil moderní postupy, jako je událostmi řízené programo-vání, rozdělení kódu do samostatných systémů, využití task-based a vícevláknového progra-mování a přesunutí herní logiky do skriptů.

Při návrhu budu brát v potaz možnost budoucího rozšiřování enginu. Engine by měldůsledně oddělovat vykreslování, fyzikální simulaci a herní logiku pro snazší udržitelnost abudoucí rozšiřitelnost kódu. Každý systém si bude držet svou sadu dat a nezasahovat přímodo ostatních.

Engine by měl nabízet úpravu a nastavení většiny svých možností z externě uloženýchuživatelských skriptů. Skriptování by mělo hrát důležitou úlohu, proto bude jádro hodněobecné a nebude neomezovat rozmanitost výsledných her (v rámci zvoleného žánru plošino-vých her). Data herních úrovní by měla být načítána z externích souborů.

4.1 Událostmi řízená aplikace

Komunikace a předávání dat mezi objekty tvoří základní stavební kámen současných progra-movacích jazyků. Nejzákladnějším typem komunikace se rozumí volání metod, předávánímdat pak jejich parametry. Taková komunikace vyžaduje, aby její iniciátor věděl o každém, ským chce komunikovat (a mohl zavolat jeho metodu). Na druhé straně pokud příjemce datje už nadále nechce odebírat, musí přímo upozornit odesílatele. Je jasné, že taková komu-nikace vyžaduje, aby oba účastníci měli k dispozici přístup k tomu druhému. Vzniká přímázávislosti mezi objekty. Většinou se přílišné přímé závislosti v aplikaci snažíme vyhnout,třeba použitím komunikace nepřímé – vyvoláním události.

Událost (event) je zpráva upozorňující na skutečnost, že proběhla nějaká akce nebozměna. Zároveň nese data s akcí související. Každý kdo se o ní dozví, může zareagovat.Vyvoláním události odesílatel říká: Dávám na vědomí, že jsem provedl tuto akci, a nezajímámě, jak zareagujete.

Prozatím teoretický popis událostí doplním zjednodušeným příkladem: Dejme tomu, žeherní objekt Hráč má nějaké Zdraví. Pokaždé, když se mu hladina Zdraví zvýší nebo sníží,odešle událost HealthChangedEvent. Tu zachytí objekt starající se o vykreslování zdravíhráče (HUD) a upraví ukazatel Zdraví na novou hodnotu. Dále se o události dozví systémpro zpracování zvuku, a pokud je zdraví pod kritickou hodnotou, začne přehrávat zvuk

19

Page 32: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

20 KAPITOLA 4. NÁVRH APLIKACE

class EventManager

«interface»

EventReceiver

+ handleEvent(Event&) : bool

ScriptCallback

+ handleEvent(Event&) : bool+ saveScriptData() : void+ loadScriptData() : bool+ clearScriptData() : void

«interface»

EventManager

+ startReceiving(EventReceiver*, EventType&)+ stopReceiving(EventReceiver*, EventType&)+ startReceiving(ScriptCallback&, EventType&)+ stopReceiving(ScriptCallback&, EventType&)+ queueEvent(Event*) : void+ abortEvents(EventType&, bool) : void+ abortEvents(EventGroup&) : void+ abortAllEvents() : void

«static»+ getInstance() : EventManager*+ setInstance(EventManager*) : void+ deleteInstance() : void

«interface»

Event

«static»+ InternalEventGroup: EventGroup+ GameLogicEventGroup: EventGroup+ ScriptEventGroup: EventGroup+ ExternalEventGroup: EventGroup

+ getTimestamp() : unsigned long+ isOfGroup(EventGroup &) : bool+ isScriptOnly() : bool+ initScriptData() : bool+ buildScriptData() : void+ destroyScriptData() : void+ getType() : const EventType& + getGroup() : const EventGroup&

Obrázek 4.1: Třídy související s událostmi

tlukotu srdce. Bez použití událostí by Hráč musel buď přímo upozornit HUD a systém prozpracování zvuku, anebo by se příjemci museli Hráče neustále dotazovat na hladinu Zdraví.

Způsobů implementace událostí nalezneme několik. V základu se dělí na lokální a globální– buď se o jejich odebírání zaregistrujeme přímo u odesílatele a pak odebíráme jen zprávyod něj, anebo se zaregistrujeme u centrálního (globálního) mezičlánku a odebíráme zprávyod všech. Tento engine bude stavět na globálně šířených událostech použitím centrálníhosprávce eventů (EventManager) – viz obrázek 4.1. Pokud bude nějaká třída potřebovatpoužít lokální události, poskytne pro to rozhraní ve stylu návrhového vzoru Observer.

Pokud chceme odebírat událost, musíme EventManageru sdělit o jaký typ jde. Z tohodůvodu je potřeba události nějak rozlišovat. Nejjednodušší rozdělením může být výčtovýtyp enum – každý nový typ eventu si do globálního výčtového typu přidá nový záznam.Obrovskou nevýhodou takového řešení je omezení typů na dobu kompilace – poté nejde při-dávat nové typy událostí. Navíc by takový enum časem nabobtnal do těžko udržovatelnéhovýsledku. Proto padlo rozhodnutí použít dynamické typy eventů pomocí hešovaného textu– každý typ (EventType) bude hešová hodnota textového názvu (např. pro event změny po-zice objektu LevelObject_PositionChangedEvent). Dále se vyplatí dělit události do skupin– například skupina interních událostí enginu nebo skupina eventů herní logiky. EventMa-nager tyto skupiny opět rozlišuje pomocí heše (EventGroup). Proč zavádět skupiny? Pokudnapříklad skončí jedna herní úroveň (level), potřebujeme invalidovat veškeré události spo-jené s herní logikou, protože už nadále nemají smysl – řekneme EventManageru aby zrušil

Page 33: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

4.2. SYSTÉMY 21

všechny eventy skupiny GameLogicEventGroup (abortEvents).Distribuce eventu neprobíhá ihned po jeho zařazení, ale hromadně v každém jednom

kroku aplikace. Během distribuce EventManager projde frontu a každou událost rozešlevšem odběratelům. Odběratelé mohou být buď v rámci aplikace (EventReceiver), nebo vrámci skriptu (ScriptCallback). Pokud odběratel vrátí hodnotu true, považujeme událost zavyřízenou a přestáváme ji propagovat. Pokud vrátí false, pokračujeme v rozesílání.

Při vyvolávání eventu netušíme, kdo, kdy a v jakém pořadí se o něm dozví. Proto vy-žaduje událostmi řízené programování mírně odlišný způsob uvažování a přístup k návrhuostatních tříd. Velikou výhodou je odstranění závislostí a snadná rozšiřitelnost celé aplikace– zejména v kombinaci se skriptováním.

Nové typy událostí můžeme vytvářet i ve skriptech a defaultně jsou zařazeny do skupinyScriptEventGroup. Takto vytvořené eventy jsou obsluhovány pouze ze skriptů.

Při návrhu systému eventů jsem se částečně inspiroval v knize Game Coding Complete[14].

4.2 Systémy

Při návrhu každé aplikace je důležité ji dobře rozvrhnout do několika částí pro oddělenínesouvisející logiky. Každá taková část by měla být samostatná, snadno rozšiřitelná a vy-měnitelná. Větší funkční celky se vyplatí načítat ze samostatných knihoven – právě kvůlisnadné obměně, ale i pro snížení doby kompilace hlavního programu a třeba i pro rozdělenípráce mezi více lidí (každý pracuje na jiné části).

class Systems

«interface»

System

+ getSystemName() : string

SystemManager

«virtual»+ addSystem(string, System*)+ loadSystem(string, string)+ hasSystem(string) : bool+ getSystem(string) : System*+ removeAllSystems()+ removeSystem(string)

«static»+ getInstance() : SystemManager*+ setInstance(SystemManager*)+ deleteInstance()

«interface»

Game::GameloopListener

«virtual»+ onInit(Game*)+ onUpdate(Game*, long)+ onDestroy(Game*)

Obrázek 4.2: SystemManager sdružuje veškeré systémy

Sumarizací těchto požadavků vzniká něco jako systém – samostatný funkční celek, kterýse v aplikaci vyskytuje právě jedenkrát. Příkladem může být fyzikální systém pro počítánífyzikálních výpočtů nebo animační systém zaštiťující vše okolo animací.

Page 34: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

22 KAPITOLA 4. NÁVRH APLIKACE

To jak systémy zorganizujeme, ovlivní celkovou práci a manipulaci s nimi. Jednou zmožností je, co systém, to statická instance v nějaké třídě (návrhový vzor Singleton) – jehoinstance je pak přístupná odkudkoliv z aplikace. Nevýhodou je psát pro každý systém kódpro přístup. Navíc takové řešení ztěžuje přidávání nových systémů do již hotové aplikace.

Vhodnější variantou je manažer spravující veškeré systémy (SystemManager). Ten umožníjejich přidávání i za běhu. Systémy budou přístupné všude tam, kde bude přístupná instancemanažeru. V našem enginu bude tento manažer statickou instancí, Singletonem. Díky „všu-dypřítomnosti“ mohou vznikat skryté závislosti (jeden systém využívá jiný systém), protomusíme být při jejich používání obezřetní. Návrh SystemManageru nalezneme na obrázku4.2.

Systémy indexujeme podle názvu a drtivou většinu vytvoříme na začátku běhu aplikace– ať už přímým vytvořením a přidáním instance (addsystem), nebo načtením z dynamickéknihovny (loadSystem). Každý povinně implementuje rozhraní GameloopListener a odebírátak kritické interní události: Inicializace (Init), Aktualizace (Update) a Ukončení (Destroy).SystemManager každý nově přidaný automaticky zaregistruje pro odebírání těchto událostí.

4.3 Herní smyčka a třída Game

Základem každého herního enginu je variace na herní smyčku – neustále se dokola opakujícísled událostí:

1. Zpracuj vstup od uživatele (proces user input)

2. Aplikuj změny (update)

3. Vykresli scénu (render scene)

Konkrétní implementace se odvíjí od ostatních vlastností a požadavků – v každém krokunemusí být nutné ani výhodné provádět všechny tři kroky. Například zpracovat vstup a hernílogiku stačí typicky 20krát až 30krát za sekundu, zatímco počet vykreslených snímků musípro zachování plynulosti obrazu být větší – 30 snímků je minimum, optimálně by jich mělobýt 60.

Vzhledem ke zvolenému událostmi řízenému typu této aplikace, můžeme všechny třikroky sloučit do jednoho – Distribuuj eventy (viz obrázek 4.3). Během distribuce se zpracujenahromaděná fronta EventManageru a upozorní všichni odběratelé GameloopListener naudálost Update – mezi ně patří i systém pro zpracování uživatelského vstupu nebo systémpro vykreslování scény (každý zaregistrovaný systém povinně odebírá událost Update). Vjednom kroku herní smyčky bude skutečně explicitně docházet jen a pouze k distribuciudálostí. Počet těchto updatů za jednu sekundu bude pevně stanoven.

Původně třetí krok – vykreslení scény – obstará systém Graphics. Ten se při obdrženíudálosti Update sám rozhodne, zda dojde k vykreslení snímku. Vše záleží na zvolenémnastavení a implementaci, bližší popis nalezneme v kapitole 4.4. Renderer totiž může běžetna samostatném vlákně a v tom případě si to, kdy dojde k vykreslení scény, řeší sám.Přidělení vlastního vlákna přináší výhodu v oddělení počtu aktualizací herní logiky a počtuvykreslení scény. Pokud zvolíme nevláknovou implementaci, bude vykresleno tolik snímků za

Page 35: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

4.4. GRAPHICS A THREADEDGRAPHICS 23

act Game loop

«iterative»

Distribute events

Initialise

Destroy

Game end

Game start

[while running]

Obrázek 4.3: Herní smyčka událostmi řízeného enginu

sekundu, kolik bude updatů celé aplikace. Na první pohled nevýhodné řešení může mít smyslpři použití enginu na zařízení s nízkým výkonem – například chytrém mobilním telefonu nebotabletu.

Při navrhování třídy Game (viz obrázek B.1) byla snaha o maximální kompaktnost.Třída sice řeší obecně inicializaci celé hry a tikot herní smyčky, ale jen minimum dalšíchfunkcí. Vzhledem k tomu, že přístup k ní nepotřebuje téměř žádná další třída, nebyl důvodvolit návrhový vzor Singleton, přestože bude s největší pravděpodobností existovat vždy jenjedna instance.

4.4 Graphics a ThreadedGraphics

Systém Graphics zaštiťuje veškeré operace spojené s vykreslováním scény a manipulaci sgrafickými daty. Staví na knihovně Ogre a poskytuje její rozhraní ostatním. Při návrhu bylasnaha o odstínění práce s objekty Ogre a zároveň připravení třídy na možné vícevláknovézpracování. Zvolil jsem tzv. task-based programming – rozdělení do samostatně spustitelnýchúloh (tasks). Pokud bude potřeba manipulovat s Ogre objekty nad rámec poskytovanéhorozhraní, zapouzdříme operace do úlohy (GraphicsTask) a vložíme do fronty pro zpracováníúloh (TaskManager). GraphicsTask zpřístupňuje další operace pro práci s Ogre. O tom, kdydojde ke zpracování úloh, si rozhoduje samo Graphics. Pokud vytváříme objekty scény, pou-žijeme rozhraní GraphicsData – Graphics opět rozhodne, kdy zavolá operace pro vytvoření

Page 36: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

24 KAPITOLA 4. NÁVRH APLIKACE

(createData), synchronizaci (synchronizeData) a smazání dat (destroyData) objektu – datamohou být v rámci optimalizace vykreslování scény kdykoliv smazána či znovuvytvořena,proto se na ně po vytvoření nikde nespoléháme (tyto metody mohou být volány z jinéhovlákna). Všechny herní objekty implementují rozhraní GraphicsData.

act ThreadedGraphics

«iterative»

«parallel»

Initialise

Process Tasks

Render frame

Destroy

Synchronize data

[while rendering]

[another thread]

Obrázek 4.4: Životní cyklus vícevláknového rendereru ThreadedGraphics

Životní cyklus Graphics nalezneme na obrázku 4.4. Po inicializaci startuje smyčka, kdev každém kroku probíhá posloupnost: (1) Zpracuj nahromaděné úlohy (Process tasks), (2)Synchronizuj data (Synchronize data), (3) Vykresli snímek (Render frame). Pokud jde onevláknovou variantu Graphics, tento krok proběhne vždy při události Update třídy Game.V opačném případě – při použití ThreadedGraphics – tato smyčka běží na vlastním vlákněa tedy nezávisle. Výhodou ThreadedGraphics je lepší rozložení zátěže a možnost kontrolovathladinu snímkové frekvence (setTargetFps). U nevláknové je maximální počet snímků rovenpočtu aktualizací hry za sekundu.

4.5 Task Manager

Task based programming využijeme nejen u Graphics, ale i dalších částech aplikace. Úlohypostupně zařazujeme do fronty zpracování (addTask). Pokud je chceme zpracovat, pře-pneme na další frontu (switchTaskQueue), abychom během zpracovávání mohli přidávatúlohy nové, a ze staré fronty postupně vytahujeme úlohy (processOneTask), dokud není

Page 37: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

4.6. STATE A STATECONTROLLER 25

prázdná (hasTask). Třída nabízí rozhraní pro odebírání událostí spojených se zpracovánímúloh (TaskManager::Listener) – umožňuje úlohy filtrovat nebo jim předávat dodatečná data.Operace TaskManageru vidíme na obrázku B.3.

Základní verze správce úloh (SimpleTaskManager) není thread-safe. Pro více vláknovézpracování se hodí jiná varianta, zamykající data před ostatními (SafeTaskManager). Volbasprávce ovlivní výkon – každé zamknutí nás stojí drahocenný procesorový čas.

S rozčleněním kódu do úloh se pojí podobný problém jako u událostmi řízeného pro-gramování – při psaní kódu tasku netušíme, kdy dojde k jeho vykonání. Také netušímepřesné pořadí, v jakém úlohy proběhnou (pokud je přidává několik vláken zároveň). Nazačátku návrhu aplikace jsem počítal s masivnějším použitím úloh a jejich automatickouparalelizací mezi více vláken. Takové řešení by znamenalo lepší rozložení výpočtů mezi víceprocesorových jader. Jenže zmíněné vlastnosti mě od toho nakonec odradily. Větší pou-žití a paralelizace tasků bude cílem dalšího researche a vývoje. Prozatím využívá vláknovézpracování tasků jen Graphics, nevláknové pak volitelně další části aplikace.

4.6 State a StateController

Typická hra začíná úvodní obrazovkou, následuje menu, kde hráč zvolí, zda chce začít novouhru, nebo načíst uložený postup či změnit nastavení. Pokud zvolí novou hru, hra přehrajeúvodní filmeček (intro) a načte a spustí první level. V každém tomto okamžiku se hra nacházív určitém stavu (State). Každý stav zobrazuje něco jiného a jinak reaguje na vstup od hráče.Proto engine obsahuje systém StateManager, kterým rozlišuje, ve kterém stavu se nachází.

Všechny stavy mají jméno, pomocí kterého je identifikujeme. Na začátku vytvoříme azaregistrujeme všechny možné stavy (addState) a poté mezi nimi přepínáme (changeState).Stavy se dají přidávat a odebírat i v průběhu hry, například pomocí skriptů.

class States

«interface»

StateManager

«virtual»+ addState(State*)+ removeState(State*)+ hasState(string) : bool+ changeState(string) : State*+ getActiveState() : State*+ deactivateActiveState()

«Event»+ StateChangedEvent()

«interface»

State

«virtual»+ getName() : string+ isActive() : bool+ setController(StateController*)+ getController() : StateController*+ removeController()+ setInput(InputSystem*)+ activate()+ deactivate()

«interface»

StateController

«virtual»+ keyPressed(KeyEvent) : bool+ keyHeld(KeyEvent) : bool+ keyReleased(KeyEvent) : bool+ mouseMoved(MouseEvent) : bool+ mousePressed(MouseEvent) : bool+ mouseReleased(MouseEvent) : bool+ activated()+ deactivated()

Obrázek 4.5: Manažer stavů a zpracování vstupu

Každý stav může mít právě jeden ovladač (StateController), který odebírá události odsystému pro zpracování uživatelského vstupu (InputSystem). O zařazení ovladače do Input-Systemu se automaticky postará State, který obdrží připravenou instanci InputSystemu vokamžiku, kdy je aktivován manažerem. Propojení tříd vidíme na obrázku 4.5.

Page 38: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

26 KAPITOLA 4. NÁVRH APLIKACE

4.7 Načítání a ukládání dat

class BinarySerializedFile

BinaryData

«virtual»+ serialize(char *, unsigned int)+ deserialize(char*, unsigned int)+ getSerializationStart() : char*+ getSerializationLength() : unsigned int+ addData(char *, unsigned int)+ endDataTier()+ nextDataTier()+ resetData()+ getNextData(unsigned int&) : const char*+ hasNextData() : bool+ hasSpace(unsigned int) : bool

«interface»

Serializable

«virtual»+ beforeSerialization()+ afterSerialization()+ beforeDeserialization()+ afterDeserialization()+ getDynamicDataSize() : unsigned int+ createEmptyData() : BinaryData*+ createEmptyData(unsigned int) : BinaryData*+ serialize(BinaryData*)+ deserialize(BinaryData*)

«interface»

BinarySerializedFile

«virtual»+ addData(Serializable*)+ saveFile(std::string)+ loadFile(std::string)+ hasNextData() : bool+ getNextData() : Serializable*

Obrázek 4.6: Třídy pro ukládání a načítání dat

Ukládání dat a jejich zpětné načítání je nezbytnou součástí enginu. Rozlišujeme mezipoužíváním běžnému člověku nečitelného binárního souboru a srozumitelnější textové vari-anty – například formát xml. Každý způsob má své výhody a nevýhody a každý se hodík jinému účelu a pro jiná data. Vzhledem k realtime povaze enginu se z hlediska výkonuvyplatí pro většinu dat používat binární formát – je datově úspornější a dá se zpracovávatrychleji (odpadá nutnost parsování). Proto bude engine poskytovat rozhraní pro ukládánía načítání objektů do binárního bloku dat – tzv. binární serializaci. Takto serializovanádata můžeme uložit do souboru či odeslat po síti. Každá třída, která implementuje rozhraníSerializable (viz obrázek 4.6), může být uložena do souboru BinarySerializedFile.

4.8 Struktura levelu

Herní úrovně (Levely) rozčleňují hru do menších úseků. Obsahují veškeré objekty virtuálníhosvěta, ve kterém se hráč pohybuje, a definují pravidla, podle kterých děj hry probíhá.

Prapředkem všech herních objektů je třída LevelObject (viz obrázek B.4), která dědíod PhysicsObject a je tak fyzikálním objektem. To je důležitý předpoklad – všechny herníobjekty podporují fyziku. Třída Model představuje 3D grafický objekt s podporou animací(startAnimation). Typickým příkladem Modelu jsou objekty tvořící pozadí a prostředí le-velu. Character je rozšířením Modelu, které už tvoří ovladatelnou postavu – „herce“ (Actor).Character může být ovládán hráčem, skriptem, nebo umělou inteligencí. Pro spínání skrip-tovaných událostí použijeme Trigger a ScriptedTrigger, které jsou typicky spínány kolizí snějakým jiným objektem.

Každý LevelObject implementuje rozhraní Serializable a může být tedy uložen do sou-boru nebo odeslán po síti a zpětně načten. Levely budou primárně ukládány Editorem běhemjejich vytváření a testování.

Page 39: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

4.9. EDITOR 27

Každá úroveň může mít přiřazený svůj vlastní skript, který je vykonán při spuštěnílevelu. Skriptem můžeme přidávat další objekty, ale hlavně definovat herní pravidla – cohráč smí a co nesmí.

4.9 Editor

Editor staví na API enginu a přináší minimum další funkčnosti. V zásadě jde jen o uži-vatelské rozhraní, proto nebude z technologického ani návrhového hlediska (návrhu tříd)příliš popisován. Bude využívat u platformy .NET standardního rozdělení do formulářů akomponent. Událostmi řízené programování je zabudováno přímo v jazyce C#.

Pro podporu historie uživatelem provedených akcí a také kvůli vícevláknovému přístupubude veškerá komunikace editor/engine probíhat pomocí operací zapouzdřených do třídimplementujících rozhraní EditorOperation. Každá operace bude reprezentována instancítéto třídy. Uživatel díky tomu bude moc využívat výhod historie akcí a vracet zpět provedenéoperace.

Souhrn levelů, skriptů, assetů a nastavení upravovaných v editoru bude ukládán dojednoho projektového souboru. Uživatel načte uložený projekt a může pokračovat v práci.

Editor bude podporovat debuggování skriptů, včetně možnosti krokování kódu, prochá-zení zásobníku volání a zobrazování obsahu proměnných ve skriptu. Veškerý kód pro debu-ggování bude součástí enginu, editor k němu jen poskytuje rozhraní.

Obrázek 4.7: Rozvržení rozhraní editoru

Návrh rozvržení rozhraní editoru je na obrázku 4.7. V horní části okna (1) bude stan-dardní horizontální lišta menu pro načítání a ukládání projektu, levelů, skriptů a podobně apod ním nástrojové lišty pro ovládání projektu, spouštění hry a používání debuggeru. Oknobude vertikálně rozděleno na dvě části (šířku si uživatel bude moci přizpůsobit), každáčást bude obsahovat další záložky. Vlevo (2) budou neměnné záložky pro úpravu nastaveníprojektu, levelu, vybraného objektu a zvoleného nástroje pro úpravu. Napravo (3) budou

Page 40: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

28 KAPITOLA 4. NÁVRH APLIKACE

dynamické záložky pro úpravu herního obsahu – například záložka s načteným levelem, tex-tovými skripty a podobně. V okně záložek mohou být další nástrojové lišty, jejichž obsahbude záležet na typu záložky (úpravu jakého typu obsahu nabízí) a zvoleném nástroji proúpravu (například nástroj pro manipulaci s objektem levelu a podobně). Ve spodní části(4) mohou být ještě další záložky s aditivním obsahem – například výpis konzole, debugovéinformace (výpis proměnných, zásobník volání a podobně).

Úprava levelu bude probíhat vizuálně – uživatel uvidí náhled levelu stejně jako ve hře.Bude moci vybírat herní objekty kliknutím myši a transformvat je manipulátory – ve středuobjektu bude zobrazen klasický tříosý manipulátor podobně jako ve většině editorů proúpravu 3D objektů. Uživatel bude moci posouvat, přibližovat a oddalovat kameru.

Page 41: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 5

Popis implementace

V této kapitole popíšu jen některé zajímavé části implementace. Veškeré třídy implemento-vané v C++ se nacházejí v namespace RD, psané v C++/CLI v RD_NET a ty v C# pakv RDEditor.

5.1 Reference counting

Protože je většina objektů sdílena mezi jádrem, editorem a skripty, těžko se definuje kdyje vhodné nepoužívané objekty mazat. Většinou je nemůžeme mazat ručně v C++, protožemohou být používány v ostatních částech s automatickou správou paměti. Ani nemůžememazání přenechat garbage collectoru .NETu nebo jazyku Lua, protože ten by nám objektsmazal, přestože bychom ho ještě používali v jiné části.

Řešením je u takto sdílených objektů udržovat počet jejich referencí – kolikrát je na ob-jekt odkazováno. Pokud počet referencí klesne na nulu, můžeme objekt smazat. Pro počítáníreferencí je použito tzv. chytrých pointerů (smart pointers). Smart pointer je instance třídys přetíženými operátory, které automaticky zvyšují a snižují počet referencí na spravovanýobjekt.

Knihovna Ogre používá smart pointerů knihovny boost – jde o třídu boost::shared_ptr.Tato třída dovoluje spravovat jakákoliv dynamicky alokovaná data a počet referencí udržujenezávisle na objektu a počet si předává mezi instancemi smart pointeru. Takové chováníby pro většinu normálních situací dostačovalo, má však jednu nevýhodu. Spravovaný objektnemá žádnou vazbu na počet referencí, takže pokud jeho holý ukazatel předáme nové instancismart pointeru, dojde pravděpodobně k vícenásobnému uvolnění paměti. Kvůli podpořeskriptování potřebujeme operovat i s holými ukazateli, kde by podobné chování způsobovalopotíže. Pointery boost::shared_ptr jsou použity jen pro počítání referencí instancí třídyEvent, která není přímo ve skriptech ukládána (do skriptů ukládáme jen data eventu, neukazatel na jeho instanci).

Pro ostatní objekty jsem vytvořil vlastní specializovanější smart pointery – nazývám jereference (třída „ref“). Data o počtu referencí jsou uložena přímo ve spravovaném objektua třída ref s nimi jen manipuluje. Podobají se referencím v jazyku C# nebo Java. Třídaref nijak neomezuje práci s objektem. Umožňuje například referenci předávat jako parametr

29

Page 42: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

30 KAPITOLA 5. POPIS IMPLEMENTACE

metod a bere v úvahu substituční princip – pokud volaná metoda očekává rodičovský typ,objekt je automaticky (ale bezpečně) přetypován i se zachováním počtu referencí.

Výpis 1

1 ref<Player> player = level−>getPlayer ( ) ; // ziskani reference2 player−>setWeight ( 50 . 0 F ) ; // manipulace s objektem3 camera−>follow ( player ) ; // metoda follow ocekava nadtyp ref<LevelObject>

Každý objekt, který chce být referencován, musí dědit od třídy Referenceable. Ukázkupráce s referencí si můžeme prohlédnout ve Výpisu 1.

5.2 Výjimky

Jazyk C++ umožňuje vyhodit jako výjimku naprosto jakýkoliv datový typ. Tato mírnáanarchie má za následek absenci informace o místě původu výjimky. Bez připojeného de-buggeru neznáme při zachycení výjimky místo, odkud byla vyvolána. S použitím maker setomuto dá zabránit a do výjimky zanést jméno souboru a číslo řádku, kde byla vytvořena.Ve Výpisu 2 nalezneme rodičovskou třídu všech výjimek enginu a ukázku definice konkrétnívýjimky a jejího použití. Pokud je definováno makro RD_USE_MACRO_EXCEPTIONS,bude vyvolaná výjimka obsahovat název souboru a číslo řádku, kde byla vytvořena. Veškerévýjimky enginu dědí od RD::Exception a nabízejí příslušné makro. Výjimky související seskriptováním navíc ještě obsahují informace název skriptu a číslo řádku skriptu, kde k chybědošlo, a výpis zásobníku volání (skriptu).

Výpis 2

1 // rodicovska trida vech vyjimek enginu2 class RD : : Exception3 {4 public :5 std : : string exception ; // nazev vyjimky6 std : : string filename ; // název souboru7 long line ; // íslo ádku8 std : : string message ; // zprava o chybe9

10 public :11 Exception ( const Exception& e ) ;12 Exception ( std : : string message , std : : string exception = " Exception " ,13 std : : string filename = "" , long line = −1) ;1415 virtual ~Exception ( ) ; // virtualni destruktor pro zamezeni memory leaku1617 std : : string getName ( ) ;18 std : : string getMessage ( ) ;19 std : : string getFilename ( ) ;

Page 43: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.3. HERNÍ JÁDRO, SMYČKA 31

20 long getLine ( ) ;21 } ;2223 // ukazka specificke vyjimky24 class RD : : SerializationException : public RD : : Exception25 {26 public :27 SerializationException ( std : : string message , std : : string filename = ""←↩

,28 long line = −1)29 : Exception ( message , " SerializationException " , filename , line )30 {31 }3233 #ifdef RD_USE_MACRO_EXCEPTIONS34 # define SerializationException ( message ) \35 SerializationException ( message , __FILE__ , __LINE__ )36 #endif37 } ;3839 // ukazka vyhozeni vyjimky, do ktere je automaticky ulozen nazev souboru a cislo radku40 throw SerializationException ( " Length of serialized data is invalid " ) ;

5.3 Herní jádro, smyčka

Herní jádro řeší inicializaci a uvolnění systémů, zanesení definic tříd pro skripty a v nepo-slední řadě tikot herní smyčky. Herní smyčka je součástí metody Game::run() a je imple-mentována jako pseudo-nekonečný cyklus s omezeným počtem updatů za jednu sekundu.Na každý update tak vychází určitý časový úsek – pokud update trvá kratší dobu než tentoúsek, je na zbytek času jádro (respektive vykonávající vlákno) uspáno; pokud trvá déle,zkrátí maximální stanovaný čas dalšího updatu. Při dlouhých updatech se tak automatickysníží jejich počet. Maximální počet je standardně stanoven na 25 updatů za 1 sekundu, cožje pro aktualizaci herní logiky naprosto dostačující.

Během jedné aktualizace jsou distribuovány všechny nahromaděné události a aktualizo-vány všechny systémy. Systém během této aktualizace obdrží údaj o časovém úseku, kterýuplynul od minulé aktualizace – to je výhodné například pro aktualizaci fyzikálního modelunebo animací.

5.4 Graphics

Jak už bylo řečeno v návrhové části 4.4, systém Graphics (viz obrázek B.2) zaštiťuje veškeréoperace spojené s vykreslováním scény a manipulaci s grafickými daty. Staví na knihovněOgre a poskytuje její rozhraní ostatním. Práce s Ogre vypadá následovně: srdce knihovny senazývá Ogre::Root a obsahuje a spravuje veškeré subsystémy. Po inicializaci Ogre::Root, zvo-líme Ogre::RenderSystem (například DirectX) a okno Ogre::RenderWindow s jedním nebo

Page 44: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

32 KAPITOLA 5. POPIS IMPLEMENTACE

několika Ogre::Viewport. Dále vytvoříme Ogre::SceneManager pro vykreslovanou scénu. Vy-kreslitelné objekty přidáváme do Ogre::SceneManager jako potomky Ogre::SceneNode.

Graphics řeší vytváření většiny Ogre objektů, v externě definovaných grafických datech(GraphicsData) většinou vytváříme až objekty scény – Ogre::SceneNode, Ogre::Entity apodobně.

Interface RD:: Graphics má 2 defaultní implementace: RD::OgreGraphics a RD::ThreadedGraphics,která přesouvá běh OgreGraphics na vlastní vlákno. Třída Game podle předaného iniciali-začního nastavení RD::Settings vybere jednu z těchto implementací. Kvůli vícevláknovostiGraphics používá TaskManager pro veškeré operace vyžádané zvnějšku. Samostatně běžícívlákno si pak úlohy vytahuje a zpracovává. Vlastní úlohy můžeme do toho manažeru za-řazovat i externě – stačí rozšířit třídu GraphicsTask, která poskytuje přístup i k protectedmetodám Graphics. Díky tomu lze libovolně upravovat chování a nastavení rendereru.

Vláknová implementace spouští pseudo-nekonečnou smyčku velice podobnou herní smyčce5.3 – opět jde o pseudo-nekonečnou smyčku s maximálním počtem updatů za jednu sekundu– počet vykreslených snímků za vteřinu (FPS – frames per second). Tento počet můžemeexterně nastavovat (setTargetFps) a pokud nastavíme hodnotu na nulu, renderer nebudenijak FPS limitovat – takové chování znamená maximální možný počet FPS, což ale můžeznačně zatěžovat hardware. U nevláknové verze toto nastavení počtu FPS nemá význam arenderer ho nijak nebere v potaz.

5.5 Zamykání (thread-safeness)

Všechny vícevláknové aplikace musejí brát v potaz paralelní přístup ke společným datůma nějak se s tímto faktem vypořádat. Při ignorování toho problému dochází k nepředvída-telným a obtížně zachytitelným chybám – klasickým příkladem je pokud první vlákno čtedata, které druhé vlákno v tu samou chvíli upravuje. První vlákno tak může načíst jen zčástiupravená data, což je velkým problémem, pokud například data reprezentují ukazatel naadresu v paměti – výsledkem je nesmyslná adresa a možný pád aplikace.

I při použití zámků musíme být obezřetní. Pokud po zpracování dat neodemkneme zá-mek, kterým jsme zamezovali manipulaci s daty ostatním, můžeme způsobit trvalé uzamčenídat. K této situaci může například dojít, pokud během zpracování dat dojde k vyhození vý-jimky. Další komplikaci způsobí, pokud si dvě vlákna zamknou data navzájem – první vláknočeká na dokončení operace druhého a druhé vlákno čeká na dokončení operace prvního. Vý-sledkem je zamrznutí obou vláken.

Pro eliminaci těchto problémů jsem použil mutexy a zámky z knihovny boost – konkrétněboost::recursive_mutex a boost::unique_lock. Tato kombinace umožňuje vícenásobné zamy-kání dat stejným vláknem a díky RAII1 přístupu eliminuje nutnost ručního odemykání –každý zámek je reprezentován objektem na zásobníku a je tak platný jen v rámci dané částikódu (scope). Při jeho odstranění ze zásobníku dojde automaticky k odemčení mutexu.

Všechny části kódu využívající zámky nabízejí makra, kterými jde zamykání zakázat apovolit. Tyto makra se nacházejí v hlavičkovém souboru „app_pch.h“ – pro zakázání zámků

1Resource Acquisition Is Initialization je technika zaručující, že dojde uvolnění alokovaných prostředů zavšech okolností. Technika využívá faktu, že jediná část kódu, která je automaticky volaná během výjimky čiukončení volání funkce, je destruktor.

Page 45: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.6. BINÁRNÍ SERIALIZACE OBJEKTŮ A JEJÍ ZÁLUDNOSTI 33

určité části stačí zakázat příslušné makro a překompilovat aplikaci. Vliv mají následujícímakra:

• RD_GENERATOR_THREADSAFE – zámky u generátoru terénu

• RD_EVENTMGR_THREADSAFE – zámky u EventManageru

• RD_GRAPHICS_THREADSAFE – zámky u OgreGraphics

Dále je ve stejném souboru makro RD_DEBUG_LOCKS, jehož definice způsobí výpiskaždého uzamknutí mutexu, což může být nápomocné při hledání chyb souvisejících sezámky.

5.6 Binární serializace objektů a její záludnosti

Základní myšlenkou binární serializace implementované v jazyce C a C++ je přímé kopí-rování surových dat objektu. Tuto skutečnost musíme při psaní serializované třídy brát vpotaz – nemůžeme například používat pointery na jiné objekty, čímž se ochudíme o možnostukládat dynamicky alokovaná data a tedy i data o předem (myšleno v době kompilace)neznámé velikosti. Při navrhování rozhraní rozhraní jsem se proto snažil tyto nedostatkyeliminovat a umožnit ukládání jakýchkoliv dat o dynamické velikosti a zanořování objektůdo sebe.

Výsledkem je třída BinaryData, pomocí které předáváme data mezi serializovanou tří-dou implementující Serializable a mezi souborem dat BinarySerialiedFile (viz obrázek 4.6).Pokud potřebujeme ukládat data o dynamické velikosti, naalokujeme instanci BinaryDatadostatečně velikou a třída je sama přiloží za konec standardní délky objektu. Při deseria-lizaci je postupně vytahujeme. Data s dynamickou velikostí mohou být například textovéřetězce, obrázky nebo například jiná už serializovaná BinaryData. To nám umožní pomyslnězanořovat objekty do sebe.

Ve Výpisu 3 nalezneme ukázku serializace třídy LevelObject s využitím LevelObject-Data, které dědí od třídy BinaryData a přenáší data mezi serializovaným blokem dat (např.souborem na disku) a jejich majitelem (instance třídy LevelObject).

Výpis 3

1 # pragma BINARY_DATA_START2 struct LevelObjectData : public PhysicsObjectData3 {4 // definice vsech dat o predem zname velikosti5 bool boundingBoxVisible ;67 LevelObjectData ( unsigned int length = sizeof ( LevelObjectData ) ,8 unsigned int dataStart = sizeof ( LevelObjectData ) )9 : PhysicsObjectData ( length , dataStart )

10 {11 }

Page 46: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

34 KAPITOLA 5. POPIS IMPLEMENTACE

12 } ;13 # pragma BINARY_DATA_END141516 void LevelObject : : serialize ( RD : : BinaryData ∗ d ) const17 {18 // ulozeni dat rodicovske tridy19 this−>PhysicsObject : : serialize ( d ) ;2021 LevelObjectData ∗ data = ( LevelObjectData ∗) ( d ) ;2223 // ulozeni dat o predem zname velikosti24 data−>boundingBoxVisible = getShowBoundingBox ( ) ;2526 // ulození dat o dynamicke velikosti27 data−>addData ( objectID . c_str ( ) , objectID . length ( ) ) ;2829 // ukoncení bloku dat teto tridy (mohou nasledovat data dcerine tridy)30 data−>endDataTier ( ) ;31 }3233 void LevelObject : : deserialize ( RD : : BinaryData ∗ d )34 {35 // nacteni dat rodicovske tridy36 this−>PhysicsObject : : deserialize ( data ) ;3738 LevelObjectData ∗ data = ( LevelObjectData ∗) ( d ) ;3940 // nacteni dat o predem zname velikosti41 setShowBoundingBox ( data−>boundingBoxVisible ) ;4243 if ( data−>hasNextData ( ) )44 {45 // nacteni dat o dynamicke velikosti46 unsigned int length = 0 ;47 const char ∗ id = data−>getNextData ( length ) ;48 setObjectID ( std : : string ( id , length ) ) ;49 }5051 // presun na dalsi blok dat (mohou nasledovat data dcerine tridy)52 data−>nextDataTier ( ) ;53 }

S binární serializací se pojí několik záludností. Zaprvé nesmíme ukládat ukazatele na jinéobjekty. Tento problém by bylo velice těžké obejít (třída by například musela poskytovatnějaké rozhraní pro mapování objektů), ale protože jsem se v celé aplikaci obešel bez uklá-dání pointerů, nerozebíral jsem dále tento problém a ukládání ukazatelů tak BinaryDatanepodporuje.

Zadruhé by ukládaná třída neměla mít žádné virtuální metody, protože ukazatel navirtuální tabulku by po deserializaci s největší pravděpodobností měl nesmyslnou hodnotu.BinaryData tento problém řeší tak, že ukládá a načítá data až od části s reálnými daty a

Page 47: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.7. FYZIKA BULLET 35

pointeru na virtuální tabulku si nevšímá.Zatřetí může nastat problém při přenosu dat mezi různými platformami (stačí i použít

jiný kompilátor). Problémem je, že každý kompilátor si optimalizuje reálné velikosti tříd aukládá do nich výplňová data (kvůli zarovnání a související optimalizaci). Toto chování se dápotlačit pragma direktivou – proto musí být definice dceřiných tříd od BinaryData obalenadirektivami #pragma BINARY_DATA_START a #pragma BINARY_DATA_END.

Začtvrté je s různými platformami problém jejich odlišného ukládání dat – Big a LittleEndian. V současnosti BinaryData tento problém nijak neřeší, data budou validní pouze nastroji s architekturou, pro kterou byl kód zkompilován. Pokud by do budoucna vyvstal poža-davek používat uložená data na obou platformách zároveň, musela by se do třídy BinaryDatapřidat podpora pro automatické převedení data mezi těmito systémy ukládání.

Zapáté může každý kompilátor používat jinou velikost vestavených datových typů –většinou záleží pro jakou platformu je kód kompilován (x86, x64 atd.). Doporučuji u všechskalárních datových typů používat tzv. bit field, kterým kompilátoru řekneme, jakou majímít data velikost. Bit field nefunguje pro float/double/long double, které by ale měly mítstejnou délku i reprezentaci všude tam, kde je dodrženo standardu IEEE 754. Při serializaciméně obvyklých datových typů (například wchar_t) musíme být obezřetní a zjistit si, jakjsou kompilátorem reprezentovány.

5.7 Fyzika Bullet

Implementaci fyziky Bullet nemá cenu moc popisovat – engine využívá standardní roz-hraní knihovny a nepřidává moc funkčnosti navíc. Veškeré fyzikální nastavení je uloženov objektu RD::PhysicsObject, od kterého dědí všechny herní objekty levelu. MezivrstvaRD::PhysicsSystem si vytáhne tyto informace a vytvoří podle nich příslušné objekty Bulletupro popis tzv. rigid body (simulace reálného chování tuhých těles). Fyzikální knihovna setaké používá pro přesné vyhledávání objektů v prostoru.

Do budoucna by mohlo být výhodné přesunout počítání fyziky na vlastní vlákno a využítv Bulletu vestavěné podpory výpočetní síly grafických akcelerátorů. Dále by bylo užitečnélépe začlenit skriptovatelnost přímo rigid body objektů a událostí při jejich kolizích.

5.8 Umělá inteligence

Základem umělé inteligence implementované v enginu jsou tzv. agenti (RD::Agent). Svéhoagenta může mít každý actor (RD::Actor, RD::Character). Všichni agenti mohou být zave-deni do správce umělé inteligence (RD::AISystem), který se postará o jejich automatickouaktualizaci v každém kroku hry. Pokud má Character přiřazeného agenta, postará se sám ojeho zavedení do správce.

Agent má definované stavy (RD::AgentState), ve kterých se může nacházet, a cíle (RD::AgentGoal),kterých se snaží dosáhnout. Každý cíl se může skládat z několika dalších podcílů a ty zase zdalších podcílů a tak dále. Cíle i stavy mají většinu metod virtuálních a podporují callbackyze skriptů (viz kapitola 5.9.3), takže můžeme snadno definovat a upravit jejich chování – uobou jde zejména o metody activated, deactivated a step.

Page 48: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

36 KAPITOLA 5. POPIS IMPLEMENTACE

Cíle mohou být velice jednoduché, nebo naopak velice komplexní. Také můžeme z jedno-duchých cílů poskládat jeden komplexní. Příklady možných cílů: dojít na nějaké místo, najítnepřítele (tedy hráče), vystřelit na nepřítele a podobně. Cíle se nemusejí použít jen k vy-tvoření iluze umělé inteligence, ale třeba i k obyčejnému naskriptování nějaké posloupnostiakcí – využití tak najdou při vytváření cutscén.

Při implementaci umělé inteligence jsem čerpal z knih Programming Game AI by Example[11]a Game Coding Complete[14].

5.8.1 Vyhledávání cesty v prostoru, A* algoritmus

Velice důležitou součástí reálně se tvářící umělé inteligence je, aby se dokázala orientovat apohybovat v prostoru. Vyhledávání a sledování optimální cesty v prostoru je v našem případěvelice zkomplikováno zaměřením enginu na plošinové hry a využitím fyzikální simulace.Pokud by například byl engine zaměřen na 2D strategické hry, nemusel by při hledánícesty brát v úvahu gravitaci nebo způsob pohybu postaviček. V tomto případě se všakmusí vypořádat s tím, že postavička (pokud má věrně simulovat pohyb člověka) může nejenchodit, ale i skákat a padat, a že se nemusí umět dostat na všechny bodu prostoru (nedoskočítak daleko, nepřejde příliš velikou překážku, nevyjde příliš příkrý svah a podobně).

Aby mohla umělá inteligence efektivně hledat cestu v prostoru, potřebuje ho rozdělitna menší úseky a ty propojit do grafu. U spousty typů her jde prostor dělit automaticky(například podle mřížky), kvůli výše zmíněným problémům by ale bylo dělení složité, protojsem zvolil manuální definici grafu s tím, že do budoucna se může automatické dělení do-implementovat. Editor umožňuje vytvářet tzv. cesty (RD::Route), po kterých může postavaputovat (viz obrázek C.1). Cesty se mohou libovolně větvit a jejich základ jde vygenero-vat z vytvořeného terénu (částečná náhrada za chybějící automatické dělení prostoru). Zaběhu hry se tak už cesty nevytvářejí, ale načítají hotové a převádějí na prostorový graf(RD::SpatialGraph), ve kterém umělá inteligence vyhledává cestu z bodu A do bodu B.

SpatialGraph se skládá z uzlů (RD::SpatialNode) pospojovaných hranami (RD::SpatialArc).Uzel má pozici v prostoru, toleranci (jak moc se od něj může postava vzdálit) a seznam hran,které z něj vedou. Hrany jsou obousměrné a obsahují odkaz přesně na 2 uzly. Hrana umož-ňuje spočítat svou délku a natočení (úhel), což se hodí pro zjištění, zda postavička hranudokáže přejít.

Správce umělé inteligence obsahuje všechny grafy popisující prostor levelu a poskytujerozhraní pro vyhledávání cesty - RD::PathFinder. Engine v současnosti obsahuje jedinouimplementaci a to je AStarPathFinder, která vyhledává cestu pomocí algoritmu A*.

A* je optimálně efektivní algoritmus pro hledání nejkratší cesty v prostoru stavějícína algoritmu Dijkstra a rozšiřující ho o heuristiky pro minimalizaci počtu hledání. Principalgoritmu je následující: Procházíme graf a zpracováváme jeho uzly pomocí prioritní fronty(prvky jsou seřazené podle hodnoty F, viz dále), na začátku fronta obsahuje jen startovníuzel. Postupně z fronty vytahujeme uzly. Pokud je vytažený uzel roven tomu cílovému, našlijsme cestu, v opačném případě zpracujeme všechny jeho sousedy. Pokud už byl sousedníuzel zpracován, přeskočíme ho. Pokud nebyl zpracován, spočítáme výhodnost vedení cestytímto uzlem – algoritmus počítá 3 hodnoty pro každý uzel:

• G (goal) – celková „cena“ dosavadní cesty z počátku do aktuálního uzlu

Page 49: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.8. UMĚLÁ INTELIGENCE 37

• H (heuristic) – odhadovaná „cena“ z aktuálního uzlu do cíle (to, jakým způsobem jetato hodnota odhadována, značně vlivní efektivnost algoritmu; engine ji počítá jakopřímou vzdálenost mezi oběma uzly)

• F (fitness) – odhadovaná „cena“ cesty z počátku do cíle přes aktuální uzel, tj. součetG + H

Pokud vychází uzel výhodněji než doposud nejvýhodnější cesta, řekneme, že cesta povedetímto uzlem a přidáme ho do fronty. Pokud skončí zpracovávání fronty a my jsme nenašlicestu, znamená to, že žádná taková neexistuje. K tomuto může dojít, pokud startovní uzela cílový uzel nejsou nijak propojeny. Celý algoritmus je ve Výpisu 4.

Výpis 4

1 ref<PathPlan> AStarPathFinder : : findPath ( ref<SpatialNode> from , ref<←↩SpatialNode> to )

2 {3 frontAdd ( createNode ( from , to , NULL ) ) ; // zaciname pocatecnim uzlem45 while ( ! frontEmpty ( ) )6 {7 Node∗ node = frontPop ( ) ; // AStarPathFinder::Node obaluje SpatialNode8 node−>close ( ) ; // oznacime jako zpracovany9

10 if ( node−>getSpatialNode ( ) == to )11 {12 return buildPlan ( node ) ; // mame cestu13 }1415 SpatialNodeList neighbors ;16 node−>getSpatialNode ( )−>appendNeighbors ( neighbors ) ;1718 for ( SpatialNodeList : : iterator it = neighbors . begin ( ) ; it != ←↩

neighbors . end ( ) ; it++)19 {20 Node∗ neighbor = translate (∗ it ) ;2122 if ( neighbor == NULL )23 {24 frontAdd ( createNode (∗ it , to , node ) ) ; // novy uzel - nejvyhodnjsi cesta25 }26 else if ( neighbor−>isClosed ( ) )27 {28 continue ; // jiz zpracovany uzel29 }30 else if ( neighbor−>getGoal ( ) >= node−>getGoal ( ) + node−>←↩

getCostToNeighbor ( neighbor ) )31 {32 neighbor−>setPrevious ( node ) ; // vyhodnejsi nez soucasna cesta33 frontAdd ( neighbor ) ;

Page 50: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

38 KAPITOLA 5. POPIS IMPLEMENTACE

34 }35 }36 }3738 return NULL ; // zadna cesta neexistuje39 }

5.9 Skriptování a jazyk Lua

API pro napojení Lua skriptů do aplikace je kompletně v jazyku C, což znamená, že najednu stranu by mělo fungovat na všech platformách, na druhou stranu však přináší určitékomplikace. Naštěstí je API dobře zdokumentované, při vývoji jsem čerpal z oficiálníchdokumentů a volně dostupných knih od autorů jazyka[12][15]. Všechny funkce a datovéstruktury z Lua API začínají „lua_“. Třídy pro práci s tímto API jsem umístil do namespace„RD::Scripting::Lua“.

Reprezentace virtuální stroje se nazývá lua_State, pro snazší práci s ním má enginetřídu Lua::State. Laždý state běží samostatně a nezávisle na ostatních. Engine vytváří jedenhlavní a jeden pro level a herní logiku (ten je při každém načtení levelu restartován). Statymezi sebou nesdílí žádná data, mají jiné sady globálních proměnných, engine do nich aleautomaticky zaregistruje stejné definice obalených tříd a pomocných funkcí – většina herníchobjektů se tak dá ovládat a vytvářet přímo ze skriptů. State umožňuje spouštět Lua skriptyuložené v souborech – skript je tak vázán na konkrétní state.

Třída Lua::LuaManager inicializuje prostředí Lua a vytváří staty. Umožňuje jejich vy-tváření, mazání, ale i restartování. Automaticky do nich zanáší zmíněné definice tříd a funkcía řeší správu chyb a výjimek, které mohou nastat při práci se skriptem – ať už jde o chybnousyntaxi (compile-time error) nebo o chyby během vykonávání skriptu (run-time error). Proladění run-time chyb obsahuje debugger – pokud je debugger povolen, předá se zpracováníchyby jemu, v opačném případě vyhodí výjimku RuntimeException.

5.9.1 Správa zásobníku

Filosofií luovského API je přenášet veškerá data z aplikace do statů (a naopak) přes pomyslnýzásobník. Pokud chceme například do lua_State přidat globální proměnou, uložíme ji navrchol zásobníku – od té chvíle leží na zásobníku pod indexem -1 (stack top). Dále nazásobník vložíme ve formě řetězce klíč, pod kterým bude tabulka uložena – název proměnné.Tím se index tabulky na zásobníku změnil na -2 (jednu pozici pod vrcholem zásobníku), klíčmá index -1. No a konečně statu řekneme, ať položku zásobníku s indexem -2 uloží doglobálních proměnných pod klíčem, který najde na indexu -1.

Je jasné, že taková práce s indexy je mírně komplikovaná a hlavně náchylná k programá-torským chybám – stačí malá chyba při počítání indexů během psaní kódu a je zle. Protojsem se snažil vytvořit nadstavbu nad standardním API, která by správu indexů a vůbeccelého zásobníku řešila sama. Nadstavba se používá v celé aplikaci a automatizuje práci sezásobníkem, což vedlo k výraznému omezení počtu chyb a zjednodušení manipulace se staty.Stále je však dobré pro použití této nadstavby chápat, jak zásobník a indexy fungují.

Page 51: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.9. SKRIPTOVÁNÍ A JAZYK LUA 39

Třída Lua::State řeší vytváření obalů zásobníku Lua::StateStack – obalů může být více,protože Lua otevírá nový zásobník pro každé volání funkce. Neexistuje žádný jeden globálnízásobník – vždy je závislý na tom, co zrovna lua_State provádí. Lua::StateStack v kombinacise Lua::StackString, Lua::StackInteger a dalšími třídami automaticky spravuje indexy avelice usnadňuje používání zásobníku.

5.9.2 Boxing objectů

Používání objektů a tříd a volání metod z C++ v jazyku Lua není až tak triviální. Vrámci rešerše jsem hledal podobná řešení a většinou šlo jen o používání statických C funkcí,málokdy o použití objektů, metod a tříd, včetně podpory dědičnosti. Existují sice hotovéknihovny, které toto řeší, žádná se mi ale nezamlouvala. Proto mi zabralo spoustu časuvymyslet vhodné rozhraní pro používání objektů enginu ve skriptech. Tato část aplikacese postupem času hodně vyvíjela podle potřeb a s prapůvodním návrhem vytýčeným napočátku vývoje nemá mnoho společného. Pro třídy, které chceme použít i ve skriptechmusíme vytvořit další obalové třídy (wrapper) podobně jako jsme to dělali pro použití třídv jazyce C# (viz kapitola 5.10).

Lua nezná objekty, ale tabulky ukládající data pod textovými klíči. Pokud chceme veskriptu používat něco ve stylu objektů a metod, vytvoříme tabulku, do které uložíme uka-zatel na objekt a nastavíme jí jako metatable tabulku obsahující ukazatele na C++ funkce.Metatable je v tomto případě něco ve smyslu definice třídy – pokud se z původní tabulkypředstavující objekt snažíme získat prvek pod nějakým neznámým klíčem, dotáže se Lua natento prvek metatable. Metatable navrátí funkci (pokud existuje), která (pokud ji správnězavoláme) automaticky obdrží jako první parametr původní tabulku. Ve funkci musíme ztabulky získat ukazatel na objekt, převést parametry metody do C++ dat a zavolat přísluš-nou metodu objektu. Ve skutečnosti je okolo ještě spousta další práce – musíme spravovatzásobník, hlídat správnost předaných argumentů, ošetřovat možné výjimky volané metodya podobně.

Vytvořil jsem rozhraní, pomocí kterého snadno vytvoříme definice obalených metod atříd (včetně podpory dědičnosti). Dále jsem vytvořil sadu maker, které velice usnadňujízískávání ukazatelů na obalené objekty, převod dat, zachytávání výjimek a podobně. Díkytomu je obalování metod a funkcí docela jednoduché. Ukázku obalení jednoduché metodynalezneme ve Výpisu 5 a to, jak by kód vypadal po rozbalení maker ve Výpisu 7. Ukázkaobalení mírně komplexnější metody je pak ve Výpisu 8.

Výpis 5

1 // priklad volani teto funkce ve skriptu:2 // local bullet = controller:shoot(x = 10, y = 0, z = 0);3 int Lua_ActorController : : shoot ( lua_State ∗ l )4 {5 // (I) nastaveni poctu parametru6 RD_LUA_ARGS (1 ) ;78 // (II) typ volani a nazev tridy

Page 52: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

40 KAPITOLA 5. POPIS IMPLEMENTACE

9 RD_LUA_THISCALL ( ActorController ) ;1011 // (III) prevod parametru12 RD_LUA_ARG_VECTOR3 ( target ) ;1314 // (IV) zavolani obalene metody/funkce15 ref<Bullet> bullet = __this−>shoot ( target ) ;1617 // (V) navratova hodnota18 RD_LUA_RETURN_OBJECT ( bullet ) ;1920 // (VI) signalizuje ukoncení volani funkce21 RD_LUA_END ( ) ;22 }

Nejprve nastavíme počet parametrů volané funkce (I). Lua podporuje volání funkcí svariabilním počtem paramterů, což ale pro vytváření wrapperu není vhodné, protože obalujeklasické s C++ funkce a metody s pevným počtem parametrů. Pokud počet parametrůnesouhlasí, wrapper vyhodí chybu. Dalším důvodem, proč hlídáme počet parametrů, jezískávání tabulky obaleného objektu a hlídání způsobu volání funkce. Lua umožňuje dvazpůsoby volání funkcí – buď pomocí tečky, což odpovídá volání statické funkce, nebo pomocídvojtečky, což se podobá volání metody – Lua při takovém volání automaticky nastaví jakoprvní parametr tabulku, ze které funkci voláme. Ve skriptech je k této tabulce přístup podjménem „self“ (obdoba klasického „this“), přes Lua API ji najdeme naspodu zásobníku (Luaargumenty funkce na zásobník vkládá zleva).

Různými způsoby volání se dostáváme k nastavení typu funkce a jménu třídy (II). Jednáse o makra:

• RD_LUA_STDCALL – značí volání pomocí tečky, tedy statickou funkci

• RD_LUA_THISCALL – značí volání pomocí dvojtečky, tedy metodu (makro získá„__this“ukazatel na obalený objekt a „__table“ pro manipulaci s tabulkou)

• RD_LUA_NEW – značí volání pomocí tečky, je obdobou konstruktoru (makro vytvořítabulku pro nový objekt)

Dále nastavíme typy parametrů a převedeme je do C++ dat (III). Parametry bychomměli získávat v pořadí, v jakém je u funkce očekáváme zleva. Převod usnadňují makra:

• RD_LUA_ARG_INTEGER,RD_LUA_ARG_DOUBLE,RD_LUA_ARG_BOOLEAN,RD_LUA_ARG_STRING,RD_LUA_ARG_TABLE - podle názvů je jasné, jaké parametry makra obstarávají

• RD_LUA_ARG_OBJECT – značí, že je parametrem obalený objekt – makro získáukazatel na tento objekt (makro má druhý parametr, který udává jakého typu objektje)

Page 53: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.9. SKRIPTOVÁNÍ A JAZYK LUA 41

• RD_LUA_ARG_REF – podobné jako RD_LUA_ARG_OBJECT, jen pracuje refe-rencemi (ne ukazateli)

• RD_LUA_ARG_QUATERNION,RD_LUA_ARG_VECTOR2,RD_LUA_ARG_VECTOR3 – převádějí data vektorů a quaternionů

Máme převedené parametry, takže zavoláme samotnou funkci, metodu, kontruktor apodobně (IV). Konečně nastavíme návratovou hodnotu (V), wrapper pro to nabízí makrapodobně jako u parametrů:

• RD_LUA_RETURN_INTEGER,RD_LUA_RETURN_DOUBLE,RD_LUA_RETURN_BOOLEAN,RD_LUA_RETURN_STRING,RD_LUA_RETURN_TABLE,RD_LUA_RETURN_QUATERNION,RD_LUA_RETURN_VECTOR2,RD_LUA_RETURN_VECTOR3– mají dostatečně výmluvné názvy, jediným parametrem je vždy hodnota danéhotypu

• RD_LUA_RETURN_OBJECT vrací obalený objekt, jediným parametrem je uka-zatel nebo referenci (v tomto případě se nerozlišuje chování), pokud je ukazatel neboreference nulová, vrací hodnotu nil

• RD_LUA_RETURN_NIL vrací hodnotu nil (obdoba null v C# nebo NULL v C++)

• RD_LUA_RETURN_ERR vrátí chybovou hodnotu (v současné době nepodporujechybovou zprávu)

• RD_LUA_RETURN nevrací žádnou hodnotu (obdoba návratového typu void)

Na úplném konci (VI) musí být ještě makro RD_LUA_END, které ošetří a zpracujemožné výjimky, uzavře zásobník a ukončí volání funkce.

5.9.3 Eventy ve skriptech

Událostí můžeme ve skriptech používat dva druhy. První možností jsou globálně šířené, kdypoužijeme EventManager podobně jako v klasickém kódu:

EventManager.startReceiving(Level.StartedEvent, myLevelCallback);

EventManager pak při distribuci eventu Level::StartedEvent volá funkci onLevel_Startedtabulky myLevelCallback.

Druhým typem eventů jsou tzv. callbacky. Každý objekt, který může být obalen doskriptu, musí dědit od třídy Scriptable, takže obsahuje metody getCallback a setCallback

Page 54: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

42 KAPITOLA 5. POPIS IMPLEMENTACE

(souhrnně property Callback). Ve skriptu nastavíme jako callback nějakou tabulku, u kterébude daný objekt enginu hledat funkce související s jeho funkčností. Pokud callback tabulkaobsahuje hledanou funkci, nahrazuje tím defaultní chování objektu – to je podstatný roz-díl oproti globálně šířeným událostem, které jen mohli stanovit reakci na nějakou událost.Callbacky můžeme přímo upravit chování enginu. Zavedení callbacku je velice jednoduché:

myGameState.Controller.Callback = myGameController;

Callbacky najdou největší využití při skriptování herní logiky, reakcí na uživatelskývstup, umožňují definování pravidel umělé inteligence.

5.9.4 Debugger a krokování v editoru

Obrázek 5.1: Editor obsahuje debugger pro krokování kódu

Lua samotná nic jako debugger nenabízí, její API jen dovoluje při většině situací vo-lat callback funkci (v terminologii jazyku Lua se nazývají hooks), čehož debugger využívá.Debugger umožňuje nastavit skriptům breakpointy, které pozastaví vykonávání kódu a pře-dají řízení debuggeru. Debugger můžeme ovládat buď z kódu, nebo v editoru. Na obrázku5.1 vidíme editor s pozastaveným skriptem. V horní liště se nachází tlačítka pro ovládání

Page 55: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

5.10. MEZIVRSTVA C++/CLI 43

debuggeru (umožnují pozastavený kód krokovat, pouštět nebo úplně zastavit), dále vidímekód skriptu včetně nastaveného breakpointu a ve spodní části výpis lokálních a globálníchproměnných. Během pozastavení můžeme procházet i zásobník volání – výpis lokálních pro-měnných je vždy poplatný vybranému zanoření.

5.9.5 Ukázka skriptování

Skriptování nabízí ještě další věci, které jsem dosud moc nezmiňoval. Wrapper umožňujepřístup k datům obaleného objektu pomocí skrytého volání getrů a setrů, tak jak to známez jazyka C# (tzv. properties). Dále si například obalené objekty ukládají uživatelská dataze skriptů. Tato data jsou nepřenosná mezi Lua staty. Ukázku skriptů pro zpracování uži-vatelského vstupu a nastavení pravidel umělé inteligence najdeme ve Výpisu 9.

5.10 Mezivrstva C++/CLI

Veškeré třídy enginu jsou psány v jazyce C++ a řadí se tedy mezi unmanaged kód – výslednýprogram běží nativně a bez garbage collectoru. Aby bylo možné používat unmanaged třídy vmanaged jazyku (C#), bylo nutné vytvořit tzv. wrapper. Zvolil jsem řešení vytvořit wrapperv jazyce C++/CLI, což je jazyk platformy .NET, který umožňuje míchat C++ a C++/CLIkód – v rámci platformy .NET se tento přístup nazývá IJW (It Just Works). Výsledek sezkompiluje do DLL knihovny, která se dá načíst a použít v C# projektu.

Wrapper je obalení původních unmanaged tříd novými managed třídami. Veškeré třídywrapperu jsou součástí namespace RD_NET (pro odlišení od původního namespace RD).Wrapper tedy musí řešit převod objektů jedné platformy do druhé (tomuto procesu se říkáMarshalling) a dále by měl zachovávat původní hierarchii tříd a umožňovat tak přetypovávánístejně jako v originálních třídách.

Pro sjednocení rozhraní wrapperu jsem vytvořil 2 základní třídy RD_NET::PtrObject aRD_NET::RefObject, od kterých dědí všechny ostatní obalové třídy. PtrObject se používápro ukládání přímých ukazatelů na instance objektů enginu a RefObject pro ukládání refe-rencí (tedy instancí těch tříd, které dědí od RD::Referenceable). Tím se přenáší referencecounting i do editorové části (detaily o počítání referencí naleznete v kapitole 5.1). Obě třídy(PtrObject i RefObject) mají template metodu GetPtr, kterou získáme příslušný ukazatel(nebo referenci). Ukázka implementace obalení jedné metody v jazyce C++/CLI je včetněvysvětlení ve Výpisu 6.

Výpis 6

1 // trida RD_NET::LevelObject je potomkem tridy RD_NET::RefObject2 void RD_NET : : LevelObject : : AddedToLevel ( RD_NET : : Level^ level )3 {4 this−>GetPtr<RD : : LevelObject >() // ziskani reference ref<RD::LevelObject>5 −>addedToLevel ( // zavolani unmanaged metody6 level−>GetPtr<RD : : Level>() // predani parameteru7 ) ;8 }

Page 56: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

44 KAPITOLA 5. POPIS IMPLEMENTACE

Marshalování vestavěných datových typů (int, char atd.) si řeší platforma .NET sama.Marshalování stringů a kolekcí musíme řešit sami – wrapper pro většinu těchto situací obsa-huje statické funkce třídy RD_NET::Marshal. Wrapper dále obaluje i události a umožňujetak jejich odebírání v jazyce C#. Také využívá tzv. properties (automatického volání setrůa getrů) pro zachování konvencí jazyka C#.

5.11 Komunikace Engine / Editor

Editor obstarává herní smyčku enginu sám – má pro to rozhraní RDEditor.GameLoop,konkrétně implementace: nevláknovou SynchronizedGameLoop a ThreadedGameLoop běžícína vlastním vlákně. Nevláknová se používá pro editační mód editoru, vláknová pro testovacírežim, kdy je spuštěna hra přímo v editoru.

GameLoop obsahuje metody pro přenášení zpráv mezi editorem a enginem. Každá zprávaimplementuje rozhraní RDEditor.Message. Příklady zpráv mohou být StopEditMode, Start-GameMode, NeedUpdate, DoOperation, UndoOperation a podobně. Poslední dvě jmenovanévykonávají RDEditor.EditorOperation, což už jsou konkrétní operace s herními objekty –úprava pozice objektu, velikosti, rotace a podobně.

Operace se dají přirovnat k úlohám (taskům), jen s tím rozdílem, že podporují Undo– navrácení do původního stavu. Díky tomuto přístupu je celý editor zaprvé jednodušerozšiřitelný, zadruhé si sám řeší, kdy se operace vykonají (což je důležité kvůli podpoře vícevláken) a zatřetí dovoluje ukládat historii operací a jejich vracení zpět (pokud to operacepodporuje).

Page 57: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Kapitola 6

Závěr

V celé práci jsem se snažil využívat moderních postupů jako je vícevláknové, task-based,eventy řízené a daty řízené programování. Aplikace je navržena jako maximálně rozšiřitelná.

Implementace jádra zabrala obrovskou spoustu času, přesto (jak už to u softwarovýchprojektů bývá) není stoprocentně hotová a doladěná. Funguje však většina stanovenýchpožadavků, jádro je schopné pohánět jednoduché plošinové hry, obsahuje reálně vypadajícífyzikální simulaci, umožnuje vykreslování i náročnějších grafických efektů a díky návrhu apodpoře pro skriptování je snadno rozšiřitelné.

Editor splňuje zpočátku obtížně splnitelně vyhlížející požadavky a představuje tak funkčníprototyp a základ, který by mohl být dále vyvíjen a vylepšován. Editor nabízí možnost pří-mého spuštění, ladění a debuggování hry – v těchto funkcích může být směle srovnáván skomerčními editory a vývojovými nástroji. Na druhou stranu možnosti editace levelu nejsounikterak rozsáhlé, funguje základní manipulace s objekty, úprava herního terénu, genero-vání a modifikace cest umělé inteligence, nastavování fyzikálních vlastností objektů nebopřehrávání cutscén. Editace skriptů probíhá v zabudovaném textovém editoru využívajícíkomponentu s podporou obarvování syntaxe.

Pro budoucí rozvoj aplikace by bylo dobré více rozdělit a zapouzdřit operace enginudo tasků, které by mohly být pro lepší rozložení zátěže zpracovávány paralelně. Dále bybylo dobré rozšířit možnosti editoru, přidat podporu skriptovatelného HUDu, přidat vícemožností umělé inteligence a podobně. V současné době existuje velice málo podobnýchnekomerčních knihoven a aplikací, proto pevně doufám a věřím, že vývoj aplikace neustanea ať už já nebo někdo jiný v něm bude nadále pokračovat.

45

Page 58: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

46 KAPITOLA 6. ZÁVĚR

Page 59: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Literatura

[1] 72% of US population are gamers, .http://www.mcvuk.com/news/30071/72-of-US-population-play-games,stav ze 19. 5. 2011.

[2] Time spent gaming on the rise – NPD, .http://www.gamespot.com/news/6264092.html, stav ze 4. 5. 2009.

[3] 2010 Total consumer spend on all games content int The U.S. estimated between $15.4to $15.6 billion, .http://www.npd.com/press/releases/press_110113.html, stav ze19. 5. 2011.

[4] Video games bigger than film, .http://www.telegraph.co.uk/technology/video-games/6852383/Video-games-bigger-than-film.html, stav ze 19. 5. 2011.

[5] Češi a Slováci utratili loni za videohry přes dvě miliardy korun, .http://www.herniasociace.cz/2011/cesi-a-slovaci-utratili-loni-za-videohry-pres-dve-miliardy-korun/], stav ze 19. 5. 2011.

[6] BAFTA Video Games Awards, .http://www.bafta.org/awards/video-games/, stav ze 19. 5. 2011.

[7] Inappropriate Content: A Brief History of Videogame Ratings and the ESRB, .http://www.escapistmagazine.com/articles/view/columns/the-needles/1300-Inappropriate-Content-A-Brief-History-of-Videogame-Ratings-and-the-ESRB, stav ze 19. 5. 2011.

[8] AHP vstoupila do mezinárodní organizace ISFE, .http://www.herniasociace.cz/2010/ahp-vstoupila-do-mezinarodni-organizace-isfe/, stav ze 19. 5. 2011.

[9] Sony Licenses Unreal Engine 3 For PS3, .http://www.digitalbattle.com/2006/07/21/sony-licenses-unreal-engine-3-for-ps3/, stav ze 19. 5. 2011.

[10] AHP. Jak vypadá typická hra?http://www.herniasociace.cz/hlavni-stranka/videohry-v-kostce/jak-vypada-typicka-hra/, stav ze 19. 5. 2011.

47

Page 60: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

48 LITERATURA

[11] BUCKLAND, M. Programming Game AI by Example. Wordware Publishing, Inc.,2004. In English.

[12] IERUSALIMSCHY, R. Programming in Lua. Lua.org, 1st edition, 2003. In English.

[13] IGDA. Study of Games And Development.www.igda.org/wiki/images/e/ee/Igda2008cf.pdf, stav ze 19. 5. 2011.

[14] MCSHAFFRY, M. Game Coding Complete. Charles River Media, 3rd edition, 2009.In English.

[15] R. IERUSALIMSCHY, W. C. L. H. d. F. Lua 5.1 Reference Manual. Lua.org, 2006.In English.

Page 61: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Příloha A

Výpisy kódu

Výpis 7

1 // jak by vypadala funkce Lua_ActorController::shoot po rozbaleni vsech maker2 int Lua_ActorController : : shoot ( lua_State ∗ l )3 {4 // (I) RD_LUA_ARGS(1);5 int __args = 1 ;6 int __argIndex = 1 ;7 int __return = 1 ;89 // (II) RD_LUA_THISCALL(ActorController);

10 const char ∗ __className = " ActorController " ;11 Lua : : State L ( l ) ;12 L . openStack ( ) ;1314 try15 {16 Lua : : StackTable __table = __getClassTable ( L , __args , __className , ←↩

__FILE__ , __LINE__ ) ;1718 ActorController ∗ __this = __getThis<ActorController>(L , __table , ←↩

__args , __className , __FILE__ , __LINE__ ) ;1920 // (III) RD_LUA_ARG_VECTOR3(target);21 Vector3 target = Lua_Vector3 : : fromTable ( L , __getTableArg ( L , ←↩

__argIndex++, __args , false , __className , __FILE__ , __LINE__ ) ) ;2223 // (IV) toto zustava stejne24 ref<Bullet> bullet = __this−>shoot ( target ) ;2526 // (V) RD_LUA_RETURN_OBJECT(bullet);27 if ( bullet == NULL )28 {29 L . getStack ( )−>pushNil ( ) ;30 }31 else

49

Page 62: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

50 PŘÍLOHA A. VÝPISY KÓDU

32 {33 bullet−>boxToScript ( L ) ;34 }35 L . closeStack ( ) ;36 return __return ;3738 // (VI) RD_LUA_END();39 }40 // zachyceni nekolika typu vyjimek, pro ukazku jen jedna41 catch ( RD : : Exception& e )42 {43 L . closeStack ( ) ;44 throw e ;45 }46 L . closeStack ( ) ;47 return __return ;48 }

Výpis 8

1 // ukazka komplexnejsi obalove funkce2 // local objects = character:look(direction, 50);3 int Lua_Actor : : look ( lua_State ∗ l )4 {5 RD_LUA_ARGS (2 ) ;6 RD_LUA_THISCALL ( Actor ) ;78 RD_LUA_ARG_QUATERNION ( angle ) ;9 RD_LUA_ARG_DOUBLE ( maxDistance ) ;

1011 ObjectList objects ;12 __this−>look ( angle , objects , ( float ) maxDistance ) ;1314 Lua : : StackTable value = L . getStack ( )−>createTable ( ) ;15 unsigned int i = 0 ;16 for ( ObjectList : : iterator it = objects . begin ( ) ; it != objects . end ( ) ; ←↩

it++)17 {18 value . setTable (19 Utils : : Parse : : uintToString ( i ) . c_str ( ) ,20 (∗ it )−>boxToScript ( L ) ,21 true22 ) ;23 i++;24 }2526 RD_LUA_RETURN_TABLE ( value ) ;27 RD_LUA_END ( ) ;28 }

Page 63: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

51

Výpis 9

1 -- ukazka Lua skriptu reagujiciho na uzivatelsky vstup2 local gameController = ScriptedStateController . new ( ) ;3 local gameState = State . new ( " GameState " ) ;4 gameController . Callback = gameController ;5 gameState . Controller = gameController ;67 SystemManager . StateManager : addState ( gameState ) ;8 SystemManager . StateManager : changeState ( " GameState " ) ;9

10 -- lua nema prikaz switch, vypomuzeme si tabulkou11 keyPressed = {} ;1213 function gameContro l ler : onKeyPressed ( e )14 local cb = keyPressed [ e . key ] ;15 if cb ~= nil then cb ( e ) end ;16 end1718 keyPressed [ KeyCode . Escape ] = endGame ;19 keyPressed [ KeyCode . Up ] = playerJump ;2021 function endGame ( )22 Game . Running = false ;23 end2425 function playerJump ( )26 level . Player . ActorControl : jump ( 1 . 0 ) ;27 end

Page 64: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

52 PŘÍLOHA A. VÝPISY KÓDU

Page 65: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Příloha B

UML diagramy

class Game

Game

«virtual»+ init() : bool+ run()+ isRunning() : bool+ update()+ stop()+ destroy()+ addListener(GameloopListener*)+ removeListener(GameloopListener*)

«Event»+ InitializedEvent()+ UpdatedEvent()+ DestroyedEvent()

«interface»

GameloopListener

«virtual»+ onInit(Game*)+ onUpdate(Game*, long)+ onDestroy(Game*)

Obrázek B.1: Třída Game

53

Page 66: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

54 PŘÍLOHA B. UML DIAGRAMY

class Graphics

«interface»

Graphics

«virtual»+ init()+ destroy()+ isInitialized() : bool+ startRendering()+ stopRendering()+ isRendering() : bool+ update()+ getTaskManager() : TaskManager*+ setTaskManager(TaskManager*)+ getTargetFps() : float+ setTargetFps(float)+ getActualFps() : float+ prepareSceneManager(SceneType, string)+ getSceneManager(string) : SceneManager*+ invalidateSceneManager(SceneManager*)+ addData(GraphicsData*, SceneManager*)+ removeData(GraphicsData*, SceneManager*)

«Event»+ RenderingStartedEvent()+ RenderingStoppedEvent()+ SceneManagerDestroyedEvent()+ SceneManagerReadyEvent()

«interface»

GraphicsData

«virtual»+ createData(Graphics*, SceneManager*)+ afterCreateData(Graphics*, SceneManager*)+ destroyData(Graphics*, SceneManager*)+ afterDestroyData(Graphics*, SceneManager*)+ synchronizeData(Graphics*, SceneManager*)+ afterSynchronizeData(Graphics*, SceneManager*)

«abstract»

GraphicsTask

«interface»

TaskManager::Task

«virtual»+ getName() : string+ isProcessed() : bool+ invalidate()+ process()

«interface»

Graphics::Listener

«virtual»+ onFrameStarted(Graphics*, float)+ onFrameEnded(Graphics*, float)

Obrázek B.2: Rozhraní Graphics

class TaskManager

«interface»

Task

+ getName() : string+ isProcessed() : bool+ invalidate()+ process()

«interface»

TaskManager::Listener

+ onTaskAdded(Task*)+ onTaskProcessed(Task*)+ onTaskAborted(Task*)+ onTaskScheduled(Task*)

«interface»

TaskManager

+ hasTask() : bool+ processOneTask()+ switchTaskQueue()+ abortTasks()+ addTask(Task*)+ addListener(TaskManager::Listener*)+ removeListener(TaskManager::Listener*)

Obrázek B.3: Struktura TaskManageru

Page 67: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

55

class LevelObject

LevelObject

+ isInLevel() : bool+ getParentLevel() : Level*+ getObjectID() : string+ setObjectID(string)

«virtual»+ addedToLevel(Level *)+ removedFromLevel()+ resetTransforms()+ showBoundingBox(bool)+ getShowBoundingBox() : bool+ getObjectType() : LevelObjectType# computeBounds()

Model

«virtual»+ getMeshName() : string+ setMeshName(string)+ getMesh() : Entity+ getAnimation(string) : Animation*+ startAnimation(Animation*, bool)+ stopAnimation(Animation*, bool)+ finishAnimation(Animation*, float)

Character

«virtual»+ getAnimationDie() : Animation*+ getAnimationShoot() : Animation*+ getAnimationJump() : Animation*+ getAnimationRun() : Animation*

PhysicsObject

«virtual»+ getPosition() : const Vector3&+ setPosition(Vector3&)+ getScale() : const Vector3&+ setScale(Vector3&)+ getOrientation() : const Quaternion&+ setOrientation()+ isInPhysics() : bool+ configPhysics(PhysicsSystem*)+ deconfigPhysics(PhysicsSystem*)+ getBoundingRadius() : float+ getBoundingBox() : AxisAlignedBox+ hasPhysicsControl() : bool+ removePhysicsControl()+ getPhysicsControl() : PhysicsController*+ setPhysicsControl(PhysicsController*)+ getMass() : float+ setMass(float)+ getFriction() : float+ setFriction(float)+ getMaxVerticalSpeed() : float+ setMaxVerticalSpeed(float)+ getMaxHorizontalSpeed() : float+ setMaxHorizontalSpeed(float)

«Event»+ OrientationChangedEvent()+ ScaleChangedEvent()+ PositionChangedEvent()+ ConfiguredEvent()+ DeconfiguredEvent()+ NeedDeconfigureEvent()+ NeedConfigureEvent()

«interface»

Actor

«virtual»+ hasActorControl() : bool+ getActorControl() : ActorController*+ setActorControl(ActorController*)+ getDirection() : Direction+ setDirection(Direction)+ getHealth() : float+ setHealth(float)+ getMaxHealth() : float+ setMaxHealth(float)+ heal(float)+ injure(float)+ kill()+ isAlive() : bool+ getTeam() : Team+ setTeam(Team)

«Event»+ DiedEvent()+ HealedEvent()+ InjuredEvent()

Trigger

+ activate()

«Event»+ ActivatedEvent()

Light

Obrázek B.4: Struktura základních LevelObjektů

Page 68: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

56 PŘÍLOHA B. UML DIAGRAMY

Page 69: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Příloha C

Obrázky

Obrázek C.1: Ukázka implementovaného editoru a jeho funkce pro úpravu cest umělé inte-ligence

57

Page 70: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

58 PŘÍLOHA C. OBRÁZKY

Page 71: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Příloha D

Instalační a uživatelská příručka

D.1 Spuštění hry

Cesta ke spustitelné hře je /compiled/bin/RainbowDemon.exe. Hra se ovládá kláves-nicí a myší.

Ovládání klávesnicí:

• Šipka nahoru – Skok

• Šipka vlevo – Chůze vlevo

• Šipka vpravo – Chůze vpravo

• Escape – Konec hry

• R – Restart levelu

Ovládání myší:

• Levé tlačítko – Vystřelení paprsku

• Pravé tlačítko – Držením se vytváří most

D.2 Spuštění editoru

Cesta ke spustitelnému editoru je /compiled/bin/RDEditor.exe. V editoru můžete na-čítat levely a skripty. Po načtení levelu můžete spustit hru tlačítkem v horní liště. Přehrávatcutscény můžete přes Level > Play Cutscene - jména cutscén jsou definována ve skrip-tech. V levé části je upravovat parametry levelu a vybraného objektu, včetně fyzikálníchvlastností atd.

Během editace skriptů můžete nastavovat breakpointy kliknutím nalevo od čísla řádku.Krokování aplikace probíhá přes tlačítka v horní liště.

59

Page 72: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

60 PŘÍLOHA D. INSTALAČNÍ A UŽIVATELSKÁ PŘÍRUČKA

Ovládání klávesnicí:

• Šipka nahoru/dolů – Posun kamery po ose Y

• Šipka vlevo/vpravo – Posun kamery po ose X

• Page Up/Page Down – Posun kamery po ose Z (zoomování)

• Tab – Pokud je zvolen objekt s podporou editace (terén, cesty), spustí se nástroj proeditaci objektu

• Q

– Při editaci cesty: Zvolení nástroje pro posun bodů– Při editaci terénu: Zvolení nástroje pro posun bodů

• W

– Při editaci cesty: Zvolení nástroje pro přidávání bodů

• C

– Při editaci cesty: Spojení vybraných bodů

• D

– Při editaci cesty: Rozpojení vybraných bodů

• Delete

– Při editaci cesty: Odstranění vybraných bodů– Při editaci terénu: Odstranění vybraných bodů

• E

– Při editaci terénu: Zvolení nástroje Extrude

• R

– Při editaci terénu: Zvolení nástroje Split

Ovládání myší:

• Levé tlačítko – Manipulace s vybraným objektem/nástrojem

• Pravé tlačítko – Vybrání level objektu/bodu terénu/atd.

• Kolečko myši – Rolováním se zoomuje, držením posouvá kamera

Page 73: Rozhraní pro tvorbu plo²inových herstm.fel.cvut.cz/files/stm_bp/stm_bp_karel_macalik.pdf · Technologie od společností Id Software nebo Unreal se díky své hardwarové ná-

Příloha E

Obsah přiloženého DVD

Přiložené DVD obsahuje tento text ve zdrojovém formátu LATEXa vysázený dokument PDF.Dále obsahuje zdrojové soubory implementované aplikace a některé knihovny potřebné kezkompilování. Součástí je i zkompilovaná spustitelná verze.

Adresářová struktura:

• /

– /compiled Zkompilovaná spustitelná verze∗ /bin Spustitelné EXE soubory∗ /media Herní data (skripty, textury, modely...)

– /libraries Externí knihovny pro kompilaci∗ /boost∗ /Bullet∗ /Lua∗ /OgreSDK

– /sources Zdrojové soubory aplikace∗ /RainbowDemon Zdrojové soubory editoru a herního jádra∗ /uml UML diagramy

– /text Text BP∗ /source Zdrojový formát BP

61


Recommended