VYSOKÁ ŠKOLA POLYTECHNICKÁ JIHLAVA Katedra elektrotechniky a informatiky Obor Aplikovaná informatika
S í ť o v á vý u ko v á h r a p s a n í n a kl á v e s ni c i bakalářská práce
Autor: Jan Shýbal Vedoucí práce: Ing. Marek Musil Jihlava 2014 1
ZADÁNÍ BAKALÁŘSKÉ PRÁCE Autor práce: Studijní program: Obor: Název práce: Cíl práce:
Jan Shýbal Elektrotechnika a informatika Aplikovaná informatika Síťová výuková hra psaní na klávesnici Hra spočívá v pohybu po šachovnici podle znaků (písmen) zadaných na klávesnici odpovídajících znakům na jednotlivých políčkách šachovnice. Z aktuální pozice na šachovnici se lze přesunout na takové bezprostředně sousední políčko, jehož písmeno odpovídá stisknutému písmenu na klávesnici. Hraje se po síti ve dvojici a cílem jednoho hráče je dostihnout jiného hráče. Vyhodnocuje se počet chybně stisknutých znaků, pro které nebylo možné provést posun po šachovnici a doba, za kterou hráč dostihl druhého hráče. Uživatel má možnost volit velikost šachovnice a možnost zapnout změnu písmen na políčkách, kterými se prošlo. Aplikace může být doplněna funkcí vyzvat čekajícího hráče ke hře a nápovědou, jakou cestou a co nejrychleji dosáhnout protivníka. Práce bude realizována v jazyce C++ jako formulářová aplikace s využitím OpenGL a frameworku Qt. V teoretické části se práce zaměří na popis OpenGL a Qt a na principy algoritmů využitých v praktické části a při programové realizaci. Praktická část se bude zabývat popisem funkčnosti hry a jejími pravidly, síťovou koncepcí hry, návrhem algoritmů s odůvodněním jejich výběru. Výsledkem bude programová realizace hry v C++.
Ing. Marek Musil vedoucí bakalářské práce
Ing. Bc. Michal Vopálenský, Ph.D. vedoucí katedry Katedra elektrotechniky a informatiky
2
Anotace Práce se zabývá vývojem síťové aplikace vhodné k výuce psaní na počítači. Hra umožňuje porovnání rychlosti psaní na počítači mezi dvěma hráči zábavnou formou. Teoretická část práce se věnuje stanovení požadavků, výběru technologií pro vývoj hry, především frameworku Qt a síťovému protokolu. Věnuje se způsobu návrhu aplikace. Praktická část demonstruje snadnost použití Open Graphics Library v rámci Qt a elegantní návrh grafického rozhraní pomocí jazyka Qt Modeling Language. Dále praktická část obsahuje informace o důležitých implementačních třídách a vybraných algoritmech užitých v klientské i serverové části.
Klíčová slova Qt, Qt Quick, QML, C++, OpenGL, server, klient, hra, síť, TCP, UDP
Abstract The bachelor's thesis concerns a development of a network application which is designed for learning of typing. The application has a form of a game and it enables a comparison of the typing speed of two players in an amusing way. The theoretical part of the thesis covers the setting of the requirements, selection of the technologies for the game's development, especially the Qt framework and the network protocol. The thesis deals with the way how the application is designed. The part describing the practical application shows the easiness with which the Open Graphics Library can be applied within Qt and the simple and efficient design of the graphical interface with the help of the Qt Modeling Language. Further, the part about practical application contains information about important implementation classes and selected algorithms applied in the client part and in the server part.
Key words Qt, Qt Quick, QML, C++, OpenGL, server, client, game, network, TCP, UDP
3
Prohlašuji, že předložená bakalářská práce je původní a zpracoval jsem ji samostatně. Prohlašuji, že citace použitých pramenů je úplná, že jsem v práci neporušil autorská práva (ve smyslu zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých zákonů, v platném znění, dále též „AZ“). Souhlasím s umístěním bakalářské práce v knihovně VŠPJ a s jejím užitím k výuce nebo k vlastní vnitřní potřebě VŠPJ . Byl jsem seznámen s tím, že na mou bakalářskou práci se plně vztahuje AZ, zejména § 60 (školní dílo). Beru na vědomí, že VŠPJ má právo na uzavření licenční smlouvy o užití mé bakalářské práce a prohlašuji, že s o u h l a s í m s případným užitím mé bakalářské práce (prodej, zapůjčení apod.). Jsem si vědom toho, že užít své bakalářské práce či poskytnout licenci k jejímu využití mohu jen se souhlasem VŠPJ, která má právo ode mne požadovat přiměřený příspěvek na úhradu nákladů, vynaložených vysokou školou na vytvoření díla (až do jejich skutečné výše), z výdělku dosaženého v souvislosti s užitím díla či poskytnutím licence. V Jihlavě dne ................................................... Podpis
4
Poděkování Na tomto místě bych rád poděkoval svému vedoucímu práce Ing. Marku Musilovi za cenné připomínky, podněty, rady a možnost tvořit pod jeho vedením. Dále děkuji své matce za příkladnou stravovací péči během vývoje praktické aplikace a jazykovou korekturu. Sestře děkuji za pomoc s překladem anotace do anglického jazyka. Za pomoc s jazykovou korekturou také děkuji Petrovi Hruškovi.
5
Obsah 1
Úvod .................................................................................. 8
2
Analýza ............................................................................ 10 2.1
Požadavky..................................................................... 10
2.1.1
Funkční .....................................................................................10
2.1.2
Nefunkční ..................................................................................11
2.2
Volba technologií............................................................ 12
2.2.1
Programovací jazyky...................................................................12
2.2.2
Qt framework ............................................................................16
2.2.3
OpenGL.....................................................................................17
2.2.4
Další technologie ........................................................................18
2.3
Způsob vývoje ............................................................... 19
2.3.1
2.4 3
Existující řešení.............................................................. 20
Návrh řešení .................................................................... 22 3.1
Model případů užití ......................................................... 22
3.2
Architektura aplikace ...................................................... 24
3.3
Síťový protokol .............................................................. 25
3.3.1
TCP vs. UDP ..............................................................................25
3.3.2
Vlastní protokol ..........................................................................26
3.3.3
Návrh vlastního síťového protokolu ...............................................28
3.4 4
Unifikovaný proces vývoje aplikací................................................19
Model návrhových tříd .................................................... 34
Implementace ................................................................. 35 4.1
Server .......................................................................... 36
4.1.1
Queue Keeper — správce fronty ...................................................36
4.1.2
Game — herní server ..................................................................37
4.2
Klient ........................................................................... 38
4.2.1
Grafické rozhraní ........................................................................38
4.2.2
Grid — herní plocha ....................................................................39
6
4.3
Společné ....................................................................... 42
4.3.1
Config – interní konfigurační soubor .............................................42
4.3.2
Sender — odesílatel ....................................................................42
4.3.3
Receiver — přijímač ....................................................................44
4.3.4
Recipients Bank — banka adresátů ...............................................45
4.3.5
Datagram Buffer — paměť „spolehlivých“ zpráv .............................46
4.3.6
Grid Generator — generátor hrací plochy.......................................47
5
Testování ......................................................................... 48
6
Nasazení .......................................................................... 50 6.1
Klient ........................................................................... 50
6.2
Server .......................................................................... 51
7
Závěr ............................................................................... 52
8
Použitá literatura ............................................................. 54
9
Ostatní............................................................................. 56 9.1
Odborné zkratky ............................................................ 56
9.2
Seznam obrázků ............................................................ 57
9.3
Přílohy .......................................................................... 57
9.3.1
Obsah přiloženého CD.................................................................57
7
1 Úvod „Hra je radost. Učení při hře jest radostné učení.“ — Jan Ámos Komenský [2] Když jsem se v patnácti letech, ehm tedy v devatenácti, rozhodoval, čím se budu dále zabývat, pekařina nebyla moje volba. Měl jsem tři zcela odlišné touhy. Lákalo mě stát se velitele dělostřelectva studiem na Univerzitě obrany. Také by se mi líbilo státi se molekulárním biologem a genetikem. Kdo netouží po tom, aby mohl klonovat sám sebe, jako by nebyl. A konečně jako třetí možná profese mě lákal vývoj softwaru — konkrétně počítačových her. Tehdy jsem již měl nějaké zkušenosti s vývojem neprogramových částí her Command & Conquer Red Alert 2 a Wolfenstein: Enemy Territory spolu s tím, že jsem měl sen jednou pracovat v jedné ze společností, která vyvinula druhou zmíněnou hru. Jedná se o společnosti id Software a Splash Damage. Právě tento sen — stát se vývojářem her — se na rozdíl od dvou dříve zmíněných tužeb, začal naplňovat i díky mé tehdejší lenosti (studium informatiky je pro mě z těchto tří zmíněných oborů nejjednodušší) a skvělé zkušenosti s vývojem velmi jednoduchých programů v jazyce Pascal v rámci studia na střední škole. Tenkrát jsem byl opravdu Pascalem unešený — byl to skvělý pocit, když vás někdo na (klíčové) slovo poslouchá. Během studia na Vysoké škole polytechnické v Jihlavě jsem se postupně posouval k naplňování svého snu nejen získáváním odborných znalostí a dovedností v rámci studia, ale i ve velké míře vývojem programových součástí hry Wolfenstein: Enemy Territory. Pokud to bylo možné, obvykle jsem si v předmětech výuky volil semestrální práce týkající se vývoje her. Zhruba dva roky zpět jsem získal možnost vyvinout pro jednu společnost hru určenou pro soutěžení v psaní na počítači. Avšak pro nedostatek času a zkušeností z této práce sešlo.
8
Právě tato hra, zmíněná v předchozím odstavci, zásadním způsobem ovlivnila výběr tématu pro bakalářskou práci. Rozhodl jsem se, že vyvinu hru s podobným konceptem té hře, kterou jsem měl vyvinout pro onu společnost. Ovšem s jinými požadavky a architekturou než bylo tenkrát požadováno. Další velkou motivací k vývoji hry je mé přesvědčení, že nejvíce a nejlépe se člověk naučí, pokud si hraje. V tomto případě si hraje na to, kdo rychleji dokáže psát na počítači a zároveň se zdokonaluje právě ve psaní na počítači. Psaní na počítači je dnes velmi aktuální téma, neboť náš svět je značně „kompjuterizovaný“ a určitá dovednost psaní na počítači je dobrým předpokladem pro dobrý výkon mnoha profesí. Také rád spojuji příjemné s užitečným, jak zní známý citát z reklamy na projímadlo. Proč tedy nevytvořit hru, která potencionálně může pomoci s učením hodnotných dovedností potřebných v dnešní době, neposunout se v naplňování svého snu a „odbytím“ si bakalářské práce zároveň?
9
2 Analýza „Kdybych měl k dispozici hodinu na zvládnutí problému, na kterém by závisel můj život, strávil bych 40 minut jeho studiem, 15 minut jeho analýzou a 5 minut jeho řešením.“ — Albert Einstein [1] Jestliže chceme něco tvořit, je dobré si nejprve ujasnit požadavky kladené ať už námi nebo tím, kdo po nás danou věc nebo práci chce, nebo tím kdo práci bude hodnotit. A je jedno jestli se jedná o stavbu domu, upečení dortu nebo vývoje softwaru.
2.1 Požadavky Požadavky kladené na vývoj softwaru lze rozdělit do různých kategorií dle různých hledisek. Jedním takovým hlediskem je funkcionalita — neboli hledisko naplňování potřeb uživatele softwaru. Z tohoto hlediska lze určit dvě základní kategorie požadavků. Funkční a nefunkční. Funkční požadavky přímo vyplývají z potřeb uživatele, respektive jeho požadavků na uspokojení konkrétních potřeb. Jako nefunkční požadavky lze označit všechny ty, které vyplývají z volených technologií vývoje (jazyka, dostupných nástrojů, metodiky vývoje a podobně), z fyzických i virtuálních omezení infrastruktury, kde bude softwarové řešení nasazené.
2.1.1
Funkční
Hlavním zdrojem funkční požadavků je zadavatel, respektive zadání — pokud existuje. Pokud zadání neexistuje, nebo je velmi nejasné, je třeba vhodným způsobem sestavit zadání diskuzí se zadavatelem. Získaní požadavků tak, aby jejich realizace dokázala plně uspokojit zadavatele, není vůbec lehký úkol vyžadující dobré dovednosti v sociální rovině, především komunikaci a analýze běžného mluveného jazyka. V tomto případě je stanovení požadavků o něco jednodušší, jelikož hlavní zadavatel je zároveň vývojář a analytik.
10
Analýzou závazného zadání této bakalářské práce lze zjistit tyto funkční požadavky: kola hry se účastní dva hráči „útočící“ hráč musí svým pohybem po hrací ploše dostihnout toho druhého v časovém limitu, jinak útočník prohrává hrací plocha je sestavena ze čtvercových buněk, kdy každá buňka obsahuje právě jedno písmeno — znak hráči se mezi buňkami mohou přesunovat stiskem klávesy, jejíž hodnota je obsažena v sousední buňce té, na které se právě nacházejí hra vyhodnocuje a zobrazuje uživatelům počet chybně stisknutých kláves, tedy počet stisků kláves, jejíž hodnoty nejsou obsaženy v žádné sousední buňce té aktuální hráči mají možnost si zvolit velikost hrací plochy hráči mají možnost zapnout změnu hodnot těch buněk, které právě opustili přechodem na jinou buňku volitelným, nikoliv povinným, požadavkem je poskytnutí nápovědy toho, kudy po hrací ploše vede nejkratší cesta k druhému hráči
2.1.2
Nefunkční
Obdobnou analýzou zadání, jako v případě analýzy funkčních požadavků, bakalářské práce lze objevit i některé nefunkční požadavky. Konkrétně tyto: realizace v jazyce C++ použití frameworku Qt použití aplikačního rozhraní OpenGL
11
Další důležitým nefunkčním požadavkem nepřímo vyplývajícím je: schopnost předání informací mezi hráči o jejich pohybu po hrací ploše v reálném čase Jelikož jsem hlavním zadavatelem tématu, stanovil jsem si nad rámec povinného zadní vlastní požadavky: pro hráče musí být co nejsnazší začít používat aplikaci bez nutnosti instalace čehokoliv dalšího hra se neinstaluje, pouze extrahuje z distribučního archívu (např. ZIP) na hrací ploše se budou nacházet náhodně generované překážky bránící hráčům v pohybu po některých buňkách hrací plochy hráč se nestará o shánění soupeře; je mu automaticky přidělen při signalizaci toho, že je připraven ke hře
2.2 Volba technologií Výběr technologií, prostředků a nástrojů zásadním způsobem ovlivňuje výkon programátora. To je mimo jiné důvodem, proč jedním z kritérií posouzení kvality společnosti zabývající se vývojem softwaru je využívání nejlepších možných dostupných nástrojů a technologií.
2.2.1
Programovací jazyky
Existují stovky programovacích jazyků. Jak vybrat ten správný? Jednou z možností je si je všechny vyzkoušet, kvantifikovat a kvalifikovat jejich nabízené možnosti. Ovšem toto by byl extrémně náročný způsob, co se času týče. Další možností je využití sdílení zkušeností jiných programátorů s konkrétními jazyky. Pokud jste nikdy neochutnali čokoládovou zmrzlinu, tak ani po přečtení stovek stran informací o čokoládové zmrzlině si nevytvoříte reálný obraz o chuti čokoládové zmrzliny. K tomu je třeba ji ochutnat. Nestačí tedy nastudování zkušenosti s jazyky, je třeba jazyky vyzkoušet. 12
Které jazyky si ale k vyzkoušení vybrat? Dobrou volbou je se podívat, co používají ti nejlepší v daném oboru. Ale to, že něco používá jeden z těch nejlepší v daném oboru, neznamená automaticky, že to ono používané je nutně nejlepší. Znamená to pouze dobrý předpoklad pro existenci kvality dané věci. A to se týká i programovacího jazyka. Jazyk C++ Pro vývoj desktopových a serverových aplikací jsou nejpoužívanější tyto tři jazyky: Java C# C++ Praktické zkušenosti mám se všemi třemi jazyky. Z hlediska programátora mě nejvíce zaujal jazyk C# díky velkému množství syntaktickému cukru a jeho rozšíření o jazyk Linq. Onen syntaktický cukr i v podobě technologie Linq umožňuje rychleji a efektivněji vytvářet aplikace oproti jazyku Java a C++. Velkou výhodou jazyků Java i C# je existence velkého množství knihoven naplňujíc snad každý požadavek programátora. Avšak proti jazyku C++ má Java i C# značnou nevýhodu v nasazení aplikací u uživatele. Java vyžaduje virtuální stroj, jazyk C# je zase opřený o framework .NET, jehož instalace je nutná a může být v některých případech i komplikovaná pro uživatele. Jazyk C++ vyniká tím, že aplikace v něm vytvořené lze snadno nasadit v cílovém prostředí. To je také jeden z hlavních důvodů, proč je tento jazyk vybrán pro zhotovení aplikace dané touto bakalářskou prací. Dalším důvodem volby C++ je skvělá možnost
nasazení aplikací,
v něm
naprogramovaných, v různých cílových platformách. Což u jazyka C# zdaleka neplatí.
13
QML Jazyk QML, celým jménem Qt Meta Language nebo Qt Modeling Language, je jazyk primárně určený k návrhu uživatelských rozhraní. Je součástí frameworku Qt Quick. Vlastnost, ve které vskutku vyniká, je rychlost návrhu grafického rozhraní s vlastním „look & feel“. Tedy QML vyniká v návrhu aplikací, kde si programátor chce definovat všechny prvky grafického rozhraní sám, anebo je chce zásadním způsobem upravit, aby dosáhl jedinečného vzhledu. Tuto vlastnost lze skvěle využít například při návrhu mobilních aplikací a her.
14
Zde je ukázka jazyka QML. Jedná se o definici vlastního tlačítka použitého v navrhované aplikaci. import QtQuick 2.0 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 FocusScope { property string text signal clicked id: rectangleMain width: 80 height: 24 Button { id: button text: parent.text activeFocusOnPress: true clip: true anchors.fill: parent focus: true style: ButtonStyle { background: Rectangle { implicitWidth: 100 implicitHeight: 25 border.width: 1 border.color: "#888" radius: 4 } MouseArea { id: mouseArea anchors.topMargin: 0 anchors.fill: parent hoverEnabled: true onClicked: rectangleMain.clicked() } } }
Výše uvedený kód definuje tři prvky. Prvek FocusScope — neviditelný prvek určený k definici speciálního chování při čtení vstupu z klávesnice a myši. 15
Prvek Button — je standardní tlačítko s výrazně upravenými vlastnosti, mimo jiné pomocí kaskádových stylů (CSS). Třetím prvkem je MouseArea, jehož hlavním úkolem je vymezit plochu, na které se bude číst vstup myší (kliknutí).
2.2.2
Qt framework
Qt znamená multiplatformní framework primárně určený pro C++ zaměřený nejen na produkci softwaru využívající interaktivní grafické rozhraní. V rámci Qt frameworku lze využít i vlastní vývojové prostředí Qt Creator. Prostředí Qt Creator 3.0 jsem zvolil k vývoji aplikace, neboť programátorovi poskytuje velké množství potřebných nástrojů včetně celé řady externích nástrojů a pluginů pro správu verzí, tvorby překladu textů, debuggování nebo návrhu GUI v jazyce QML a pokročilý textový editor zdrojových kódů. Kromě Qt Creatoru pokytuje dobrou podporu pro využití Qt knihoven i prostředí Visual Studio nebo NetBeans.
Obrázek 1: Qt Creator
16
Název Qt vznikl spojením dvou písmen Q a t. Q vybral jen z původních vývojářů, protože se mu líbilo, jak vypadá ve textovém editoru Emacs. Písmeno t bylo přidáno ke Q jako symbol slova „toolkit“. Jeden framework vládne všem. To je propagační heslo vývojářů Qt, které se snaží ukázat, že Qt lze opravdu použít pro vývoj softwaru na všech nejpoužívanějších platformách – a to za použití jednoho aplikačního kódu bez nutnosti vytvářet pro každou platformu zvláštní vývojovou větev. Qt lze využívat pod třemi různými licencemi. Z těch nekomerčních je nejzajímavější GNU Lesser General Public License v2.1 (LGPL). Tato licence je podobná GPL licenci, ale navíc poskytuje možnost distribuovat aplikaci, ke které jsou knihovny Qt dynamicky linkované, i pod jinou licencí než je (L)GPL; to znamená, že pokud programátor bude Qt knihovny dynamicky linkovat, nemusí zdrojový kód své aplikace s nikým sdílet a aplikaci může i prodávat nebo volně šířit jen v její binární podobě.
2.2.3
OpenGL
Framework Qt obsahuje i knihovny umožňující velmi jednoduše využívá aplikačního rozhraní a knihovny OpenGL. Použití OpenGL v Qt je opravdu velmi snadné, ona snadnost a elegantnost je klíčovou vlastností. V kapitole zabývající se implementací aplikace je praktická ukázka kódu. OpenGL je knihovna a aplikační rozhraní určené k programování grafických karet. Oproti konkurenci v podobě knihoven a rozhraní DirectX vyniká tím, že se jedná o otevřený standard dostupný na mnoha platformách.
17
2.2.4
Další technologie
Star UML Star UML je volně dostupný a otevřený CASE nástroj pro návrh a modelování aplikací pomocí jazyka UML. Tento nástroj jsem vybral na základě rešerše volně dostupných nástrojů se stejným zaměřením. Poskytuje možnosti ve větší kvantitě a lepší kvalitě než konkurenční nástroje Modelio či Papyrus. Avšak nedosahuje kvalit komerčních nástrojů. Gliffy Pro tvorbu nestandardizovaných diagramů a přehledů jsem vybral nástroj Gliffy, který je dostupný jako webová aplikace. V omezené míře lze tento nástroj využívat i zdarma. Tento nástroj jsem vybral, jelikož umožňuje velice snadno a rychle tvořit přehledné a graficky příjemné vizualizace.
Obrázek 2: Gliffy
18
2.3 Způsob vývoje Dobrý vývojář softwaru by měl nejen umět něco vytvořit, ale měl by to umět vytvořit efektivně. A přesně pro účel zefektivnění tu jsou metodiky vývoje softwaru. Metodik vývoje softwaru existují desítky. Jak už bylo řečeno, cílem všech těchto metodik je zefektivnění vývoje softwaru — a to pomocí standardizovaných inženýrských postupů. Jednotlivé metodiky se liší především ve vhodnosti použití pro určitý typ uživatelů a určitý typ řešených problémů. Některá metodika je vhodná pro malý tým, některá je vhodnější pro jednotlivce nebo mezinárodní kolektiv, jiná je zase vhodná pro řešení malých projektů, jiná je zase vhodná pro projekty rozsáhlé.
2.3.1
Unifikovaný proces vývoje aplikací
Všechny metodiky vývoje softwaru vyžadují určité praktické zkušenosti ze strany uživatele (analytika, programátora, manažera, grafika, apod.) s nimi, aby plnily svůj účel — skutečně zefektivnily vývoj konkrétního softwaru. S unifikovaným procesem vývoje (UP) mám již praktické zkušenosti jak pracovní tak školní. Navíc pracovní postupy dané touto metodikou vnímám jako relativně intuitivní. Proto jsem tuto metodiku zvolil jako pomoc při vývoji aplikace. Metodika UP dělí veškeré aktivity v rámci vývoje softwaru do pěti kategorií: Požadavky Analýza Návrh Implementace Testování Podobnost struktury této práce s výše zmíněnými kategoriemi aktivit není náhodná.
19
Značnou výhodou metodiky UP je, že poskytuje svému uživateli mnoho ověřených pracovních postupů, které lze ve většině případů využívat nezávisle na ostatních postupech daných touto metodikou. Takže si uživatel může vybrat pro svou potřebu právě jen ty postupy, které jsou nejvhodnější a nejpotřebnější pro typ řešeného problému. Nabízené pracovní postupy jsou definovány dostatečně obecně tak, aby bylo možné si opět vybrané postupy upravit dle vlastní potřeby.
2.4 Existující řešení Existuje celá řada her zaměřených na výuku psaní na počítači. Většina těchto her je pouze pro jednoho hráče. Mnoho těchto her je tvořeno kopiemi klasických her (např. Pacman, had, tetris) s tím rozdílem, že hra se ovládá namísto šipek dynamicky se měnícími písmeny. Výrazně méně je her určených pro více než jednoho hráče. Většina z nich si je podobná a lze o nich hovořit jako o klonech. Jsou to: Během těchto her se hráčovi zobrazují souvislé věty, které je nutné číst a přepisovat. Každé správně přepsané slovo posune hráče na hrací dráze vpřed. Vítězí ten nejrychleji píšící. Výsledek hry lze ovlivnit pouze rychlostí psaní. Jedná se o tyto hry: Nitro Type dostupná na webu http://www.nitrotype.com Rank My Typing dostupná na webu http://www.rankmytyping.com Type Racing dostupná na webu http://www.typeracing.net/ typr X typing races dostupná na webu http://app.typrx.com Sense Lang Racer dostupná na webu http://race.sense-lang.org/
20
Obrázek 3: Sense Lang Racer
Všechny předchozí hry svými možnostmi a kvalitou překonávají tyto dvě hry: Typing of Dead — předchůdce Typing of Dead: Overkill Typing of Dead: Overkill — web hry je http://www.sega.com/totdo/ V případě druhé zmíněné se jedná 3D hru s velice příjemným designem a širokými herními možnostmi. Hráč ovládá svou herní postavu klasicky myší a standardními klávesami jako tomu je v jiných 3D hrách. Ovšem v této hře je úkolem likvidace tzv. nemrtvých (zombie). Každý nemrtvý má u své hlavy zobrazen text a je-li hráčem přepsán, dojde tak k likvidaci příslušného nemrtvého. Obrázek ze hry pro vytvoření představy o vzhledu bohužel nemohu přiložit, neboť se jedná o placenou hru a není k dispozici obrázek ze hry s vhodnou licencí. Domovská webová stránka hry je Další hry pro více hráčů se mi nepodařilo najít. Jsou tedy těžko k nalezení nebo neexistují. Z porovnáním existujících řešení je zřejmé, že není k dispozici žádné řešení podobné tomu, jaké má být zhotoveno na základě tématu této bakalářské práce. 21
3 Návrh řešení „Zbavte se poloviny věcí a potom se zbavte poloviny toho, co zbylo.“ — Krugův třetí zákon [3] Při návrhu jsem se nejprve zabýval sestavením modelu případů užití z daných funkčních požadavků. Pro jednotlivé případy užití jsem definoval scénáře. Na základě případů užití a jejich scénářů a nefunkčních požadavků jsem stanovil architekturu aplikace a navrhl síťový protokol. Nakonec jsem z vytvořeného modelu případů užití sestavil model analytických tříd. Na jejich základě jsem stanovil třídy návrhové.
3.1 Model případů užití Při prvním modelování případů užití jsem vycházel z větší množiny funkčních požadavků, než je zmíněno v kapitole 2.1.1 o funkčních požadavcích. Stanovil jsem si mnohem více požadavků nad rámec povinného zadání. Výsledkem byl velice komplikovaný model, díky kterému jsem si uvědomil, že jsem zvolil nevhodný způsob — zbytečně jsem uvažoval složité procesy, jež by při tom šly nahradit výrazně jednoduššími. Zaměřil jsem se tedy na výrazné zjednodušení funkčních požadavků tak, aby zjednodušení přineslo lepší uživatelskou zkušenost pro uživatele (hráče), zároveň zjednodušilo vývoj a strukturu aplikace a naplnilo zadání této bakalářské práce. Výsledkem zmíněného zjednodušení jsou požadavky (viz kapitola 2.1.1), na jejichž základě jsem sestavil model případů užití zhruba 5x jednodušší oproti prvnímu pokusu. Model se skládá ze dvou systémů, jeden symbolizuje server, druhý klientskou část.
22
Obrázek 4: Diagram případů užití
23
3.2 Architektura aplikace Při návrhu architektury aplikace je vhodné si zjistit, zdali pro řešený problém není již navržen nějaký architektonický styl nebo vzor. Není třeba vymýšlet znovu kolo, které bylo již dávno vynalezeno. Z modelu případů užití vyplývá existence dvou oddělených systémů, které jsou zároveň relativně jednoduché a mají spolu nějakým způsobem komunikovat. Jelikož nejsou kladeny žádné speciální nároky na komunikaci mezi oběma systémy, lze využít pro řešení komunikace těchto systémů notoricky známý architektonický styl klient — server. V klientském systému lze identifikovat nejméně dvě části systémů. Jednu logickou, druhou prezentační. Pro řešení spolupráce takových dvou částí existuje také dobře známý vzor model — view — controller (MVC). Tento vzor rozlišuje tři části (vrstvy) systému. Datovou, prezentační a logickou. Z úhlu pohledu MVC lze za datovou část považovat například konfigurační soubor s nastavením adresy a portu serveru a server samotný. Logická část klientské aplikace bude mít ve své kompetenci příjem/odesílání dat ze serveru a jejich interpretaci při generování potřebných informací pro grafické rozhraní, které lze považovat za prezentační vrstvu. Logická část také bude mít ve své kompetenci načítání konfiguračního souboru.
24
3.3 Síťový protokol V dnešní době jsou při vývoji síťových aplikací používány dva protokoly. Jedním je TCP/IP a druhým UDP.
3.3.1
TCP vs. UDP
Charakteristika TCP: vytváří se spojení garantuje doručení zpráv v pořadí, v jakém byly odeslány automaticky dělí data na pakety kontroluje to, aby data nebyla odesílána příliš rychle a nedošlo k zahlcení síťě snadno se používá [8] Charakteristika UDP: nevytváření se spojení není garantováno doručení paketů v pořadí, v jakém byly odeslány data je nutné dělit do paketů ručně je nutné hlídat, aby pakety nebyly odesílány příliš rychle a nedošlo k zahlcení sítě není zaručeno doručení paketů, některé se mohou ztratit [8] Pro výběr vhodného protokolu je nutné si uvědomit, že herní server musí být schopen v reálném čase doručit zprávy klientům, respektive v co možná nejkratším čase. Klient vůči serveru to samé. Další klíčovou vlastností je, že jakmile jsou k dispozici nová data, tak ta stará automaticky zastarávají a mohou se zahodit.
25
Doručování v co možná nejkratším čase. Zde je TCP v jasné nevýhodě oproti UDP. Kontrola datového toku TCP může odesílané zprávy pozdržet, což je nežádoucí. UDP paket není nijak řízen a rychlost jeho doručení čistě závisí na infrastruktuře mezi klientem a serverem. Pouze nejnovější data jsou aktuální. I zde je TCP v nevýhodě oproti UDP. Jestliže se některá část zprávy ztratí, TCP zajistí přeposlání zprávy. Ovšem, aby bylo zajištěno doručení zpráv ve správném pořadí, dojde ke zdržení odeslání nejnovějších dat — a to je rozhodně nežádoucí. Velkou výhodou TCP oproti UDP je snadnost používání. TCP poskytuje více služeb, kdy některé z nich bude v případě použití UDP implementovat v dané aplikaci ručně.
3.3.2
Vlastní protokol
Během předchozích let jsem se věnoval mimo jiné studiu fungování síťové komunikace, jedno z nejúspěšnějších a nejprodávanějších enginů počítačových her — id Tech 3 nebo také Quake 3 engine. Tento herní engine byl původně vyvinut pro hru Quake 3 Arena společností id Software v roce 1999. Od té doby bylo prodáno několik desítek licencí pro vývoj desítek různých her. Mimo jiné se tento engin stal základním kamenem pro jednu z nejlépe vydělávajících herních sérií — Call of Duty, kdy některé hry z této série přinesli svému vydavateli tržby v řádech desítek miliard korun při nákladech několika miliard korun. Princip komunikace serveru a klienta v id Tech 3: V serverové části, která se stará o vyhodnocování uživatelských akcí, jsou uchovány všechny stavy herních objektů — hráčů, herních postav, herního prostředí — souhrnně stavy herního světa. Veškeré uživatelské akce (stisk kláves) jsou vyhodnocovány serverem, který na jejich základě upravuje stav herního světa — například změní pozici hráčovi postavy. Server posílá informace o aktuálním stavu herního světa hráčům, kde je jsou tyto stavy transformovány do 3D viditelného na monitoru. Součástí herního světa mohou být stovky objektů. Kdyby server měl posílat informace o všech objektech zároveň, nemohla by si v roce 1999, kdy byl tento engin vyvinut, 26
většina potencionálních hráčů zahrát skrze síť internet, neboť by takto velké množství dat nezvládla přenášet v reálném čase zařízení tehdejší doby. Jako řešení výše zmíněného problému byla implementována technologie delta komprese. Tato technologie zajistila nebývalé snížení datového toku od serveru ke klientovi. Server zasílá informace o stavech v konstantní frekvenci 20 Hz — posílá hráčům 20 snímků herního světa za sekundu. Delta komprese zajistila to, že se v jednotlivých snímcích neposílaly informace o všech stavech světa, ale jen o těch stavech, které se změnili od předchozího spolehlivě doručeného snímku k hráčovi. Engin id Tech 3 využívá ke komunikaci mezi klientem a serverem výhradně protokolu UDP, který nezaručuje doručení odesílané zprávy. Jak tedy zjistit, snímek byl nebo nebyl spolehlivě doručen? Vlastní implementací potvrzováním. Každá odeslaná zpráva (datagram) serverem nebo klientem obsahuje hlavičku a vlastní informace o herním světě. Hlavička obsahuje mimo jiné: 1. ID datagramu 2. ID naposledy obdrženého datagramu Potvrzování funguje tak, že klient i server si uchovává ID naposledy obdrženého datagramu. Jedná-li se o klienta, tak klient zašle v každém datagramu ID datagramu, který obdržel naposledy od serveru. Tímto klient potvrdí serveru, že konkrétní snímek herního světa obdržel.
27
3.3.3
Návrh vlastního síťového protokolu
Pro potřeby komunikace serveru a klienta jsem vytvořil vlastní protokol založený na UDP a inspirovaný protokolem enginu id Tech 3. Struktura datagramů zasílaných pomocí UDP je stejná při odesílání zpráv ze strany klienta, tak ze strany serveru. Strukturu datagramu jsem rozdělil na dvě části. Hlavičku a příkazy.
Obrázek 5: Struktura datagramu
Hlavička datagramu Hlavička je rozdělena na tyto 4 části: 1. R — indikuje, zdali je datagram doručován jako spolehlivý nebo nespolehlivý (0 nebo 1) 2. ID — je ID datagramu; každý další zaslaný datagram má o 1 vyšší ID než ten předchozí, aby bylo možné určit na straně příjemce, který je novější 3. ACK — je ID naposledy přijatého datagramu 4. REC — je ID cílového objektu, kterému je datagram zasílán; na straně serveru tím objektem může být správce fronty nebo některý z herních serverů; na straně klienta jím může být hra nebo správce nastavení hry
Obrázek 6: Struktura hlavičky
28
Příkazy Část příkazy obsahuje libovolný počet příkazů a hodnot oddělených zpětnými lomítky. Tato struktura umožňuje snadné ladění nebo rozšíření o další typy příkazů. Takto např. vypadá část `příkazy‘ zasílaná klientem při změně pozice hráče: \positionUpdated\1 \old\3 \new\4\
Příkaz matchCreated Zasílá server klientovi s počátečním nastavením hry. Příklad: \matchCreated\1389233142984 \width\15 \fields\XSGLDVBDPIOCPYKRIHQJXQOFUXBHQGCZYER+++VZDFNVBOAVUA+++KR+ ++DJWXLBT+++FU+++LMBQYNMVNYVI+++OPOE+++LQJPSDGNUFLT+++UBCZEYQSHR MW+++NVT+++LPJMFNZFHYMD+++XFILLISTIRBC+++GUEWBA+++JPUTMKPDJMYQ++ +GDEODSFNTGVU+++IVKZQWYIZHTJWRAJTHBIHBPXL \obstacles\5 \oP0\128 \oP1\167 \oP2\35 \oP3\55 \oP4\92 \attacker\1\
Struktura: matchCreated — udává ID herního serveru width — určuje velikost hrací plochy fields — je seznam hodnot pro jednotlivá pole hrací plochy; znak ‚+‘ znamená indikaci překážky obstacles — udává počet překážek na hrací ploše oP0 až oP4 — umístění překážky na hrací ploše attacker — indikuje to, zdali hráč útočí nebo nikoliv 29
Příkaz matchState Zasílá server klientovi jako snímek stavu herního světa. Příklad: \mSt\1 \pAt\0 \pAo\0 \pDf\224 \pDo\224 \tiL\119599 \sF1\0 \vF1\X \sF2\224 \vF2\L\
Struktura: mSt — indikuje, že se jedná o příkaz matchState pAt — aktuální pozice útočníka pAo — předchozí pozice útočníka pDf — aktuální pozice obránce pDo — předchozí pozice obránce tiL — časový limit do konce hry v milisekundách sF1/sF2 — příkaz značí výběr buňky hrací plochy k aktualizaci její hodnoty vF1/vF2 — příkaz značí novou hodnotu buňky vybranou příkazem sF1/sF2
30
Příkaz queueSize Zasílá server klientovi s informací o počtu hráčů čekajících ve frontě na hru. Příklad: \queueSize\2\
Struktura: queueSize — udává počet hráčů ve frontě Příkaz matchEnded Zasílá server klientovi s výsledky zápasu. Příklad: \matchEnded\1 \winner\2 \elapsedTime\0\
Struktura: matchEnded — indikuje, že se jedná o výsledky zápasu winner — určuje, zdali je vítězem obránce nebo útočník elapsedTime — indikuje uplynulý čas od začátku zápasu; hodnota 0 znamená, že zápas byl v průběhu zrušen jedním z hráčů
31
Příkaz acknowledge Zasílá klient/server serveru/klientovi jako potvrzení doručení zprávy, která byla označena jako spolehlivá. Příklad: \acknowledge\1\
Struktura: acknowledge — má vždy hodnotu 1; ID potvrzované zprávy je obsaženo v hlavičce datagramu — viz část AKC v sekci `hlavička‘ Příkaz matchCanceled Zasílá klient/server serveru/klientovi jako informaci o tom, že zápas byl zrušen. Zasíláli tuto zprávu sever, znamená to, že hráč čekal příliš dlouho ve frontě na hru bez nalezení protihráče. Příklad: \matchCanceled\1\
Struktura: matchCanceled — hodnotou je vždy 1
32
Příkaz requestOpponent Zasílá klient serveru s požadovaným nastavením hry jako požadavek na zařazení do fronty hráčů čekajících na protivníka. Příklad: \requestOpponent\1 \ruleSize\225 \ruleDynamicFields\0\
Struktura: requestOpponent — indikuje, že se jedná o žádost o zařazení do fronty ruleSize — udává zvolenou velikost hrací plochy uživatelem ruleDynamicFields — udává to, zdali se během zápasu mají měnit hodnoty právě opuštěných buněk hrací plochy Příkaz positionUpdate Zasílá klient serveru s informací o změně polohy na hrací ploše. Příklad: \pU\1 \old\209 \new\194\
Struktura: pU — indikuje, že se jedná o příkaz positionUpdate old — značí původní pozici new — značí novou pozici
33
3.4 Model návrhových tříd Na základě modelu případů užití a jejich scénářů jsem sestavil model analytických tříd. Model analytických tříd se zabývá pouze doménou problému, nikoliv doménou jeho řešení. To umožňuje sledovat navrhovaný systém z určité perspektivy/nadhledu, kdy model není zahlcen dalšími detaily týkající se řešení problému. Následně jsem model analytických třídy transformoval na třídy návrhové. Tento model již je určený k zanášení detailů týkajících se řešení problému. Avšak třídy v tomto modelu, na rozdíl od tříd implementačního modelu, nemusí obsahovat úplný výčet metod a atributů. Je zde stále důležitější přehlednost oproti úplnosti.
Obrázek 7: Návrhové třídy
34
4 Implementace „Jsou dvě věci, ke kterým lidi jen těžko přimějete: Přemýšlet o věcech a provádět je v pořadí podle jejich důležitosti. Právě v této dovednosti ale spočívá rozdíl mezi profesionálem a amatérem.“ — George Maxwell [4] Tato kapitola je věnována uspořádání projektu a jeho součástí, deklaraci a popisu kompetencí implementačních tříd a ukázky některých metod a algoritmů. Hlavní projekt IDE Qt Creator 3.0 je rozdělen do tří podprojektů, kdy každý podprojekt je ve vlastní složce: client — třídy v tomto projektu mají prefix K_ server — třídy v tomto projektu mají prefix S_ tests — třídy v tomto projektu mají T_ Kromě těchto podprojektů obsahuje souborový systém hlavního projektu složku common. Složka common obsahuje třídy a jmenné prostory, které jsou společně použité pro server i klientskou část. Zde uvedené třídy a jmenné prostory užívají prefix C_. Prefixy jsou použité pro zpřehlednění a urychlení práce s větším množství souborů zároveň. Dále podprojekt client obsahuje složky QML a resources. Složka QML obsahuje kód soubory s návrhem grafického rozhraní v jazyce QML. Složka resources obsahuje použité textury. Podprojekt client dále zahrnuje dva speciální soubory s příponou qrc. Tyto dva soubory slouží k integraci libovolných dalších souborů přímo do binárních souborů (exe, dll). Pro použití je nutné qrc soubory zkompilovat přiloženým kompilátorem, kdy výsledkem kompilace jsou soubory s příponou rcc. V klientské aplikaci jsou pomocí těchto souborů integrovány textury hráčů a QML soubory, které by jinak bylo nutné přiložit volně k aplikaci do složek — což není žádoucí.
35
4.1 Server 4.1.1
Queue Keeper — správce fronty
Hlavním úkolem správce fronty je příjem žádostí o zařazení do fronty hráčů čekajících na oponenta/zápas. Správce přijaté žádosti od hráčů umístí do fronty a v pravidelných intervalech zkusí sestavit zápasy pro hráče, kteří zadali souhlasná pravidla hry — velikost hrací plochy a dynamická pole. Jestliže je hráč ve frontě určitou dobu, správce upraví hráčem zadaná pravidla tak, aby se zvýšila pravděpodobnost nalezení oponenta. Pokud je hráč ve frontě příliš dlouho, je hráč z fronty vyřazen. Deklarace třídy class S_QueueKeeper : public C_Recipient { Q_OBJECT public: explicit S_QueueKeeper( QPointer
sender , QPointer recipientsBank ); ~S_QueueKeeper(); virtual void processDatagram( QHostAddress sourceIp , quint16 sourcePort , QByteArray datagram ); quint32 count(); private: QPointer rulesCheckTimer; QQueue< QPointer<S_GameRequest> > queue; QPointer sender; QPointer recipientsBank; void processCommands( QStringList commands , QPointer<S_GameRequest> request); void checkRules(); signals: public slots: virtual bool removeByIpWithPort( QString ipWithPort ); private slots: void processQueue(); };
36
4.1.2
Game — herní server
Tato třída reprezentuje konkrétní herní server obsluhující jeden konkrétní zápas. Jakmile správce fronty sestaví zápas, tak herní server zajistí vygenerování hrací plochy, náhodně vybere útočníka a zašle počátečního nastavení hráčům. Po dobu trvání zápasu zpracovává a ověřuje pohyb hráčů po hrací ploše. Také ověřuje, zdali hráči nejsou v kolizi — tedy jestli nevyhrál útočník. Deklarace třídy class S_Game : public C_Recipient { Q_OBJECT public: explicit S_Game( QPointer sender , QPointer<S_GameRequest> request , QPointer<S_GameRequest> otherRequest ); virtual void processDatagram( QHostAddress sourceIp , quint16 sourcePort , QByteArray datagram ); ~S_Game(); quint16 getWidth() const; quint16 getHeight() const; bool getRuleDynamicFields() const; QPointer<S_Player> getAttacker() const; QPointer<S_Player> getDefender() const; quint64 getId() const; void setId(const quint64& value); void executePreparation(); private: quint64 id; quint16 width; quint16 height; bool ruleDynamicFields; QPointer<S_Player> attacker; QPointer<S_Player> defender; QByteArray grid; QStringList obstacles; QPointer timelimitTimer; QPointer frameTimer; QPointer countdownTimer; QPointer sender; qint32 countdown; bool playersAreColliding; void start(); void cancel( const QPointer<S_Player> interrupter ); void processCommands( const QStringList commands , const QHostAddress address , const quint16 port ); signals: void ended( QPointer game ); public slots: virtual bool removeByIpWithPort( QString ipWithPort ); private slots: void prepare(); void run(); void end( QPointer<S_Player> loser = 0 ); };
37
4.2 Klient 4.2.1
Grafické rozhraní
Hlavní okno aplikace je definované v jazyce C++, ostatní jsou navržena v jazyce QML.
Obrázek 8: Okno nastavení zápasu
Obrázek 9: Hlavní okno s hrací plochou
38
4.2.2
Grid — herní plocha
Tato třída reprezentuje hrací plochu. Jejím úkolem je zobrazení hrací plochy, která obsahuje buňky, hráče, překážky. Zobrazení plochy v této třídě je naprogramováno pomocí knihoven OpenGL. Deklarace třídy class UI_Grid : public QGLWidget { Q_OBJECT public: explicit UI_Grid( const QPointer game , QWidget* parent ); ~UI_Grid(); private: QPointer game; GLuint texturesAttacker[ 8 ]; GLuint texturesDefender[ 8 ]; GLuint texturesObstacles[ 12 ]; GLuint* obstacleTypes; GLfloat cellSize; GLuint lineWidth; GLuint gridWidth; GLuint gridHeight; void renderGrid( const GLuint width , const GLuint height , const GLuint lineThickness ); void renderCharacters(); void renderObstacle( const quint32 position , const quint32 type ); void renderObstacles(); void renderPlayer( const GLuint position , const PlayerDirection direction , const PlayerRole role ); bool loadTexture( const QString path , GLuint textures[] , const GLuint index ); void loadGLTextures(); PlayerDirection getDirection( const GLuint current , const GLuint previous ) const; protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL( int width , int height ); };
39
Použití je OpenGL tímto způsobem je velice jednoduché oproti konkurenčním řešením (např. GLUT). Stačí vytvořit třídu, která dědí z třídy QWidget a definovat 3 virtuální protected metody. protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL( int width ,
int height );
Metoda initializeGL() je určená k prvotnímu nastavení OpenGL. Metoda paintGL() zajišťuje samotné renderování grafické scény. A konečně metoda resizeGL() je určena k definici chování při změně velikosti viditelné plochy, kde se zobrazuje grafická scéna. Prvotní nastavení OpenGL je renderování v 2D je velice jednoduché. void UI_Grid::initializeGL() { // initializes Projection Matrix glMatrixMode( GL_PROJECTION ); glLoadIdentity(); // sets the viewport glViewport( 0.0f, 0.0f, this->height(), this->height() ); // sets size of observed area glOrtho( 0.0 , this->height() , this->height() , 0.0 , 1.0 , -1.0 ); // initializes Modelview Matrix glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // initialize clear color glClearColor( MYGL_BACKGROUND_COLOR , 10.f ); // 2D = no depth glDisable( GL_DEPTH_TEST ); // disable lighting glDisable( GL_LIGHTING ); // loads textures loadGLTextures(); }
40
Metoda zajišťující renderování je také velmi jednoduchá, neboť volá další funkce které se zabývají renderováním jednotlivých součástí scény — mřížky, znaků, hráčů, překážek. void UI_Grid::paintGL() { // clears color buffer glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // resets modelview matrix glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // renders grid this->renderGrid( this->gridWidth , this->gridHeight , this->lineWidth ); // renders characters this->renderCharacters(); // renders obstacles this->renderObstacles(); // gets directions of players PlayerDirection attackerDirection = this->getDirection( this->game>getAttackerPosition() , this->game->getAttackerPositionPrevious() ); PlayerDirection defenderDirection = this->getDirection( this->game>getDefenderPosition() , this->game->getDefenderPositionPrevious() ); // renders players this->renderPlayer( this->game->getAttackerPosition() , attackerDirection , ATTACKER ); this->renderPlayer( this->game->getDefenderPosition() , defenderDirection , DEFENDER ); this->swapBuffers(); }
41
A konečně metoda definující chování při změně velikosti plochy. void UI_Grid::resizeGL( GLint width , GLint height ) { // sets the viewport glViewport( 0.0f , 0.0f , height , height ); // initializes Projection Matrix glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0.0, height , height , 0.0 , 1.0 , -1.0 ); // initializes Modelview Matrix glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); GLfloat bigger; if( height > width ) bigger = height; else bigger = width; this->cellSize = ( this->height() - this->lineWidth * ( bigger + 1 ) ) / ( bigger ); }
4.3 Společné 4.3.1
Config – interní konfigurační soubor
Tento soubor obsahuje konstanty definované pomocí maker Obsahuje definice vlastností síťového protokolu, výčtové datové typy, nastavení pravidel hry, nastavení chování správce fronty, nastavení grafického rozhraní klienta.
4.3.2
Sender — odesílatel
Tato třída zajišťuje zasílání datagramů svým příjemcům skrze UDP socket. Zajišťuje správné vytvoření hlavičky UDP datagramu a připojuje k ní data předaná uživatelů této třídy. Zprávy, které jsou zvolené jako spolehlivé, umisťuje do paměti spolehlivých zpráv. Jestliže do určité doby není doručení spolehlivé zprávy potvrzeno, dojde k opakování jejího zaslání určenému příjemci.
42
Deklarace třídy class C_Sender : public QObject { Q_OBJECT public: explicit C_Sender( QPointer udpSocket , QPointer reliableMessages , QHash< QString , quint32 > lastReceivedMessageId ); void resetMessageCounter(); private: QPointer udpSocket; QPointer reliableMessages; QHash< QString , quint32 > lastReceivedMessageId; quint32 messageCounter; QByteArray createHeader( const bool reliable , const quint32 id , const quint32 acknowledge , const quint64 recipient ); QPointer resendTimer; void sendWithIdAcknowledge( const QByteArray datagram , const QHostAddress address , const const const const const
quint16 port , bool reliable , quint64 recipient , quint32 id , quint32 acknowledge
); signals: void messageExpired( QString ipWithPort ); public slots: void send( const QByteArray datagram , const QHostAddress address , const quint16 port , const bool reliable , const quint64 recipient ); void sendWithAcknowledge( const QByteArray datagram , const QHostAddress address , const quint16 port , const bool reliable , const quint64 recipient , const quint32 acknowledge ); void resendAllReliableMessages();
};
43
4.3.3
Receiver — přijímač
Tato třída zajišťuje přijetí zpráv skrze UDP socket a jejich předání danému příjemci. Příjemce může být konkrétní herní server, správce fronty, klientská hra nebo správce nastavení zápasu. Deklarace třídy class C_Receiver : public QObject { Q_OBJECT public: explicit C_Receiver( QPointer udpSocket , QPointer reliableMessages , QHash< QString , quint32 > lastReceivedMessageId , QPointer recipientsBank ); private: QPointer reliableMessages; QPointer udpSocket; QPointer recipientsBank; QHash< QString , quint32 > lastReceivedMessageId; void passIncomingData( QHostAddress& sourceIp , quint16& sourcePort , QByteArray& datagram ); void processAcknowledge( quint32 acknowledge , QString ipWithPort ); protected: signals: void sendAcknowledge( const QByteArray datagram , const QHostAddress address , const quint16 port , const bool reliable , const quint64 recipient , const quint32 acknowledge ); public slots: private slots: void readPendingDatagrams();
};
44
4.3.4
Recipients Bank — banka adresátů
Bank adresátů je datový kontejner uchovávající ukazatele na objekty — adresáty — a jejich ID. Deklarace třídy class C_RecipientsBank : public QObject { Q_OBJECT public: explicit C_RecipientsBank(QObject *parent = 0); quint64 insert( QPointer pointer ); bool insertWithId( QPointer pointer , quint64 id ); QPointer get( quint64 id ); bool remove( quint64 id ); quint32 count(); private: QHash< quint64 , QPointer > recipientList; signals: public slots: bool removeAndDeleteByValue( QPointer object );
};
45
4.3.5
Datagram Buffer — paměť „spolehlivých“ zpráv
Paměť spolehlivých zpráv je datový kontejner uchovávající spolehlivé zprávy, které byly odeslány a čekají na potvrzení přijetí příjemcem. Deklarace třídy struct C_DatagramInfo : public QObject { Q_OBJECT public: quint32 id; QByteArray datagram; QHostAddress address; quint16 port; quint8 trials; quint64 recipient; }; class C_DatagramBuffer : public QObject { Q_OBJECT public: explicit C_DatagramBuffer(QObject *parent = 0); void insert( QString ipWithPort , QPointer ); QList< QPointer > get( QString ipWithPort ); bool erase( QString ipWithPort , QPointer info ); quint32 count(); bool contains( QString ipWithPort ); QMultiHash>::iterator begin(); QMultiHash>::iterator end(); private: QMultiHash< QString , QPointer > messages; signals: public slots: bool removeByIpWithPort( QString ipWithPort );
};
46
4.3.6
Grid Generator — generátor hrací plochy
Generátor hrací plochy není třída. Je to jmenný prostor sdružující funkce použité ke generování hrací plochy. Funkce zde obsažené zajišťují vytvoření jednotlivých buněk hrací plochy, ověření integrity hrací plochy, ověření platnosti přechodu hráče z buňky do buňky, generování překážek. Deklarace veřejných funkcí jmenného prostoru namespace C_GridGenerator { quint32 getRandomNumber( const quint32 low , const quint32 high ); QByteArray getRandomGrid( const quint16 width , const quint16 height ); quint8 getNewValueFor( const quint16 width , const quint32 position , const QByteArray& grid ); bool isNeighbour( const quint16 width , const quint32 oldPosition , const quint32 newPosition , const quint32 gridSize ); quint32 getNewPosition( const quint8 character , const quint32 currentPosition , const quint16 width , const QByteArray& grid ); QStringList createObstacles( QByteArray& grid , const quint16 width , const qreal relativeCoverage );
}
47
5 Testování "Testovaním programu můžeme dokázat existenci chyb, nikoliv potvrdit jejich absenci." — Edsger Dijkstra [5] U softwaru lze testovat zda: pokrývá funkce dané zadáním splňuje určité bezpečností kritéria je stabilní a má předvídatelné chování dobře využívá systémových prostředků Naplnění funkčních požadavků Kvalita implementovaných řešení funkčních požadavků byla testována pravidelně během vývoje. Průběžně byl udržován seznam požadavků k otestování a seznam toho, co se již otestovalo. V konečné fázi vývoje aplikace byla všechna již dříve ověřená řešení požadavků. Bezpečnostní kritéria Bezpečnost aplikace nebyla nijak verifikována a lze předpokládat nízkou míru zabezpečení především proti podvodníkům ze strany hráčům, kteří by chtěli vlastními programovými prostředky získat výhodu nad protihráčem. Kvalitní zabezpečení proti tomuto typu hrozby je velmi komplikované, nákladné a často jen málo efektivní. Stabilita a předvídatelnost chování Stabilita klientské i serverové části byla průběžně testována pro fungování v pravděpodobných i málo pravděpodobných situacích a podmínkách. Během vývoje bylo odladěno mnoho nestabilních stavů, jejichž řešení často zabralo enormní množství času. U některých problémů s neočekávaným chováním bylo obtížné
48
nasimulovat podmínky tak, aby kontrolovaně došlo k výskytu problému, a mohl tak být podroben analýze a aplikaci následného řešení. Původně jsem plánoval využít pro testování spolehlivosti jednotkových testů. Některé části aplikace jsou pomocí jednotkových testů otestovány, ovšem od tvorby těchto testů jsem v průběhu vývoje upustil pro vysokou časovou náročnost údržby a tvorby jednotkových testů. Testováno bylo nasazení pod operačním systémem Windows 7 a Windows XP. Využití prostředků Během vývoje bylo průběžně kontrolováno využití operační paměti a času procesoru tak, aby nedošlo nadměrnému využívání prostředků bezúčelně. Při implementaci renderování hrací plochy pomocí OpenGL byla odhalen zásadní výkonostní nedostatek při použití funkce knihovny Qt pro vykreslení textu skrze OpenGL v grafické scéně. Tato funkce je nevhodná pro renderování většího množství textu. Problém byl vyřešen výrazným snížením počtu voláním dané funkce.
49
6 Nasazení „Co je platné, že kráva dává hodně mléka, když vědro převrhne.“ — dánské přísloví [7] Tato část je věnována pro uživatele — správce serveru a hráče. Na přiloženém CD se nachází ZIP archiv, který obsahuje dvě složky: source — tato složka obsahuje zdrojový kód aplikace bin — tato složka obsahuje spustitelné programy určené uživatelům
6.1 Klient Na přiloženém CD si otevřete ZIP archiv, ve kterém vstupte do složky bin. V této složce se nachází složka pojmenovaná client. Tuto složku včetně jejího obsahu extrahujte na libovolné místo v počítači. Nyní můžete spustit klientskou část jediným spustitelným programem, který se složce client nachází. Ve zmíněné složce client se nachází i konfigurační soubor config.ini, ve kterém lze nastavit adresu a port serveru. Po spuštění aplikace se zobrazí okno s natavením zápasu. Zde si vyberte libovolná pravidla hry a kliknutím na tlačítko hrát budete zařazeni do fronty čekajících hráčů na zápas. Správce fronty Vám automaticky vybere soupeře a náhodně určí, zdali budete útočit nebo se budete bránit. Útočící hráč musí dostihnout obránce v časovém limitu, jinak prohrává. Po hrací ploše se hráč pohybuje stiskem kláves zobrazených v bezprostředně sousedních buňkách hrací plochy.
50
6.2 Server Na přiloženém CD si otevřete ZIP archiv, ve kterém vstupte do složky bin. V této složce se nachází složka pojmenovaná server. Tuto složku včetně jejího obsahu extrahujte na libovolné místo v počítači. Nyní můžete spustit serverovou aplikaci souborem start.bat. Spuštění souboru server.exe není pro start serveru dostačující.
51
7 Závěr „Odborný text bez závěru je jako luxusní dárek v igelitce z Tesca.“ — neznámý autor [6] Naplněné cíle Cílem praktické části práce bylo vytvořit hru vhodnou ke zlepšování dovedností psaní na PC. Tento cíl se podařilo naplnit včetně všech dalších povinných funkčních požadavků. Nad rámec povinného zadání se také podařilo implementovat pokročilý design síťové komunikace inspirované těmi nejlepšími v daném oboru. Podařila se i efektivním způsobem implantace generování překážek na hrací ploše, což přineslo jako vedlejší efekt zlepšení vizuální stránky hry. Podařilo se ověřit snadnost použitelnosti knihoven OpenGL v rámci frameworku Qt. Nenaplněné cíle Jako volitelný cíl byla uvedena implementace nápovědy pro hráče o tom, kudy vede k soupeři nejkratší. Potřebný netriviální algoritmus jsem úspěšně implementoval v jiné aplikaci,
avšak
pro
nedostatek
času
již
nebylo
možné
tento
algoritmus
přeimplementovat a použít v této práci. Taktéž jsem se v teoretické části věnoval popisu OpenGL méně, než by dle stanovení zadání bylo pravděpodobně očekáváno. Od rozsáhlejšího popisu knihoven OpenGL jsem ustoupil proto, jelikož jsem si během psaní této práce uvědomil, že by takový popis neměl žádný užitek, neboť knihovna OpenGL je dobře pospána a dokumentována mnoha jinými zdroji — a pravděpodobně i lépe než bych to svedl já. Zdaleka nejvíce času mi zabral vývoj aplikace, jehož délka se zvětšila především kvůli odhalování a ladění špatně detekovatelných bugů v serverové části. Z toho důvodu mi zbylo zhotovení textu bakalářské práce výrazně méně času než bych si představoval — to se projevilo i absencí diskuze a popisu použitých algoritmů v aplikaci.
52
Možná rozšíření Během vývoje jsem bral na zřetel případné to, aby bylo různé části aplikace rozšířit o další funkce. Díky zvolenému formátu síťového protokolu lze snadno obohatit herní svět serveru o další objekty, než jsou jen čtvercové překážky, aniž by byl potřeba větší zásah od struktury aplikace. V případě, že by se aplikace dočkala masivního využití ze strany hráčů, lze snadno optimalizovat datový tok mezi serverem a klientem. Nyní je síťový protokol více nastaven tak, aby komunikace pomocí něj byla lépe čitelná pro člověka. Vhodným rozšířením klienta je sledování dostupnosti serveru pomocí pingování. Zajímavou a praktickou možností, která by mohla technické podpoře ušetřit mnoho práce, by byla případná implementace automatického ověřování a instalace aktualizací klienta. Pro zlepšení uživatelského prožitku lze snadno doplnit grafickou scénu o pokročilé grafické efekty — například ji převést do 3D — a to s bez jakéhokoliv zásahu do herní logiky serveru i klienta. Ze strany uživatelů by vítaným rozšířením mohlo být přepracování grafického rozhraní do jednookenního designu se zcela vlastními komponentami poskytujícími originální look & feel.
53
8 Použitá literatura [1] Mottak. Citáty - Analýza [online]. [cit. 2014-01-09]. Dostupné z: http://www.mottak.cz/citaty/analyza.php [2] ZAPLETAL, Miloš. Velká encyklopedie her 2: Hry v klubovně. [s.l.] : Leprez, 1996. ISBN 80-901826-9-0. [3] KRUG, Steve. Webdesign: Nenuťte uživatele přemýšlet. Brno: Computer press, a.s. ISBN 80-251-1291-8. [4] Citáty o prioritách. Pelmel citáty [online]. [cit. 2014-01-09]. Dostupné z: http://citaty.pelmel.info/citaty/c17-priority [5] Citáty o chybách a testování SW. LadyLoba [online]. [cit. 2014-01-09]. Dostupné z: http://ladyloba.blog.cz/0801/citaty-o-chybach-a-testovani-sw [6] Citáty slavných. Cílený koučink [online]. [cit. 2014-01-09]. Dostupné z: http://www.cilenykoucink.cz/citaty/ [7] Mottak. Citáty - Zbytečnost [online]. [cit. 2014-01-09]. Dostupné z: http://www.mottak.cz/citaty/zbytecnost.php [8] UDP vs. TCP. Gafferongames.com [online]. [cit. 2014-01-09]. Dostupné z: http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/ [9] Implicit Sharing. Qt Project [online]. [cit. 2014-01-09]. Dostupné z: http://qt-project.org/doc/qt5.0/qtcore/implicit-sharing.html [10] The Three Laws of TDD. Http://butunclebob.com [online]. [cit. 2014-01-09]. Dostupné z: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd [11] C++ Coding Standard. Possibility Outpost [online]. [cit. 2014-01-09]. Dostupné z: http://www.possibility.com/Cpp/CppCodingStandard.html [12] What REALLY happens when you don't free after malloc?. Stackoverflow [online]. [cit. 2014-01-09]. Dostupné z: http://stackoverflow.com/questions/654754/what-really-happenswhen-you-dont-free-after-malloc [13] Modeling a Network protocol with UML. Scietec [online]. [cit. 2014-01-09]. Dostupné z: http://scietec.blogspot.cz/2010/05/modeling-network-protocol-with-uml.html
54
[14] Unreal Networking Architecture. Epic Games [online]. [cit. 2014-01-09]. Dostupné z: http://udn.epicgames.com/Three/NetworkingOverview.html [15] Characteristics of UDP Packet Loss: Effect of TCP Traffic. Internet Society [online]. [cit. 2014-01-09]. Dostupné z: http://www.isoc.org/INET97/proceedings/F3/F3_1.HTM [16] Quake 3 network protocol. Tilion [online]. [cit. 2014-01-09]. Dostupné z: http://www.tilion.org.uk/2011/11/quake-3-network-format/ [17] Quake Engine code review. Fabien Sanglard's non-blog [online]. [cit. 2014-01-09]. Dostupné z: http://fabiensanglard.net/quakeSource/quakeSourceNetWork.php [18] QUAKE 3 SOURCE CODE REVIEW: NETWORK MODEL. FABIEN SANGLARD'S WEBSITE [online]. [cit. 2014-01-09]. Dostupné z: http://fabiensanglard.net/quake3/network.php [19] The Quake3 Networking Model. Book of Hook [online]. [cit. 2014-01-09]. Dostupné z: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/Quake3Networking
[20] ARLOW, Jim a Ila NEUSTADT. UML2 a unifikovaný proces vývoje aplikací. Brno: Computer Press, a.s., 2007. ISBN 978-80-251-1503-9. [21] Server Discovery for Quake III Arena, Wolfenstein Enemy Territory and Quake 4. Centre for Advanced Internet Architectures, Technical Report 070730A. 2007. [22] VAN WAVEREN, J.M.P. The DOOM III Network Architecture. 2006.
55
9 Ostatní 9.1 Odborné zkratky OpenGL — Open Graphics Library TCP — Transmission Control Protocol UDP — User Datagram Protocol QML — Qt Meta Languagenebo Qt Modeling Language PDF — Portable Document Format Linq — Language Integrated Query GUI — Graphical user interface IDE — Integrated development environment UML — Unified Modeling Language UP — Unified Process MVC — Model-view-controller exe — executable dll — Dynamic-link library rcc — Resource Compiler qrc — Qt Resource Collection GLUT — OpenGL Utility Toolkit CD — Compact disc
56
9.2 Seznam obrázků Obrázek 1: Qt Creator ................................................................................................. 16 Obrázek 2: Gliffy ........................................................................................................ 18 Obrázek 3: Sense Lang Racer ...................................................................................... 21 Obrázek 4: Diagram případů užití ................................................................................ 23 Obrázek 5: Struktura datagramu .................................................................................. 28 Obrázek 6: Struktura hlavičky ..................................................................................... 28 Obrázek 7: Návrhové třídy .......................................................................................... 34 Obrázek 8: Okno nastavení zápasu .............................................................................. 38 Obrázek 9: Hlavní okno s hrací plochou ...................................................................... 38
9.3 Přílohy 9.3.1
Obsah přiloženého CD
Na přiloženém CD se v kořenovém adresáři nachází tato bakalářská práce ve formátu PDF a archiv formátu ZIP se zdrojovým kódem aplikace a přeloženými spustitelnými soubory klienta i serveru.
57