Matematická hra na frameworku XNA • Seznamte se s existujícími implementacemi hry KenKen a tyto implementace porovnejte. • Nastudujte framework XNA. • Ujasněte si rozdíly mezi verzemi softwarového vybavení pro PC a Windows Phone 7. • Implementujte komponentu pro generování zadání hry. • Naprogramujte hru pro obě výše zmíněné platformy. • Vytvořte program pro platformu PC pro tisk zadání hry. • Všechny softwarové výstupy důkladně otestujte.
České vysoké učení technické v Praze Fakulta informačních technologií Katedra softwarového inženýrství
Bakalářská práce
Matematická hra na frameworku XNA Jan Nohavica
Vedoucí práce: Mgr. Petr Matyáš
14. března 2012
Poděkování Děkuji svému vedoucímu práce Mgr. Petru Matyášovi za bezproblémovou spolupráci a všem svým přátelům, kteří mi pomohli s testováním softwaru.
Prohlášení Prohlašuji, že jsem tuto práci vytvořil samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Ve smyslu §60 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ý zákonů (autorský zákon), nemám závažný důvod proti užití tohoto školního díla a k užití uděluji svolení.
V Praze dne 14. března 2012
..................... 7
České vysoké učení technické v Praze Fakulta informačních technologií c 2012 Jan Nohavica. Všechna práva vyhrazena.
Tato práce vznikla jako školní dílo na Českém vysokém učení technickém v Praze, Fakultě informačních technologií. Práce je chráněna právními předpisy a mezinárodními úmluvami o právu autorském a právech souvisejících s právem autorským. K jejímu užití, s výjimkou bezúplatných zákonných licencí, je nezbytný souhlas autora.
Odkaz na tuto práci Jan Nohavica. Matematická hra na frameworku XNA: Bakalářská práce. Praha: ČVUT v Praze, Fakulta informačních technologií, 2012.
Abstract This thesis is about an implementation of the mathematical game KenKen in the XNA framework. The results are a game generating library, game version for Windows operating system, game version for Windows Phone 7 mobile operating system and .NET application for game printing. The work describes all steps that led to the creation of all software parts. At the end I summarize accomplished goals and methods of propagation, which I chose for this game. Keywords XNA, Windows, Windows Phone 7, .NET, print, game, software, mathematics, Caged Math, KenKen.
Abstrakt Tato práce se zabývá implementací matematické hry KenKen ve frameworku XNA. Výsledkem je knihovna pro generování jednotlivých zadání, verze hry pro operační systém Windows, verze hry pro mobilní operační systém Windows Phone 7 a .NET aplikace pro tisk zadání. V práci se věnuji krokům, které vedly k vytvoření jednotlivých částí softwaru a v závěru pak shrnuji dosažené cíle a metody propagace, které jsem pro tuto hru zvolil. Klíčová slova XNA, Windows, Windows Phone 7, .NET, tisk, hra, software, matematika, Caged Math, KenKen.
9
Obsah Úvod
17
1 KenKen 19 1.1 Historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.2 Principy hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.3 Současné implementace . . . . . . . . . . . . . . . . . . . . . . 21 2 Analýza a návrh 23 2.1 Programátorské prostředky . . . . . . . . . . . . . . . . . . . . 23 2.2 Generování zadání her . . . . . . . . . . . . . . . . . . . . . . . 27 2.3 Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3 Implementace 3.1 Generátor zadání . . . . . . 3.2 Verze hry pro Windows . . 3.3 Portace na Windows Phone 3.4 Program pro tisk zadání . . 3.5 Testování . . . . . . . . . . 3.6 Nasazení a propagace . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
37 37 40 52 53 55 58
Závěr
59
Literatura
61
A Seznam použitých zkratek
63
B Obsah přiloženého CD
65
11
Seznam obrázků 1.1
Ukázka zadání KenKenu . . . . . . . . . . . . . . . . . . . . . . . .
20
2.1 2.2
Herní smyčka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagram herních obrazovek . . . . . . . . . . . . . . . . . . . . . .
24 33
3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8
Četnost klecí při rozměru 6x6 Četnost klecí při rozměru 8x8 Ukázka menu . . . . . . . . . Ukázka skrolovací obrazovky Ukázka hry jednoho hráče . . Ukázka herního lobby . . . . Ukázka hry na telefonu . . . Program pro tisk zadání . . .
39 40 47 48 49 51 53 54
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
13
Seznam tabulek 1.1
Seznam klecových operací . . . . . . . . . . . . . . . . . . . . . . .
20
2.1 2.2 2.3 2.4 2.5 2.6
Minimální hardwarové požadavky Windows Phone 7 Tabulka rozměrů a nárůstu obtížnosti . . . . . . . . Generování Latinských čtverců . . . . . . . . . . . . Tabulka maximální velikosti klece . . . . . . . . . . Seznam výzev ve hře . . . . . . . . . . . . . . . . . . Seznam použité hudby . . . . . . . . . . . . . . . . .
. . . . . .
26 27 29 29 34 35
3.1 3.2
Rychlost generování zadání (v milisekundách) . . . . . . . . . . . . Výsledky usability testování . . . . . . . . . . . . . . . . . . . . . .
39 57
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
15
Úvod V této práci se budu zabývat implementací hry KenKen od japonského matematika Tetsuya Miyamota. Hru, vzdáleně připomínající známé Sudoku, jsem objevil v lednu 2011. Představil jsem ji svým přátelům, které zaujala, ale zjistili jsme, že v té době neexistovala žádná pořádná implementace, která by splňovala naše očekávání. Rozhodl jsem se ji tedy proto sám vytvořit. Po sepsání všech vlastností, které u takové hry očekávám (nastavení obtížnosti, možnost tisku nebo žebříček nejlepších), jsem si uvědomil, že svým rozsahem značně překračuje velikost programů, které běžně píši a proto jsem jí přetvořil v zadání bakalářské práce. Základní cíle, které jsem si stanovil jsou – vytvoření hry pro operační systém Windows a mobilní operační systém Windows Phone 7, dále pak možnost tisku jednotlivých zadání (buď v samotné hře nebo pomocí externí aplikace) a podpora hry více hráčů. Hra by měla obsahovat moderní prvky, tj. především systém výzev a žebříček nejlepších časů dle nastavené obtížnosti. Prvním krokem po počáteční analýze musí být vytvoření dostatečně rychlého generátoru zadání her (řádově maximálně jednotky sekund), ze kterého pak všechny ostatní součásti budou vycházet. Vzhledem k multiplatformnosti titulu je třeba zvolit technologii, která programování obou verzí co nejvíce usnadní. Všechny součásti se budou muset řádně otestovat a po dokončení veškerých programátorských prací musím zvolit i vhodnou formu propagace mezi fanoušky podobných logických her. Hlavním lákadlem by měl být fakt, že pro obě platformy bude hra vydána zdarma a navíc bude jak v češtině tak v angličtině.
17
KAPITOLA
KenKen 1.1
Historie
Poprvé byla hra KenKen představena v roce 2004 japonským učitelem mamematiky Tetsuyo Miyamotem pod názvem „Kashikoku-Naru-Puzzle“, což v překladu známená „puzzle které vás udělá chytrým“. V roce 2006 začalo japonské nakladatelství Gakken propagovat KenKen jako sérii knih pro děti. Do západní společnosti pak pronikl KenKen v březnu 2008, kdy se začal objevovat v britském deníku The Times. Později toho roku vyšly knihy věnované KenKenu v USA, Francii, Španělsku a rovněž online vydání New York Times začalo publikovat 6 zadání denně. [5] Originální název KenKen prošel složitým vývojem. Mimochodem „Ken“ je japonský výraz pro moudrost, čili název KenKen je ve smyslu „moudrost na druhou“. Dnes se dá setkat s názvy KenKen, KenDoku, Caldudoku nebo Mathdoku. Je to především proto, že KenKen je registrovaná značka firmy Nextoy LLC a nelze ji tedy používat bez svolení majitele práv. Takže i já budu nucen vymyslet pro svou hru alternativní název.
1.2
Principy hry
KenKen je matematická hra založená na jednoduchých aritmetických operacích. Základem je čtvercová matice o rozměrech 4x4 a více. Tato matice je rozdělena na takzvané klece. Klec je definovaná jako 1 až několik sousedních buněk, jejíž hranice je jasně viditelná (viz. obrázek 1.1). Sousední buňky jsou takové, které sdílejí minimálně jednu hranu (nestačí sdílet pouze roh). Každá buňka musí být součástí právě jedné klece a každá klec má přiřazenou právě jednu z pěti operací plus její výsledek (viz. tabulka 1.1). Cílem hry je doplnit do každého řádku a do každého sloupce čísla 1–rozměr hry (při rozměru 4x4 19
1
1. KenKen lze použít pouze čísla 1, 2, 3 a 4). Správné řešení musí splňovat dvě základní podmínky: 1. Unikátnost čísel – všechny řádky a sloupce obsahují každé z možných čísel právě jednou. 2. Správné řešení klece – klecová operace provedená nad všemi čísly v kleci musí produkovat zadaný výsledek.
Obrázek 1.1: Ukázka zadání KenKenu
Tabulka 1.1: Seznam klecových operací Operace = -
Počet buněk 1 2
/
2
+
2 a více
*
2 a více
20
Popis výsledek klece zároveň určuje hodnotu buňky první buňka mínus druhá (nebo opačně) musí být rovna výsledku klece první buňka děleno druhá (nebo opačně) musí být rovna výsledku klece (čísla v kleci musí být soudělná) součet všech buněk v kleci musí dát dohromady výsledek klece součin všech buněk v kleci musí dát dohromady výsledek klece
1.3. Současné implementace
1.3
Současné implementace
V současné době (březen 2012) existuje již relativně mnoho implementací, ale část z nich je omezena například malým počtem zadání a podobně. Odkazovat budu především na takové implementace, které se nějakým způsobem liší od ostatních. • NekNek (http://www.mlsite.net/neknek/) – rozměr zadání 3x3 až 9x9, žádné nastavení obtížnosti, umožňuje odkrýt správnou hodnotu pro vybranou buňku, umí zkontrolovat současné uživatelovo řešení (i částečné) a na požádání zobrazí i kompletní řešení. • Caldudoku (http://www.caldudoku.org) – rozměr zadání 4x4 až 10x10 (bez 7x7), u menších zádání lze nastavit obtížnost, obsahuje průběžnou kontrolu řešení, která podbarvuje duplicity čísel v řádku a sloupci a klece se špatným výsledkem (takovou funkci chci i ve své hře). • Mathdoku (http://www.mathdoku.com) – rozměr zadání 4x4, 6x6 a 8x8, obsahuje čtyři úrovně obtížnosti – easy, medium, hard a speciální noOp, která funguje tak, že uživateli se zobrazí pouze výsledek klece, ale ne operace, která k ní vede. To dělá řešení ještě mnohem složitější. I tuto funkcionalitu přidám do své hry. • KenKen (http://www.kenken.com) – oficiální stránka KenKenu. Obsahuje pouze 6 ukázkových zadání, ale přes jejich web se generuje 6 zadání každý den (různých velikostí a obtížnosti) pro New York Times. Na stránce lze nalézt i seznam knih, které se KenKenem zabývají. • MinuPlu (http://www.minuplu.com) – každých několik týdnů se objeví nových šest zadání s rozměry 3x3 až 6x6 i s řešením. Kromě hraní online lze zadání stáhnout i jako PDF soubory (vhodné pro tisk). • CalduDoku (http://www.conceptispuzzles.com) – vyžaduje registraci a většina zádání je placená, zajímavým nápadem jsou ovšem verze zadání dle počtu operací – SingleOp (pouze jedna operace), DualOp (dvě operace) a QuadOp (všechny čtyři operace). Při hledání současných implementací, jsem nenalezl žádnou desktopovou aplikaci pro Windows. Co se týče Windows Phone 7 tam jsem našel celkem tři. Jde o CalduDoku, Mathdoku a Ultimate Sudoku. Žádná z nich, ovšem není dostatečně komplexní a působí jednoduše – jedná se tedy o jiný koncept, než zamýšlím já.
21
KAPITOLA
Analýza a návrh 2.1
Programátorské prostředky
Předem jsem si stanovil dvě platformy, na kterých hra musí běžet – OS Windows a Windows Phone 7. Díky tomuto výběru, přicházejí v úvahu dvě možné programátorské platformy: • Silverlight – platforma z dílen společnosti Microsoft, která slouží především pro vývoj multimediálních aplikací (webových, desktopových i pro Windows Phone 7). • XNA – framework rovněž od firmy Microsoft. Je navržen přímo pro vývoj her (kromě PC a telefonů i pro herní konzoli Xbox 360). Vzhledem k tomu, že mým cílem je vytvořit profesionálně vypadající hru (jak je to jen v jednočlenném týmu možné) je XNA mnohem lepší volbou, neboť je pro tyto záležitosti přímo navržen. Platforma Silverlight by byla lepší ve smyslu jednodušší implementace, ale zase s náročnějším „ohnutím“ designu hry dle mých představ. Jedním z faktorů je i to, že s XNA mám narozdíl od Silverlightu praktické zkušenosti a již vím, co můžu očekávat a na co si dát pozor. Pro programování využiji Visual Studio 2010 Ultimate (studentská licence) spolu s Windows Phone SDK, který obsahuje emulátor prostředí telefonu. Kromě toho, bude samozřejmě potřeba software na úpravu grafiky – pravděpodobně freeware produkt Paint.NET. K dispozici mám telefon Samsung Omnia 7 s WP7, díky čemuž budu moci hru testovat i přímo a nebudu odkázán pouze na emulátor.
2.1.1
Framework XNA
XNA Game Studio ve verzi 4.0 je framework, od společnosti Microsoft, primárně určený pro vývoj her pro platformy Windows, Windows Phone 7 a Xbox 23
2
2. Analýza a návrh 360. První verze byla vydána na jaře 2006 [3] a od té doby vychází přibližně každý rok nová verze. Je založen na .NET frameworku a jedná se v podstatě o nadstavbu nad grafickým prostředím DirectX. To dělá programování mnohem snažší, než kdyby programátor musel pracovat přímo s DirectX (jednodušší práce s texturami, vykreslováním i se zvukem a hudbou). Jelikož se jedná o .NET je teoreticky možné použít při programování jazyky C++, Visual Basic, C# a další. Dříve byl jediným oficiálně podporovaným jazykem právě C#, ale nově od verze 4.0 je podporován i Visual Basic [7]. XNA není nástroj pro programování her s rozpočtem v řádech milionů dolarů. Je spíše výsledkem snahy Microsoftu umožnit programování dobře vypadajících her pro své platformy (především Xbox 360 a WP7) i malým nezávislým týmům (v mém připadě dokonce jednotlivcům). Jeho výhodou je samozřejmě to, že je Microsoftem široce podporován, je zdarma (neboť na vývoj postačuje i Visual Studio Express, které je zdarma pro všechny) a pokud člověk zná alespoň základy jazyka C# dokáže do programování v XNA proniknout velmi rychle. Základním stavebním kamenem všech her v XNA je takzvaná herní smyčka (viz. obrázek 2.1). Smyčka se skládá z těchto částí:
Start Update Initialize
UnloadContent ntn
LoadContent Draw
Quit
Obrázek 2.1: Obrázek herní smyčky v XNA
• Start – Spuštění hry. • Initialize – Probíhá inicializace proměnných, alokace datových struktur, nastavení globálních vlastností (defaultní rozlišení, povolená gesta ovládání telefonu), spouští se konstruktory tříd atp. • LoadContent – V této metodě se nahraje audiovizuální obsah tj. textury, modely, zvuky, hudba a případně videa. • Update – Zde se zpracovává vstup uživatele (myš, klávesnice, gamepad nebo dotyky na displej) a přepočítavají se všechny náročnější úkoly jako jsou kolize objektů, umělá inteligence protihráčů a další. 24
2.1. Programátorské prostředky • Draw – Metoda pro vykreslení aktuálního stavu hry. • UnloadContent – V této metodě se z paměti odstraní veškerý obsah, který se nahrál v příslušné části LoadContent. • Quit – Ukončení hry. XNA umožňuje navíc vytvořit vlastní Content Pipeline, což je soubor metod, které zpracovávají audiovizuální obsah. To v praxi znamená, že si lze vytvořit například třídu obsahu Level a v rámci jednoho řádku kódu lze načíst celou úroveň hry najednou (a upravený Content Pipeline se postará o nahrání všech potřebných textur, modelů, zvuků atd.). Jakmile skončí metoda LoadContent, začnou se periodicky střídat metody Update a Draw. Lze nastavit buď fixní počet provedení za sekundu (defaultně je 60krát) a nebo variabilní ve smyslu „tak často jak to jde“. Pokud se stane, že metoda Update trvá déle než přidělené kvantum času, tak se metoda nechá doběhnout a následující Draw se přeskočí. Takové je originální chování, které lze samozřejmě různými prostředky změnit. Vždy záleží na konkrétní hře, jestli je pro ni důležitější mít pořád aktuální hodnoty proměnných, nebo aby uživatel přesně viděl, co se děje. Není nutné mít ve hře jednu jedinou velkou smyčku (to by bylo spíše na škodu). Vhodnější chování je, aby například každý vykreslitelný objekt tyto základní metody implementoval. Pak stačí přes všechny aktivní objekty iterovat a zavolat metody Update a Draw nad nimi. Typická ukázka – v hlavní smyčce se zavolá metoda Update – ta zjistí která z herních obrazovek je aktivní a zavolá její metodu Update – aktivní obrazovka se podívá na seznam svých objektů a u všech aktivních zavolá metodu Update – takhle to může kaskádovitě propadávat několik úrovní. Tento přístup je poté samozřejmě mnohem jednodušší na správu i implementaci a navíc je díky němu hra do značné modulární. Jednou vytvořený například zobrazovač aktuálního množství života u hráče, lze přenášet mezi hrami bez nutnosti změn (takovým přenositelným třídám, které implementují všechny metody herní smyčky se v XNA říká komponenty).
2.1.2
Windows Phone 7
Mobilní operační systém Windows Phone 7 byl vydán ve 4. čtvrtletí roku 2010. Ačkoliv má číslovku 7 s předchozí verzí Windows Mobile 6.5 nemá společného téměř nic. V nové verzi Microsoft poprvé představil koncept dlaždic. Dlaždice je v podstatě rozšířená ikona čtvercového nebo obdelníkového tvaru, která umožňuje určitou míru interaktivity. Příkladem může být aplikace pro kontrolu emailové schránky – jakmile přijde nový email, na dlaždici se vedle samotné ikony ukáže „1“ symbolizující nepřečtený email. Tento koncept dlaždic je již nyní naplno integrován i v herní konzoli Xbox 360 a bude i základem operačního systému Windows 8. Kromě dlaždic, je pak základem UI takzvaný 25
2. Analýza a návrh Metro styl, který se vyznačuje tím, že jednotlivé obrazovky aplikace jsou vedle sebe naskládány a uživatel mezi nimi horizontálně listuje. Ale chci především upozornit na věci, které jsou důležité pro programování aplikací a her. Předně se jedná o nutné hardwarové minimum, které musí splňovat každý telefon s WP7. (viz. tabulka 2.1). [6] Z těchto parametrů je pro mojí hru klíčové: dotykový displej (jakmile bude hra uzpůsobená na použivání myši změna na dotyk prstem bude bezproblémová), 256 MB RAM (část zabere samotný systém – ideálně by se hra měla pohybovat kolem 50 MB) a fixní rozlišení obrazovky 800x480 (to usnadní umisťování prvků). Další podstatnou věcí je způsob, jakým se hry na WP7 zveřejňují. Jediným způsobem je totiž nově fungující Marketplace, do kterého můžou vývojáři své aplikace a hry nahrávat. Po nahrání se spustí certifikační proces, který trvá typicky 3–5 dní. Pokud aplikace splní všechny nutné podmínky a má požadované vlastnosti je zveřejněna na Marketplace. Uživatelé si ji pak mohou stáhnout (a to buď v trial verzi nebo zakoupit plnou). Jelikož moje hra bude zdarma, nemá smysl vytvářet trial verzi a rovnou bude zveřejněna verze plná. Tabulka 2.1: Minimální hardwarové požadavky Windows Phone 7 Minimální hardwarové požadavky Windows Phone 7 Displej Kapacitní s minimálně 4 současnými dotyky a rozlišením 800x480 Senzory A-GPS, kompas, akcelerometr, senzor vzdálenosti Kamera 5 Mpx a více RAM 256 MB a více Paměť 8 GB a více GPU Musí podporovat DirectX 9 CPU ARMv7 Cortex a lépe Nejprve budu vytvářet verzi pro PC, jakmile bude hotova a otestována provedu portaci na WP7. Seznam změn, které budu muset provést je následující: 1. Ovládání – Adaptace ovládání z kombinace myš a klávesnice na dotyk. 2. Hudba – Narozdíl od Windows (kde může být hudba spuštěna automaticky) musí ve WP7 hra nejdříve zkontrolovat jestli nehraje jiná hudba. Dle podmínek pro certifikaci aplikací na Marketplace má totiž hudba spuštěná uživatelem přednost před hudbou samotné hry. 3. User interface – Displej je samozřejmě menší než u klasického PC a proto musím dát pozor, aby důležité prvky byly dobře viditelné a veškerý text čitelný. 4. Multiplayer – Vzhledem k náročné implementaci nebude v mobilní verzi hra více hráčů. 26
2.2. Generování zadání her 5. Herní profily – Nepředpokladám, že by hru na jednom telefonu hrálo více lidí, proto bude v mobilní verzi existovat pouze jeden skrytý profil hráče s názvem „WP7“. Žebříček nejlepších časů, ale zůstane zachován. 6. Životní cyklus – Od nové verze Windows Phone 7.5 (Mango) funguje v systému i multitasking. Musím tedy přidat metody pro správné chování hry v situacích, kdy hráč nebo systém vyvolá upozadění aplikace na úkor jiné (a naopak při jejím návratu do popředí) – to je například uložení rozehrané hry.
2.2
Generování zadání her
Prvním krokem k implementaci KenKenu je vytvoření komponenty pro generování jednotlivých zadání her (viz. obrázek 1.1), kterou bude moci využívat jak samotná hra tak program na tisk zadání. Vstupem bude rozměr matice a obtížnost. Jako minimální rozměr jsem zvolil 4x4, neboť je to první velikost, která je alespoň minimálně složitá. Jako maximální rozměr jsem zvolil 10x10, protože zhruba od rozměru 8x8 je hra již velmi náročná (viz. tabulka 2.2). Obtížnosti budou celkem 4 – Easy (Začátečník), Medium (Pokročilý), Hard (Znalec) a Expert. První tři se budou lišit jen četností generování klecí velikosti 1 (čím více jich je tím jednodušší je řešení). Expert ale bude speciální – počet klecí velikosti 1 bude stejný jako u obtížnosti Hard, ale bude to takzvaný noOp, kdy se uživateli zobrazí jen výsledek, ale ne operace která k němu vede, což náročnost posune o řád výše. Celkem bude tedy ve hře 28 kombinací (7 rozměrů x 4 obtížnosti) a věřím, že v takovém množství si každý hráč najde tu ideální náročnost, která mu bude vyhovovat. Tabulka 2.2: Tabulka rozměrů a nárůstu obtížnosti Rozměr 4x4 5x5 6x6 7x7 8x8 9x9 10x10
Počet buněk 16 25 36 49 64 81 100
Nárůst oproti předchozí – 9 (56 %) 11 (44 %) 13 (36 %) 15 (30 %) 17 (26 %) 19 (23 %)
Algoritmus generování bude probíhat, možná nečekaně, „obráceně“. Bude mít tyto kroky: 1. Generování řešení 2. Generování klecí 3. Generování operací v klecích 27
2. Analýza a návrh Tento postup zajístí vždy správné zadání na konci kroku 3. Kdyby se postupovalo opačně (nejdříve by se vytvořily klece) mohlo by se stát, že pro danou sestavu nelze najít existující řešení – navíc by hledání řešení bylo časově velmi náročné (oproti mnou navrženému postupu).
2.2.1
Generování řešení
Prvním krokem je tedy vytvoření řešení zadání. Jinými slovy do čtvercové matice vložit čísla 1–rozměr tak, aby v žádném řádku ani sloupci nebylo jedno číslo více než jednou. Matici, která splňuje takovou podmínku se říká „Latinský čtverec“. Například pro rozměr 4x4 existuje 576 různých Latinských čtverců. [10] Při vymýšlení algoritmu na rychlé generování těchto čtverců jsem vycházel z [2], který jsem následně upravil tak, aby vyhovoval mým potřebám. Kroky algoritmu v pseudokódu jsou následující (pro kratší zápis označme rozměr matice v celé této kapitole jako N ): 1. Vygeneruje náhodnou permutaci čísel 1–N a vloží ji do dvou polí: Permutace a DočasnáPermutace. 2. N–krát provede: • VkládanáHodnota = DočasnáPermutace[0] - 1 • Pro každý řádek výsledné matice (označme i) provede Matice[i, DočasnáPermutace[i]-1] = VkládanáHodnota • Vyrotuje DočasnouPermutaci o jednu pozici doleva Nyní již algoritmus generuje Latinské čtverce, ale v každém takovém čtverci je jeden řádek, který obsahuje čísla 1–N seřazené popořadě – to je pro hru samozřejmě nežádoucí. Z tohoto důvodu jsem přidal ještě jeden krok ve kterém využívám základní vlastnost Latinských čtverců: „Prohozením libovolných dvou sloupců Latinského čtverce získáme znovu Latinský čtverec (analogicky pro řádky)“. 3. Využiji již vygenerované Permutace a prohodím vzájemně dvě třetiny sloupců následujícím způsobem: for (int i = 0; i < N / 3; i++) VyměňSloupceVMatici(Permutace[i]-1 a Permutace[N-1-i]-1) Příklad jednoho generování je v tabulce 2.3. Časová složitost algoritmu je následující: získání permutace neboli N prohození v poli = O(N ), vložení všech čísel (na každou pozici právě jednou) = O(N 2 ), prohození sloupců = O(N 2 /3). Celková složitost generování je tedy rovna O(N 2 ), což je při maximálním rozměru 10x10 velmi rychlé a dostačující. 28
2.2. Generování zadání her Tabulka 2.3: Generování Latinských čtverců Matice 0040 0400 0004 4000 0140 0401 1004 4010 0143 3401 1034 4310 2143 3421 1234 4312 4123 2431 3214 1342
Proměnné Permutace DočasnáPermutace VkládanáHodnota
3241 3241 4
Permutace DočasnáPermutace VkládanáHodnota
3241 2413 1
Permutace DočasnáPermutace VkládanáHodnota
3241 4132 3
Permutace DočasnáPermutace VkládanáHodnota
3241 1324 2
Permutace Prohazované sloupce
3241 02
Algoritmus končí po přesně daném počtu kroků (závislém na N) a nemá možnost se zacyklit. Korektní Latinský čtverec je vygenerován vždy, protože se každé číslo vloží do všech řádků na rozdílné indexy (vkládá se dle čísel v Permutaci). Díky rotování DočasnéPermutace navíc nemůže nastat vložení čásla na obsazenou pozici, protože nám všechny indexy v daném řádku nabídne právě jednou, pokaždé pro jinou VkládanouHodnotu (viz. tabulka 2.3).
2.2.2
Generování klecí
Cílem této části algoritmu je každé buňce přiřadit klec do které patří. Fungují zde samozřejmě určitá omezení – klec s buňkami musí být souvislá, to znamená, že každá buňka v kleci musí s alespoň jednou další buňkou v dané kleci sdílet minimálně jednu hranu. Klece jsou omezené velikostí – minimální velikost je 1 a maximální je rovna (N/2) + 1 (viz. tabulka 2.4). Tabulka 2.4: Tabulka maximální velikosti klece Rozměr Maximální velikost
4x4 3
5x5 3
6x6 4
7x7 4
8x8 5
9x9 5
10x10 6 29
2. Analýza a návrh Vstupem algoritmu je tedy matice, která se má rozdělit na klece a zvolená obtížnost, která se v algoritmu promítne jako číslo – Easy = 6, Medium = 3, Hard a Expert = 0. Generující algoritmus provede postupně pro každou buňku matice následující kroky: 1. Určí, zdali je možné připojit se na klec buňky, která je vlevo (nelze pokud se jedná o první sloupec nebo je daná klec už moc velká). 2. Určí, zdali je možné připojit se na klec buňky, která je nahoře (nelze pokud se jedná o první řádek nebo je daná klec už moc velká). 3. Vygeneruje náhodné číslo z intervalu: • <1, 8 + obtížnost) pokud se nelze připojit na klec vlevo. • <5, 8 + obtížnost) pokud se nelze připojit na klec o řádek výše. • <6, 8 + obtížnost) pokud se nelze připojit na klec vlevo ani na klec o řádek výše. • <0, 8 + obtížnost) pokud se lze připojit na klec vlevo i na klec o řádek výše. 4. Dle hodnoty vygenerovaného čísla provede: • if (číslo == 0) – připojení na klec vlevo. • else if (číslo < 6) – připojení na klec o řádek výše. • else if (poslední zpracováná buňka je v kleci o velikosti jedna a leží vlevo nebo nahoře od současné) – připojení na klec poslední zpracované buňky. Tento krok zamezí vytvoření takzvaných „mrtvých buňek“. • else – vytvoření nové klece. V kroku 3 vidíme, že čím menší je obtížnost tím větší je interval, ze kterého je generováno náhodné číslo. To vede k větší pravděpodobnosti větve „vytvoření nové klece“. A samozřejmě čím více klecí velikosti 1 zadání obsahuje, tím jednodušší je jeho řešení. Časová složitost je znovu O(N 2 ), neboť s každou buňkou se pracuje právě jednou. Algoritmus matici rozdělí vždy korektně, protože každou buňku buď přiřadí ke stávající kleci, nebo založí klec novou – jiná možnost není a ani jedna z nich nemůže selhat. Díky analýze v krocích 1 a 2 se navíc nemůže stát, aby vznikla klec větší než (N/2) + 1.
2.2.3
Generování operací v klecích
Posledním krokem ke kompletnímu zadání je vygenerování operací a výpočet výsledku pro každou klec (seznam možností viz. tabulka 1.1). Tato část algoritmu se musí provést i při obtížnosti Expert (pouze se daná operace nezobrazí uživateli). Mnou navržený postup je následující: 30
2.2. Generování zadání her 1. Pokud je velikost klece 1 rovnou se přiřadí operátor „=“ a výsledek bude roven hodnotě buňky. 2. Vygeneruje se náhodné číslo z intervalu: • <0, 4) pokud jsou v kleci dvě buňky. • <0, 2) v ostatních případech (tři a více buněk). 3. Dle hodnoty vygenerovaného čísla se provede: • (Hodnota = 0) – operátor „*“ – vypočítá se součin všech čísel v kleci, pokud je výsledek větší než 999 změní se Hodnota na 1 (to zabrání příliš dlouhému výsledku, který by se nemusel vejít do grafického vyjádření klece). • (Hodnota = 1) – operátor „+“ – vypočítá se součet všech čísel v kleci a nastaví se jako výsledek klece. • (Hodnota = 2) – operátor „/“ – vypočítá se podíl obou čísel v kleci. A to jak první děleno druhé tak druhé děleno první, pokud je alespoň jeden z těchto výsledků beze zbytku, nastaví se jako výsledek klece. Jinak se změní Hodnota na 3. • (Hodnota = 3) – operátor „-“ – vypočítá se rozdíl obou čísel (použije se ten větší než 0) a nastaví se jako výsledek klece. Takto navržený algoritmus pro každou klec vrátí vždy korektní výsledek – pokud by součin byl větší než 999 změní se na součet, pokud by při dělení čísla nebyla soudělná změní se na rozdíl. Jeho časová složitost je poměrně náročná na přesné určení, ale určitě nepřekročí N 2 , protože takovou složitost by měl jen v případě, kdyby všechny klece měli velikost 1 (a taková možnost je ošetřena), čili můžeme složitost bezpečně určit jako O(N 2 ).
2.2.4
Shrnutí
Celková složitost generování zadání je tedy O(N 2 ), neboť žádná z částí algoritmu nemá větší složitost. Ačkoliv v tomto případě (maximální rozměr pouze 10x10) hrají větší úlohu konstanty, přesto by měl být algoritmus dostatečně rychlý tj. i zadání s největším rozměrem dokáže vygenerovat pod 1 sekundu. Jsem si vědom toho, že takto generovaná zadání mohou mít více řešení. To ale není problém ani při tisku her ani při samotném hraní, protože vytvořím funkci na kontrolu uživatelova řešení. V praxi to znamená, že nezáleží, které z řešení uživatel nalezl pokud budu vždy schopný určit, zdali je správné nebo ne. Taková kontrola bude velmi jednoduchá – stačí zkontrolovat unikátnost čísel v každém řádku a sloupci a zkontrolovat výsledek u každé klece. 31
2. Analýza a návrh
2.3
Gameplay
Nyní je potřeba navrhnout samotnou hru. Co vše bude obsahovat, jaká bude logická struktura menu a všechny další věci, které jdou vytvořit bez samotného programování. Seznam „features“, které jsem si určil jako žádoucí v mojí hře je následující: • Rozměr zadání od 4x4 do 10x10 včetně. • 4 různé obtížnosti – Easy, Medium, Hard a Expert (bez zobrazení operací v klecích). • Herní profily – pro situace vícečlenné domácnosti, návštěvy kamáradů atp. • Žebříček nejlepších časů dle obtížnosti a rozměru. • Výzvy – úkoly pro hráče, které zatraktivňují hru a prodlužují její životnost. • Rychlá a vlastní hra. Při rychlé hře se náhodně zvolí obtížnost a rozměr zadání. • Ukládání rozehrané hry. • Kontrola – uživatel si bude moci zapnout funkci Kontrola, která bude barevně podbarvovat číselné duplicity v řádku/sloupci a rovněž klece se špatným výsledkem. • Krok zpět – možnost postupně odkrokovat svoje akce až na začátek (v případě špatně zvoleného postupu). • Tréninkový mód, kde bude mít uživatel možnost nechat si zobrazit správné řešení. • Hru více hráčů – dva hráči budou hrát stejnou hru a první úspěšný řešitel vyhrává. Součástí lobby (obrazovka před samotnou hrou) bude chat, kde se hráči budou moci domluvit na zvoleném rozměru a obtížnosti. • Tisk zadání – ten vyřeším přes samostatný program. • Samozřejmostí jsou zvuky a podkreslující hudba. Co se týče názvu hry, vybíral jsem z několika možných variant, protože samotné KenKen nemůžu použít (jedná se o registrovanou značku). Jelikož je klíčovým prvkem hry klec, rozhodl jsem se ji zahrnout do názvu mé hry. Z možností „Math in cages“, „Numbers in caged“, „Caged numbers“ a „Caged Math“ jsem zvolil poslední jmenovanou. Nadále tedy budu o mé hře referovat 32
2.3. Gameplay jako o „Caged Math“ – v české verzi pak „Matika v kleci“. Motiv klece chci využít i v barevném provedení – hra bude evokovat mříže a dominantními barvami budou odstíny šedé. Jako kontrastní barvu (při zvýraznění tlačítka a podobně) použiji červenou a bílou.
2.3.1
Herní obrazovky
Protože už vím, co vše bude hra obsahovat, můžu navrhnout systém obrazovek (viz. obrázek 2.2). Pro tvorbu diagramu jsem využil Visual Studio 2010. Šipka značí možnost přesunu mezi obrazovkami a každý šedý obdelník je právě jednou obrazovkou. Černé rámečky jsou pojmenovány a slouží pro rychlejší orientaci v obrázku.
Start
Singleplayer
Options
Choose profile
Pause menu
[Resume or Quick game] Game
Quit Game settings Singleplayer menu Challenges
Scoreboard menu
Scoreboard
Game lobby
Game
Lobby menu
Options
Multiplayer
Main Menu
Choose role
Options
Change resolution
How to Play
Obrázek 2.2: Diagram herních obrazovek 33
2. Analýza a návrh Ještě přidám několik poznámek k obecnému fungování hry. První obrazovkou po zapnutí je výběr profilu, kde se bude dát profil i vytvořit nebo smazat. Při všech akcích a v celé hře musí být uživatel přihlášen (z důvodu konzistence chování). Struktura žebříčku nejlepších časů se bude skládat z menu, kde si uživatel vybere obtížnost a poté bude listovat mezi jednotlivými rozměry. V každé kombinaci obtížnost + rozměr bude uloženo 10 nejlepších časů a jméno profilu, který daného času dosáhl. Pokud v dané kategorii žádný dosažený čas nebude zobrazí se informace o neexistenci rekordu (aby uživatel například nečekal v domnění, že se rekordy odněkud nahrávají). Nastavení bude přístupné nejen z hlavního menu, ale i během pauzy samotného hraní a rovněž v lobby hry více hráčů. V nastavení půjde provést: zapnutí/vypnutí hudby a zvuků, změna jazyka (čeština nebo angličtina), volba celeobrazového režimu nebo zobrazení v okně a změna rozlišení. Při výběru možných rozlišení jsem čerpal z [8] a [9]. Povolil jsem celkem 7 nejpoužívanějších, které umožnují hrát v nativním rozlišení celkem 76,6 % uživatelů (k lednu 2012). Ostatní hráči budou mít obraz lehce zdeformovaný nebo mohou mít hru v okně a zvolit si rozlišení, které jim bude nejvíce vyhovovat. Podrobnější informace o obrazovkách jsou v kapitole 3.2.
2.3.2
Výzvy
Celkem jsem pro hru vymyslel 15 výzev (v angličtině Challenges), které bude moci hráč splnit. V tabulce 2.5 se nachází vždy český a anglický ekvivalent názvu. Tabulka 2.5: Seznam výzev ve hře Úkol Dohraj hru pro začátečníka Dohraj hru pro pokročilého Dohraj hru pro znalce Dohraj hru pro experta Dokonči hru pod 60 sekund Dokonči hru pod 30 sekund Dokonči hru pod 20 sekund Dohraj hru 6x6 Dohraj hru 7x7 Dohraj hru 8x8 Dohraj hru 9x9 Dohraj hru 10x10 Dohraj 10 her Dohraj 100 her Dohraj 1000 her
34
Český název Jsem začátečník Zahřívám se Přituhuje Jsem profík Myslím rychle Rychle a zběsile Rychlost světla Matika je mi koníčkem 7 je mé šťastné číslo 64 ? Brnkačka Nikdy to nevzdám Neporazitelný Tahle hra je sranda Miluju tuhle hru Jsem závislý
Anglický název I’m rookie Warming up Getting tough I’m pro Think fast Fast and Furious Speed of light Math is my hobby 7 is my lucky number 64 ? Piece of cake Never give up Unbeatable This game is fun Love this game I’m addicted
2.3. Gameplay
2.3.3
Hudba
Všechnu hudbu pro hru jsem čerpal ze serveru www.freemusicarchive.org, kam uživatelé nahrávají svoji tvorbu a umožňují ji zdarma šířit pro nekomerční využítí (většinou se jedná o licenci Creative Commons). Do hry jsem hledal především instrumentální hudbu, která by při přemýšlení nerušila a byla jen příjemným dokreslením situace. Seznam nakonec vybraných písní (o celkové délce 12 minut 36 sekund) je v tabulce 2.6. Tabulka 2.6: Seznam použité hudby Autor Black Ant Broke For Free Digi G’Alessio Chan Wai Fat Lee Maddeford
Skladba Fater Lee Only Instrumental raw instrumental pt.1 Dream (instrumental) Tom’s Lullaby (with Les Gauchers Orchestra)
Délka 2:23 2:38 3:06 2:02 2:27
35
KAPITOLA
Implementace 3.1
Generátor zadání
Generátor zadání jsem implementoval jako Portable DLL, díky tomu může stejný soubor využít pro generování jak samotná hra na Windows a Windows Phone tak i program pro tisk. Algoritmus přesně kopíruje způsob navržený v 2.2. Základem je třída Board, která reprezentuje celé jedno zadání hry. Obsahuje tyto veřejné atributy: • Size – Rozměr matice. • Difficulty – Obtížnost hry. • NoOp – Booleovská hodnota určující zdali se jedná o obtížnost Expert. • Numbers – 2D pole s řešením. • Cages – List všech klecí ve hře. Konstruktor třídy přijímá parametry rozměr, obtížnost a noOp. Na základě těchto hodnot vytvoří nejprve přes třídu Permutations pole Numbers a poté přes třídu Cages vyplní list všech klecí. Druhým kontruktorem třídy Board je varianta, která přijímá parametry rozměr, obtížnost, řešení v 1D poli a seznam klecí vyjádřený v řetězci. Tento konstruktor slouží pro obnovení zadání při nahrávání uložené hry. Malou pomocnou třídou je statická třída MyRandom, která je pouhým obalem nad knihovní funkcí Random. Důvod existence této knihovny je prostý, vytváření stálé nové instance třídy Random by bylo zbytečně časově náročné, neboť generování pseudonáhodných čísel je v mojí knihovně využíváno často. Další třídou je třída Permutations, ta slouží k vygenerování řešení (viz. 2.2.1). Obsahuje konstruktor (přijímá parametr rozměr hry), jednu metodu klíčovou a tři metody pomocné: 37
3
3. Implementace 1. public int[,] GetNumbers() – Základní metoda, kterou volá třída Board pro vygenerování řešení. Zde je implementován samotný algoritmus. 2. private int[] getRandomPermutation(int[] array) – Pomocná metoda, která přijímá pole čísel a vrací jejich náhodnou permutaci. 3. private void switchColumns(int first, int second) – Pomocná metoda, která přijímá dva indexy. V interním poli result prohodí dva sloupce s danými indexy. 4. private void switchRows(int first, int second) – Pomocná metoda, která přijímá dva indexy. V interním poli result prohodí dva řádky s danými indexy. Poslední skupinou tříd jsou třídy pro práci s klecemi. Konkrétně se jedná o Cages,Cage a Cell. Třída Cell reprezentující jednu buňku je jednoduchá třída, která má pouze dva atributy: Value (hodnotu buňky) a Coor (souřadnice buňky). Třída Cage je základní třída nesoucí všechny informace o kleci: • Result – Výsledek klece. • Operator – Operace v kleci. • Cells – List všech buněk patřících do klece. • Coordinates – List souřadnic všech buněk (ten je sice obsažen už v rámci struktury Cells, ale tento přístup k souřadnicím je mnohem rychlejší). Jedinou metodou třídy Cage je public void AddOperator(), která přiřadí kleci náhodný operátor a vypočítá správný výsledek (viz. 2.2.3). Poslední třídou je zastřešující třída Cages, kterou využívá Board při generování zadání. Konstruktor Cages přijímá dva parametry – rozměr a obtížnost. Při generování se využívá metoda public List
GetCages(int[,] array), která přijme 2D pole s řešením (výstup třídy Permutations) a vrací vybudovaný list se všemi klecemi. Využívá při tom interní metodu private void createCages(), která implementuje algoritmus z 2.2.2. A nyní k tomu co takto naprogramovaný generátor dokáže. Nejprve rychlost – v tabulce 3.1 je uveden vždy čas v milisekundách pro vygenerování jednoho zadání (jedná se o průměr z 1 milionu generování). Předně vidíme, že rozdíl mezi obtížnostmi je prakticky zanedbatelný – těžší obtížnosti se generují nepatrně rychleji díky tomu, že mají nižší počet klecí a tím pádem se méně přiřazuje operátor a počítá výsledek. Kromě rozměrů 4x4 až 10x10, které potřebuji pro moji hru jsem testoval i to, jak dlouho trvá vygenerování větších zadání. Tak například zadání o rozměru 100x100 trvá v průměru 4,4 ms a zadání o obřím rozměru 1000x1000 trvá lehce pod 1 sekundu (960 ms). Tyto 38
3.1. Generátor zadání výsledky jsou více než dostačující. A to jak pro samotnou hru tak i pro tisk – i nejpomalejšího zadání (Easy 10x10 – 0,046 milisekund) se stihne během 1 sekundy nagenerovat 21. Tabulka 3.1: Rychlost generování zadání (v milisekundách) Rozměr 4x4 5x5 6x6 7x7 8x8 9x9 10x10
Easy 0,00961 0,01366 0,01755 0,02296 0,03033 0,03736 0,04538
Medium 0,00965 0,01392 0,01815 0,02531 0,03134 0,03871 0,04690
Hard 0,00955 0,01471 0,01824 0,02407 0,03151 0,03825 0,04644
Druhá klíčová vlastnost u generátoru je, aby byly papírově těžší zadání opravdu složitější na řešení. Vycházím z principu, že čím více převažují menší klece nad většími, tím jednodušší je celkové řešení, neboť klece o velikosti 1 jsou vyřešené ihned a obecně u malých klecí je menší počet možných řešení. Pro názornost toho jak můj generátor tento problém řeší jsem přidal obrázky 3.1 a 3.2 (data jsou průměrem ze 100 000 generování). Na obou obrázcích je vidět stejný trend. Čím jednodušší obtížnost tím více je v zadání malých klecí a logicky pak méně těch velkých. Konkrétně pak obtížnost Easy při rozměru 6x6 má nejvíce klecí velikosti 1 (v průměru 3,56 ku 2,18 u Hard) a naopak těch o velikosti 4 má nejvíce Hard (v průměru 5,94 ku 3,02 u Easy). Obtížnost Medium se dle očekávání nachází mezi nimi.
Četnost klecí při rozměru 6 7 5,94
5,71
6
Četnost klece
5 4,32 4
4,1 Hard
3,56 3,16
3
2,97
3,02
2,58
2,47
Medium Easy
2,18 2
1,69
1 1
2
3
4
Velikost klece
Obrázek 3.1: Četnost klecí při rozměru 6x6 39
3. Implementace Analogicky stejný tvar mají všechny tři křivky i u rozměru 8x8 (viz. obrázek 3.2). Korektně řečeno mají ho u všech rozměrů, ale do ukázky jsem dal tyto dva rozměry, protože je na nich trend nejlépe viditelný. Četnost klecí při rozměru 8 10
9,32
9 8
Četnost klece
7 6
7,11
6,85 6,45 5,87
Hard
4,99 5 4,08 4
3,88
4,14
Medium Easy
2,57
3
4,13 2,82 2,74
2,21
2,58
2 1 1
2
3
4
5
Velikost klece
Obrázek 3.2: Četnost klecí při rozměru 8x8
3.2
Verze hry pro Windows
Při programování samotné hry jsem vycházel z diagramu obrazovek (viz. obrázek 2.2). Základem je Game State Management (GSM) dostupný jako zdrojový kód ze stránek create.msdn.com, což je server pro vývojáře aplikací a her pro Xbox 360 a WP7 spravovaný Microsoftem. Tento GSM využívá většina projektů, protože je napsaný velmi obecně – funguje na telefonu i herní konzoli a má připravené zpracování uživatelského vstupu přes gamepad, klávesnici i dotykový displej.
3.2.1
Správce obazovek
Správce obrazovek se skládá z jedné hlavní třídy ScreenManager, která je jádrem celé hry a obsahuje všechny metody herní smyčky (viz. obrázek 2.1). Konstruktor ani metoda Initialize neobsahují nic vyjímečného a proto se jim nebudu blíže věnovat. Metoda LoadContent nahrává všechen obsah, který je sdílený a vyplatí se ho udržovat v paměti po celou dobu běhu hry. Jedná se o písmo použité v menu, texturu tlačítka v menu, písmo používané pro nadpis herních obrazovek a texturu sloužící jako pozadí celé hry. Třída má dvě důležité datové struktury – screens, což je seznam všech nahraných obrazovek a screensToUpdate, který obsahuje ty obrazovky ze screens, u kterých 40
3.2. Verze hry pro Windows se ještě neprovedla metoda Update. Důležité metody třídy ScreenManager jsou: 1. void TraceScreens – pomocná debug metoda, která vypisuje seznam všech aktuálně nahraných obrazovek do konzole. 2. void AddScreen(GameScreen screen) – metoda přidá předanou obrazovku do screens a zavolá její metodu LoadContent. 3. void RemoveScreen(GameScreen screen) – metoda odebere předanou obrazovku ze screens i screensToUpdate a poté zavolá metodu UnloadContent. 4. void Update(GameTime gameTime) – metoda provádí následující kroky: a) Všechny obrazovky ze screens přidá do screensToUpdate. b) Pro každou obrazovku z screensToUpdate provede její Update a pokud je stav obrazovky „TransitionOn“ nebo „Active“ zavolá zpracování vstupu od uživatele. c) Pokud je aktivní výpis obrazovek do konzole zavolá se metoda TraceScreens. 5. void Draw(GameTime gameTime) – metoda projde všechny obrazovky ve screens a pokud jejich stav není „Hidden“ zavolá Draw dané obrazovky. ScreenManager pracuje s abstraktní třídou GameScreen, která virtuálně implementuje všechny základní metody (LoadContent, UnloadContent, HandleInput, Update a Draw) a navíc k tomu metodu void ExitScreen(), která řeší bezpečné odebrání obrazovky. To znamená, že obrazovka místo okamžitého zmizení přejde do černé barvy a poté se odebere. Stejně tak každá nová obrazovka přechází z černé – tento styl vypadá elegantněji než v případě okamžitého přeskakování. V konstruktoru každé obrazovky se pak nastavuje doba přechodu (TransitionOn a TransitionOff). Kromě abstraktní třídy GameScreen obsahuje hra tyto abstraktní obrazovky: 1. MenuScreen – tato třída představuje obrazovky s menu. V kontruktoru přijímá název obrazovky (ten bude zobrazen nahoře). Konkrétní menu pak vytváří svůj seznam instancí třídy MenuEntry (jedna instance představuje jednu položku menu). Každé položce menu se přiřadí funkce, která se provede pokud ji uživatel vybere. Tlačítko v menu je nejdříve šedé s černým písmem – pokud na něj uživatel najede zbarví se do červena a písmo se změní na bílé (viz. obrázek 3.3). 41
3. Implementace 2. MessageBoxScreen – třída simuluje modální okno na které musí uživatel reagovat (při jeho zobrazení se zbylá část obrazovky ztmaví). Konstruktor přijímá 4 parametry: zobrazovanou zprávu pro uživatele, textový popisek prvního tlačítka, textový popisek druhého tlačítka a booleanovskou hodnotu jestli se jedná pouze o potvrzovací zprávu (v tom případě se místo dvou tlačítek zobrazí pouze jedno uprostřed). Při vytvoření nové zprávy se přiřadí funkce, které se zavolají pokud bude zpráva přijmuta/odmítnuta. 3. TextInputBoxScreen – třída prakticky totožná s MessageBoxScreen. Klíčový rozdíl je v tom, že uživatel v tomto okně zadává nějaký text. Konstruktor přijímá zprávu pro uživatele a typ vstupu (IP adresa, název profilu, zpráva pro druhého hráče v multiplayeru) – dle něj se nastaví jeho maximální možná délka. Při zpracování uživatelova vstupu se využívá třída InputState. V XNA se stisk detekuje tak, že v minulém stavu byla klávesa stisklá a v aktuálním již není (stav se mění v každém Update tj. defaultně 60krát za sekundu). Třída tedy udržuje vždy aktuální a minulý stav pro každý možný ovladač (klávesnice, gamepad, myš a dotyková obrazovka). Názvy metod jsou samovysvětlující a není třeba je blíže vysvětlovat (všechny vrací booleanovskou hodnotu): • IsNewKeyPress(Keys key) • IsNewButtonPress(Buttons button) • IsMenuSelect() • IsMenuCancel() • IsMessageAccept() • IsMouseClickIn(Rectangle rectangle) – bylo kliknuto myší v daném obdélníku ? • IsMouseIn(Rectangle rectangle) – nachází se myš v daném obdélníku ? • IsMouseScrollDown() • IsMouseScrollUp() • IsMenuUp() • IsMenuDown() Tento přístup má velkou výhodu v tom, že veškeré změny v nastavení ovládání se provádí na jediném místě, což výrazně urychlý konverzi ovládání pro mobilní telefon. 42
3.2. Verze hry pro Windows
3.2.2
Pomocné třídy
Pomocné třídy jsou v mé definici takové, které svou činnost nijak nevykreslují, ale starají se o jednu specifickou funkci programu (přehrávání hudby, lokalizace, diskové I/O operace atd.). 3.2.2.1
Globální proměnné
Statická třída Global obsahuje všechny proměnné a metody, které je vhodné mít rychle a všude přístupné. Jsou to tyto atributy: • SoundManager – správce hudby. • AllProfiles – seznam všech herních profilů. • ActiveProfile – aktivní herní profil. • Scores – datová struktura obsahující celý herní žebříček. • Width – šířka herního okna. • Height – výška herního okna. • Fullscreen – určuje, jestli je hra v režimu celé obrazovky. • Music – určuje, jestli je zapnuta hudba. • Sounds – určuje, jestli jsou zapnuty zvuky. • Challenges – seznam všech výzev. • Mouse – aktuální souřadnice myši v okně. A tyto metody: • void Initialize() – volána při zapnutí hry. Prázdný profil se nastaví jako aktivní, naplní se seznam všech herních profilů a načte se žebříček nejlepších časů. • PlayerProfile GetDummy() – vytvoří prázdný herní profil s nastavením: vypnutá hudba a zvuky, režim celé obrazovky s maximálním rozlišením a jazykem angličtinou. • void SetActiveProfile(PlayerProfile profile) – předaný herní profil nastaví jako aktivní. • void UpdateChallenges(Difficulty diff, int size, TimeSpan time) – dle předaných parametrů dohrané hry aktualizuje stav výzev. 43
3. Implementace • string StringDifficulty(Difficulty diff) – vrací textovou reprezentaci předané obtížnosti. • void PrintText(SpriteBatch spriteBatch, Rectangle rectangle, string text, SpriteFont font, Color color) – vykreslí zadaný text daným písmem a barvou v co největší možné velikosti do zadaného obdelníku (bez deformace poměru stran). 3.2.2.2
Lokalizace
O lokalizaci hry se stará třída Localization. V dodané verzi jsou ve hře dostupné jazyky angličtina a čeština. Třída má tyto tři atributy: aktuální jazyk Language CurrentLanguage, celkový počet jazyků int Languages a datovou strukturu dvou zanořených slovníků se všemi texty ve všech jazycích Dictionary<string, Dictionary> strings. Pro práci se třídou pak slouží následující metody: • string GetString(string name) – hlavní metoda, kterou využívá celá hra při práci s texty. Tato metoda vyhledá správný text dle parametru, který značí název textu a aktuálně zvoleného jazyka. • void AddStrings(string name, string english, string czech) – metoda přidá nový text do struktury strings. Parametry jsou: název textu, jeho varianta v angličtině a jeho varianta v češtině. • void SetNextLanguage() – metoda přenastaví aktuální jazyk na další v pořadí. • void FillDictionary() – metoda volaná v konstruktoru, která přidá do struktury strings všechny texty. Praktický příklad použití: při budování slovníku se zavolá metoda AddStrings("GameName", "Caged Math", "Matika v kleci"). Poté se může kdekoliv v programu zavolat Localization.GetString("GameName") a metoda vrátí název hry dle aktuálně nastaveného jazyka. Díky tomuto chování lze změnit nastavený jazyk okamžitě a kdekoliv. Ovšem reálně je to samozřejmě umožněno pouze v nastavení hry, které je přístupné ze tří míst (viz. obrázek 2.2). Pokud by se do hry přidával další jazyk bylo by potřeba těchto kroků: do výčtového typu se všemi jazyky přidat daný nový, zvýšit hodnotu int Languages o jedna, přidat jeden parametr do metody AddStrings() a samozřejmě dopsat překlady všech textů do metody FillDictionary(). Jinými slovy přidání nového jazyka se dá provést v jediném souboru zdrojového kódu. 44
3.2. Verze hry pro Windows 3.2.2.3
Správce hudby
K přehrávání hudby a zvuků slouží třída SoundManager, která obsahuje 2 klíčové atributy: slovník se všemi zvukovými efekty Dictionary<string, SoundEffect> sounds a seznam všech písní List<Song> music. V metodě LoadContent se vybuduje seznam písní v náhodném pořadí a načtou se všechny zvukové efekty. V konstruktoru se poté spustí první píseň v seznamu a hlasitost se nastaví na 20 %. Jakmile píseň skončí (vyvolá se EventHandler MediaStateChanged) pustí se další píseň ze seznamu. Navíc třída obsahuje tyto dvě metody: • void UpdateStatus() – metoda se vyvolá při změně nastavení hudby. Pokud je nový stav „On“ nastaví se hlasitost na 20 %, pokud je nový stav „Off“ nastaví se hlasitost na 0 %. • void PlaySound(string name) – Předávaný parametr určuje název zvukového efektu, který se přehraje (stisk tlačítka, zdárné dokončení hry atd.). 3.2.2.4
Ukládání a načítání dat
K operacím se soubory slouží v XNA speciální třída IsolatedStorage ta funguje jednotně jak na PC (kde udržuje speciálně pojmenovanou strukturu složek na základě verze hry) tak na WP7 a i na Xboxu 360. Jedna metoda se tedy využívá všude a konkrétní systém si ji pak už přebere po svém (to jak a kam soubory fyzicky uloží). Kromě samotné třídy Storage, která slouží jako obal nad IsolatedStorage použivá hra tři datové struktury: PlayerProfile, GameSave a Scores. Nebudu tu vypisovat dlouhé seznamy všech jejich atributů (obsahují přesně to, co by člověk očekával). Při práci s těmito strukturami se využívá XML serializace, takže samotný zápis do souboru probíhá automaticky. Důležitější jsou samotné metody, které hra využívá: • void SaveScoreboard() – uloží aktuální žebříček nejlepších časů do souboru Game Scoreboard.xml. • List<Score> GetScore() – opačná metoda k předchozí – žebříček z daného souboru načítá. • void SaveGame(GameSave save) – uloží rozehranou hru (název souboru #Jméno profilu# Save.xml). • GameSave LoadSaveGame() – nahraje dříve uloženou hru. • void DeleteSaveGame() – smaže dříve uloženou hru (nastává pokud hru uživatel úspěšně dohraje). 45
3. Implementace • bool SaveFileExists() – vrací „true“ pokud má aktivní herní profil uloženou hru. • List GetProfiles() – načte seznam všech herních profilů. • void CreateNewProfile(string name) – vytvoří nový herní profil s předaným jménem. • void DeleteProfile(string name) – smaže herní profil s předaným jménem. • void SaveProfileChanges() – uloží změny v nastavení (hudba, rozlišení, jazyk) u aktivního profilu. Všechny metody jsou samozřejmě ošetřeny – kontrolují jestli soubor, který chtějí mazat opravdu existuje. Nevytvoří profil pokud už s daným jménem existuje (to je navíc ošetřeno už při samotném tvoření profilů) a tak dále. 3.2.2.5
Žebříček nejlepších časů
Pro reprezentaci žebříčku slouží třída Score, která u každého rekordu udržuje 4 atributy: obtížnost hry, rozměr hry, dosažený čas a jméno hráče, který rekordu dosáhl. Samotnou práci se žebříčkem zajišťuje třída Scoreboard a její tři metody: • bool IsNewRecord(Difficulty diff, int size, int time) – vrací „true“ pokud byl dosažen nový rekord. • string GetRecord(Difficulty diff, int size) – vrací aktuální rekord v dané kombinaci obtížnost + rozměr. Ten se uživateli zobrazuje při hře. • List<string> GetRecords(Difficulty diff) – vrací seznam rekordů v dané obtížnosti. Metoda se využivá v obrazovce Scoreboard. 3.2.2.6
Kontrola uživatelova řešení
Při kontrole řešení (v singleplayeru a multiplayeru) hra využívá statickou třídu UserSolutionCheck, která sdružuje 2 metody hlavní a 9 metod pomocných, které ty hlavní využivají: • bool IsComplete(int size, Board board, GamePiece[,] gamePieces, Difficulty diff) – metoda zkontroluje jestli je řešení kompletní a správné. 46
3.2. Verze hry pro Windows • void CheckUserBoardForErrors(int size, Board board, GamePiece[,] gamePieces, Difficulty diff) – používá se pokud má uživatel zapnutou kontrolu svého hraní. Metoda změní barvu písma z černé na červenou u těch herních buněk, které porušují pravidla hry (duplicity v řádku a sloupci nebo špatné řešení klece). Pomocné metody už jen ve zkratce: 2 metody pro zvýraznění chybných buněk (jedna pro řádky a druhá pro sloupce), metoda pro kontrolu výsledku klece, která dále využívá 5 metod – 1 za každou možnou operaci. Poslední metodou je kontrola unikátnosti čísel v řádku/sloupci (vrací boolean).
3.2.3
Neherní obrazovky
Do neherních obrazovek patří všechna menu a horizontálně skrolovací obrazovky (tam uživatel přepíná mezi více stranami). Ukázka hlavního menu je na obrázku 3.3. Ostatní menu (ve hře celkem 9) vypadají stejně a liší se jen názvem v horní části a samozřejmě tlačítky. Tyto obrazovky lze ovládat buď myší nebo šipkami a klávesami Enter a Escape.
Obrázek 3.3: Ukázka menu Na obrázku 3.4 je ukázka skrolovací obrazovky. Ty jsou ve hře celkem 3: • How to Play (Jak hrát) – návod ke hraní na celkem 5 stranách (Ovládání, Hra, Klece, Ukázka, Hra více hráčů). • Challenges (Výzvy) – seznam 15 výzev na 2 stranách. Pokud uživatel výzvu ještě nesplnil je místo ikony zobrazen velký otazník. 47
3. Implementace • Scoreboard (Žebříček) – pro každou obtížnost je jedna obrazovka, kde uživatel přepíná mezi rozměry. Vždy se zobrazuje 10 nejlepších časů kombinace obtížnost + rozměr. Ovládání je realizováno buď myší (a to kliky nebo kolečkem) nebo šipkami, což je uživateli naznačeno příslušnými ikonami a vysvětleno v sekci „Jak hrát“.
Obrázek 3.4: Ukázka skrolovací obrazovky
3.2.4
Hra jednoho hráče
Tato část je jádrem celé hry. Uživatel si nejprve zvolí co chce hrát. Může si vybrat mezi rychlou a vlastní hrou. U vlastní hry si volí obtížnost (Easy, Medium, Hard, Expert), rozměr (4x4 až 10x10) a typ hry. Typem hry se rozumí buď trénink nebo normální hra. Ukázka jedné z her je na obrázku 3.5. Trénink se liší tím, že uživatel má možnost nechat si zobrazit správné řešení. V důsledku toho se výsledky z tréninku nepromítají ani do žebříčku nejlepších časů a ani v něm nelze splnit výzvu. Z toho důvodu se při tréninku nezobrazuje rekord v dané kategorii ani aktuální herní čas. Pokud uživatel zvolí rychlou hru obtížnost i rozměr je vybrán náhodně a hra je automaticky „normální“. Realizaci obstarává třída SingleplayerGame, která využívá několik pocmocných tříd – kromě dříve zmíněné UserSolutionCheck se jedná o tyto: 1. GameStep – tato třída reprezentuje jeden herní krok. Během hry se všechny uživatelovi kroky (přidání/změna/smazání čísla v buňce) zaznamenávají a vkládají do datové struktury Stack gameStack. Díky tomu má uživatel možnost odkrokovat zpět na začátek. Tato funkce se hodí zejména v případě, kdy je hráč v situaci, kdy volí 48
3.2. Verze hry pro Windows
Obrázek 3.5: Ukázka hry jednoho hráče
mezi více možnostmi jak dál a později si uvědomí, že jím zvolená cesta byla špatně. 2. GamePiece – každá instance této třídy reprezentuje jednu herní buňku. V konstruktoru obdrží správný výsledek, souřadnice na hrací ploše a informaci jestli je obtížnost hry Expert. Vlastní implementace metod Update a Draw poté zajišťuje správné vykreslení buňky v závislosti na aktuální situaci (když je označena, když je číslo v ní špatně, když se uživatel vrací o krok zpět atd.). 3. NumberMenu – tato třída zajišťuje menu pro zadávání čísel na hrací plochu. Jakmile uživatel klikne na herní buňku vykreslí se u ní bílé kruhy. Pro každé z možných čísel jeden kruh a k tomu dva navíc. První se symbolem „_“ slouží k vymazání aktuální čísla v buňce, druhý se symbolem „X“ slouží k zavření menu – například pokud se uživatel překlikl jinam než chtěl. Třída SingleplayerGame má dva kontruktory – první slouží pro start nové hry a příjímá obtížnost, rozměr a typ hry, druhý slouží pro pokračování dříve uložené hry a přijímá strukturu GameSave. Oba konstruktory využívají metodu CommonConstructor(), která řeší věci, které se musí provést vždy (vytvoření buněk, nastavení stopek měřící délku hry atd.). Jedinou metodou mimo těch základních (Load/UnloadContent, Draw, Update a HandleInput) je metoda void SaveGame(), která vytvoří strukturu GameSave z aktuálního stavu hry a uloží jí přes metodu Storage.SaveGameSave(). 49
3. Implementace Metoda Update zpracuje vstup uživatele, vyvolá Update pro všechny součásti hry (jednotlivé buňky a NumberMenu) a zkontroluje jestli hráč nedohrál hru (přes metodu UserSolutionCheck.IsComplete()). Pokud ano, zastaví čas a zobrazí MessageBox s výsledným časem a poznámkou jestli se uživatel dostal do žebříčku nejlepších časů. Metoda Draw je poměrně rozsáhlá a proto je rozdělena do tří menších metod: 1. DrawPieces() – vykreslí herní buňky. 2. DrawMenu() – vykreslí tlačítka pro ovládání hry – Undo, Check, Menu a pokud je typ hry „trénink“ pak i Solution. 3. DrawHints() – vykreslí informace o obtížnosti hry, aktuálním rekordu a délce hraní (viz. obrázek 3.5). Pokud uživatel hru ukončí, aniž by ji úspěšně vyřešil, dojde k automatickému uložení a v SingleplayerMenu přibyde možnost „Continue / Pokračovat“. A naopak dřívě uložená hra se smaže pokud ji uživatel vyřeší.
3.2.5
Hra více hráčů
Princip hry více hračů je takový, že dva hráči začnou v jeden moment hrát stejnou hru a kdo ji první úspěšně vyřeší vyhrává. Jakmile uživatel zvolí hru více hráčů musí si vybrat mezi rolí hosta a klienta (hráči musí být ve stejné lokální síti nebo musí mít host veřejnou IP adresu). Pokud zvolí roli hosta objeví se v herním lobby a čeká na připojení druhého hráče. V opačném případě musí zadat IP adresu hostitelského počítače – jestliže na dané adrese existuje herní lobby s volným místem uživatel se připojí – jinak obdrží zprávu o selhání připojení. Herní lobby je obrazovka s chatem, kde si uživatelé můžou domluvit jakou hru budou hrát (viz. obrázek 3.6). Klient může přecházet mezi stavy „Připraven/Nepřipraven“. Hostitel spouští hru (pokud je klient připraven) a mění nastavení obtížnosti. Do chatu se kromě samotných zpráv vypisují i změny stavu (uživatel se připojí/odpojí, hostitel změní nastavení atd.) u každé zprávy je zobrazen čas odeslání. Jakmile jsou hráči ve hře a jeden z nich zadání vyřeší obdrží druhý hráč informaci s časem dokončení a poté je vrácen do lobby. Pro síťovou komunikaci hra využívá knihovnu lidgren, která je dostupná na http://code.google.com/p/lidgren-network-gen3/. Tato knihovna, řeší spoustu nutných úkonů – roli serveru, připojování hráčů, posílání zpráv atd. Vzhledem k tomu, že informací přenášených mezi hráči je minimum zvolil jsem u zpráv nejbezpečnější metodu přenosu NetDeliveryMethod.ReliableOrdered to zajistí, že všechny zprávy dojdou ve stejném pořadí v jakém byly odeslány. Pro rozpoznání typu paketu (celkem 13) slouží enum PacketType. Nejdůležitější typ paketu Message využívá třídu ChatMessage, která obsahuje 3 atributy: 50
3.2. Verze hry pro Windows
Obrázek 3.6: Ukázka herního lobby
1. MessageType Type – typ zprávy může být: Host, Client, GameStart, ChangeState, ClientConnect a ClientDisconnect. 2. DateTime Time – datum a čas vytvoření zprávy. 3. string[] Parameters – parametry zprávy, jež jsou zpracovány v závislosti na typu zprávy.
Jedinou metodou je pak string GetMessageInLanguage(), která vrací obsah dané zprávy v aktuálním jazyce. Tento přístup zajistí to, že pokud uživatel změní jazyk v průběhu hry, tak i dříve odeslané systémové zprávy budou v nově zvoleném jazyce. Generování zadání pro hráče probíhá na straně hosta – ten vygenerovanou hru (dle nastavených parametrů) uloží u sebe a vytvoří z ní strukturu GameSave s nulovým časem uložení. Tuto strukturu odešle klientovi a jakmile je potvrzeno přijetí zadání oba hráči se automaticky přesunou do samotné hry. Samotný kód tříd MultiplayerLobbyScreen a MultiplayerGame je velmi podobný s hrou jednoho hráče – pouze navíc probíhá zpracování síťových zpráv a jsou přidány metody pro správné ukončení hry v případě kdy jeden z hráčů opustí hru (Quit(), ShutdownServer() a DisconnectClient()). Jediný rozdíl ve hře je v tom, že zatímco při hře jednoho hráče se herní čas při pauze zastaví, tak u hry více hráčů běží stále. Tím jsou zajištěny rovnoměrné podmínky pro oba hráče. 51
3. Implementace
3.3
Portace na Windows Phone
Díky využití XNA nebyla portace na mobilní telefon příliš náročná a do značné míry vychází z 2.1.2. Ve Visual Studiu jsou obě verze (PC i WP7) v jednom projektu a pro rozlišení chování na jednotlivých verzích se používá konstrukce „#if WINDOWS_PHONE“ a „#endif“. Seznam změn, které jsem provedl (řazeno od nejvýraznějších): • Rozlišení hry je napevno nastaveno na 800x480. • Není zobrazen žádný kurzor (při ovládání dotykem nedává smysl). • Hra neobsahuje hru více hráčů. • Tlačítka při hře jsou zvětšena a upravena pro ovládání prsty (viz. obrázek 3.7 a rozdíl oproti 3.5). • Číselné menu při hře se zobrazuje vždy na horní liště (ne přímo u buňky jako v PC). • Při ukládání hry je nový parametr ForceSave – určuje jestli uložení hry vyvolal uživatel nebo systém. • Nový event handler GameStateManagementGame_Activated, který je aktivován systémem v případě, že telefon přechází do stavu „odemknuto“. Pokud metoda nalezne uloženou hru s příznakem ForceSave načte rovnou tuto rozehranou hru. Jinak dojde ke klasickému načtení hlavního menu. • Nový event handler GameStateManagementGame_Deactivated, který je aktivován systémem v případě, že telefon přechází do stavu „zamknuto“. Pokud metoda nalezne aktuálně rozehranou hru uloží jí s příznakem ForceSave. • Existuje pouze jeden herní profil s názvem „WP7“, první obrazovka tedy není výběr profilu, ale rovnou hlavní menu. • V menu se nezobrazuje název profilu. • Hudba se přehrává pouze pokud již v telefonu není puštená hudba uživatelem. • Ikony kláves (Enter, Escape atd.) jsou nahrazeny ikonou prstou. • Odkaz na obrazovku s výzvami je přímo v hlavním menu. • V nastavení hry již není možnost změnit rozlišení. • V návodu ke hraní se nezobrazuje obrazovka vysvětlující ovládání (vše je ovládáno dotykem) a hru více hráčů.
52
3.4. Program pro tisk zadání
Obrázek 3.7: Ukázka hry na telefonu
3.4
Program pro tisk zadání
Program pro tisk herních zadání je samostatný program napsaný v jazyce C#, který stejně jako samotná hra využívá knihovnu generátoru. Celý program se skládá z jediné obrazovky, na které uživatel nastaví všechny parametry (viz. obrázek 3.8). Stejně jako hru jsem i tento program vytvořil ve dvou jazykových mutacích (v češtině a angličtině). Uživatel kromě rozměru a obtížnosti nastavuje počet zadání, které se umístí na jednu stranu a celkový počet zadání, který se vygeneruje (mezi 1 a 24). V nastavení obtížnosti je navíc možnost „Náhodná“, která způsobí, že každé z generovaných zadání bude mít náhodnou obtížnost. Posledním parametrem je mezera mezi hrami, což vyjadřuje minimální zaručenou mezeru (v bodech) mezi dvěma zadáními. Po stisknutí tlačítka „Generovat náhled“ se zobrazí okno s náhledem stran, který uživatel může vytisknout. Na každé tištěné straně se na spodní části vykreslí vodorovná čára a pod ní nápis: „Thank you for using Cage Math Game Printer - Enjoy the game - http://cagedmath.weebly.com“. V případě, že uživatel nemá nainstalovanou žádnou tiskárnu je mu umožněno uložit vygenerované stránky ve formátu XPS. Mimochodem obrázek 1.1 byl vytvořen právě tímto programem. Celý zdrojový kód programu má pouhých 400 řádek. Kromě několika menších metod, které řeší změnu jazyka či změnu nastavení jsou klíčové tyto metody:
53
3. Implementace
Obrázek 3.8: Program pro tisk zadání
• List GetBoards(int count, int size, int difficulty) – vrací seznam všech zadání, které se použijí pro náhled nebo tisk. • void document_PrintPage(object sender, EventArgs e) – řeší samotný tisk – dle nastavení parametru „počet zadání na stránku“ zavolá konkrétní metodu Print1 až Print8. Pokud po provedení metody zbývají ještě nějaká zadání zavolá se document_PrintPage znovu. • void Print1(EventArgs e, int count) – jedna z metod (další jsou Print2, Print4, Print6 a Print8), která umístí daný počet zadání na jednu stranu. 54
3.5. Testování • void DrawBoard(EventArgs e, Rectangle rectangle, Board board) – slouží k vykreslení zadání do přidělené oblasti.
3.5
Testování
Všechny součásti musely být samozřejmě důkladně testovány. Současná verze XNA (4.0), ale zatím bohužel není připravena na automatické testování. Zvolil jsem tedy tyto tři způsoby jak aplikaci testovat:
3.5.1
Unit testy
Unit testy neboli jednotkové testování se používá pro kontrolu funkčnosti malých kousků kódu – typicky metod. Využil jsem je tedy pro otestování generátoru zadání. Jde celkem o 6 testů (název testu se vždy skládá z testované metody a slova Test): • GetNumbersTest() – test vygeneruje danou metodou GetNumbers() 1000 latinských čtverců pro každý rozměr 4 až 10 a kontroluje jestli vrácené dvourozměrné pole je opravdu latinským čtvercem (splňuje unikátnost čísel v řádku a sloupci). • AddOpTest() – test vygeneruje vždy 1000 klecí velikosti 1 až 10. Každé z nich přiřadí testovanou metodou operátor a kontroluje jestli je přiřazený operátor platný (množina možných operací vychází z velikost klece viz. tabulka 1.1). • GetCagesTest() – test kontroluje vytváření klecí nad dvourozměrným polem (1000 instancí pro každý rozměr 3 až 10). Po vytvoření klecí musí být každá buňka v právě jedné kleci a žádná klec nesmí být větší než (rozměr / 2) + 1. • BoardConstructorTest() – test konstruktoru třídy Board s ručně psanými testovacími daty (9 testů standardního a 4 testy nestandardního vstupu – typicky hodnoty mimo očekáváný rozsah). • GetRandomPermutationTest() – test generování náhodných permutací – kontroluje se jestli jsou hodnoty v novém poli stejné jako v původním (na pořadí nezáleží). • ResultTest() – test metod pro výpočet správného výsledku klece (celkem 10 testovacích dat). Každá struktura s testovacími daty obsahuje správný výsledek pro všechny relevantní operace (pokud je velikost klece 2 výsledek pro operaci „=“ nedává smysl). 55
3. Implementace
3.5.2
Usability testy
Testování použitelnosti jsem provedl po vytvoření funkční PC verze hry. Testy obnáší vytvoření scénaře, který plní vybrané osoby – podle jejich reakcí a způsobu řešení úkolů se v programu hledají designové chyby. Dle článku [4], který se touto problematikou zabývá je dostatečný počet testovacích osob 5. Pro účely testování jsem tedy vytvořil tento text: Tento test vám zabere přibližně 15 minut. Děkuji předem za vaši pomoc a váš čas. Jste zapáleným fanouškem logických her a právě jste si stáhli novou hru jménem Caged Math. 1. Bohužel v angličtině nejste příliš silný. Po vytvoření herního profilu tedy nejprve změňte jazyk hry na češtinu. 2. Spusťte hru jednoho hráče s nastavením rozměr 4 a obtížnost Znalec. Do prvního řádku vložte čísla 2, 1, 3, 4 a poté hru ukončete. 3. Zjistěte jaký je aktuální nejlepší čas v kategorii rozměr 5 a obtížnost Pokročilý. Čas zapište na následující řádek. 4. Napište kolik je ve hře celkem výzev. 5. Přečtěte si sekci Jak hrát a označte odpověď, která nejvíc vystihuje váš názor. a) Vím přesně jak se hra hraje. b) Vím jak se hra hraje, ale raději si to ověřím při samotném hraní. c) Tuším jak se hra hraje a budu potřebovat několik her abych ji pochopil. d) Z návodu jsem hru nepochopil a nevím jak se hraje. 6. Ohodnoťte obecné vlastnosti aplikace od 1 do 10 (10 naprosto souhlasím, 1 vůbec nesouhlasím). a) Aplikace se mi vizuálně líbí. b) Aplikace se mi dobře ovládá. c) Ovládací prvky jsou tam, kde bych je očekával. d) Logická struktura menu mi vyhovuje. 7. Prostor pro vaše komentáře.
56
3.5. Testování Testování jsem provedl na 5 osobách. U úloh 1 až 4 jsem měřil celkový čas a počet chyb (například hledání ve špatném submenu). V tabulce 3.2 jsou shrnuty výsledky. Tabulka 3.2: Výsledky usability testování
1 2 3 4 5
Úloha 1 (čas/chyb) 0:21 / 0 0:20 / 1 0:29 / 0 0:21 / 0 0:11 / 0
Úloha 2 (čas/chyb) 1:08 / 0 1:11 / 0 1:21 / 0 1:20 / 1 0:53 / 1
Úloha 3 (čas/chyb) 2:38 / 1 1:35 / 0 2:07 / 1 2:04 / 1 1:24 / 0
Úloha 4 (čas/chyb) 3:00 / 0 1:53 / 0 3:36 / 1 2:32 / 0 2:04 / 1
Úloha 5 (odpověď) A A B B B
Úloha 6 (známky) 8, 9, 8, 9 9, 10, 8, 10 8, 8, 8, 6 9, 3, 7, 8 9, 10, 9, 9
S výsledky testu jsem byl spokojen. I uživatelům, kteří hru viděli poprvé se hra líbila (průměrná známka 8,6) a dobře ovládala (průměrná známka 8). Po několika minutách ve hře už vše ovládali velmi rychle. Vzhledem k tomu, že všichni dokázali principy hry pochopit z návodu Jak hrát (odpovědi A nebo B v úloze 5) není nutné ho dále rozšiřovat nebo upravovat. V posledním bodě, který byl prostorem ke komentářům jsem obdržel několik zajímavých podnětů, kterým se budu věnovat při tvorbě dalších verzí: • Změnu jazyka umožnit ještě před vytvářením profilu. • Po vytvoření profilu ho rovnou nastavit jako aktivní. • Umístit žebříček s nejlepšími časy přímo do hlavního menu. • Při nastavování obtížnosti hry umožnit ovládání i šipkami doleva a doprava (v současné době Enter). • Stejně jako ve verzi pro telefony zvýraznit jestli je při hraní aktivní funkce „Check“. • Umístit klávesové zkratky pro ovládání hry blíže k sobě.
3.5.3
Vlastní testy
V průběhu celého vývoje jsem aplikaci průběžně testoval a nahrál jsem řádově několik hodin (především pak u mobilní verze). Po dokončení každé verze, která přinesla něco radikálně nového z pohledu uživatele jsem hru odeslal několika známým, kteří mají zkušenosti buď s programováním nebo hrají ve velkém počítačové hry. Novinky a změny jsem s nimi konzultoval a snažil jsem se díky nim objevit možné zádrhele. 57
3. Implementace
3.6 3.6.1
Nasazení a propagace Nasazení
Nasazení mobilní verze bylo jednoduché. Jediným způsobem je totiž využití Marketplace. Vývojář vyplní základní údaje – jméno aplikace, popis, verze, cena v jednotlivých regionech atd. Dále je potřeba několik screenshotů a především soubor, který vygeneruje Build příkaz ve Visual Studiu. Pokud jsou všechny údaje v pořádku spustí se certifikace. Jakmile aplikace projde všemi testy (typicky 2 až 3 dny) je zveřejněna. Vývojáři jsou poté zpřístupněny statistiky stahování (vždy o týden později). Caged Math byl poprvé zveřejněn 18. prosince 2011 ve verzi 0.9, v současné době (březen 2012) je aktuální verze 1.1 a hra má kolem 300 stažení (nejpopulárnější je ve Spojených státech – 80 stažení). Díky tomu, že jsem hru zpropagoval na několika českých fórech, které se hrami na mobilních telefonech zabývají je počet českých stažení 33, což je na nízký počet telefonů s WP7 u nás velmi dobrý poměr (přes 10 % všech stažení). U PC verze bylo nasazení o něco složitější. Využil jsem integrovaný nástroj ve Visual Studiu pro tvorbu instalačních balíčků. Výsledkem jsou 2 soubory o velikosti 30 MB. Při samotné instalaci program zkontroluje jestli uživatelův systém má nainstalovány dvě nutné součásti (Microsoft .NET Framework 4 Client Profile a Microsoft XNA Framework Redistributable 4.0). Pokud některá ze součástí chybí je automaticky stažena a nainstalována (poté je nutný restart). Na ploše jsou potom vytvořeny dvě ikony – jedna pro spuštění hry, druhá pro program pro tisk zadání.
3.6.2
Propagace
Prvním krokem pro propagaci hry byla krátka 5 minutová prezentace PC verze hry na konferenci určené herním vývojářům Game Developer Session 2011. Druhým krokem bylo vytvoření jednoduchých webových stránek na adrese „http://cagedmath.weebly.com“. Tam se nachází seznam novinek (především informace o nových verzích), dále informace o samotné hře, video ukázka hry a hlavně odkazy ke stažení jednotlivých verzí hry. Zřejmě nejdůležitějším krokem byla ovšem recenze hry na serveru bonusweb.cz [1], která má sekci věnovanou hrám zdarma. Hra obdržela velmi dobré hodnocení 82 % a jako hlavní klady byly zvýrazněny možnost tisku rébusů a ovládání. CagedMath byl dokonce zvolenou Hrou týdne a dostal se díky tomu na hlavní stránku zpravodajského serveru idnes.cz. Během prvního týdne od zveřejnění recenze byla hra stažena ze stránek Bonuswebu celkem 1600 krát.
58
Závěr V této bakalářské práci se mi podařilo splnit všechny vytyčené cíle a vyzkoušet si tvorbu softwaru od nápadu přes návrh, implementaci až po nasazení a propagaci. Výsledkem je funkční implementaci hry KenKen, pod vlastním názvem Caged Math, se všemi navrženými požadavky a to pro obě cílené platformy (PC a mobilní telefony s Windows Phone 7). Vytvořil jsem i program pro tisk herních zadání a webovou stránku k propagaci hry. Vzhledem k vysokému hodnocení v recenzi (82 % a vysokému počtu stažení viz. [1]) věřím, že jsem vytvořil kvalitní a uživatelsky přívětivou hru, která je k dispozici zdarma a doposud pro PC neexistovala. Rovněž věřím, že jsem rozšířil povědomí o principech této zajímavé matematické hry, která se může stát podobným fenoménem jako Sudoku. Pro další vývoj a zlepšování hry bych rád využil především feedback od samotných hráčů a rovněž nápady, které jsem obdržel v rámci usability testů.
59
Literatura [1]
Bonusweb.cz: Caged Math - Sudoku pro matematiky. [cit. 2012-03-13]. Dostupné z WWW:
[2]
Code through the Looking Glass: LATIN SQUARE and its implementation (C++). [cit. 2012-03-01]. Dostupné z WWW:
[3]
Harbour, J. S.: XNA Game Studio 4.0 for Xbox 360 developers. Cengage Learning, 2012, ISBN 978-1584505372.
[4]
Jakob Nielsen: Why You Only Need to Test with 5 Users. [cit. 2012-03-13]. Dostupné z WWW:
[5]
KenKen.com: The KenKen Craze! [cit. 2012-02-26]. Dostupné z WWW:
[6]
Lee, H.; Chuvyrov, E.: Beginning Windows Phone 7 Development. Apress, 2010, ISBN 978-1430232179.
[7]
Microsoft: What’s New in XNA Game Studio 4.0 Refresh. [cit. 2012-02-25]. Dostupné z WWW:
[8]
w3schools.com: Browser Display Statistics. [cit. 2012-03-03]. Dostupné z WWW:
[9]
w3schools.com: Statistics for Higher Screen Resolutions. [cit. 2012-03-03]. Dostupné z WWW:
[10] Wolfram: Latin Square. [cit. 2012-03-01]. Dostupné
z
WWW:
61
PŘÍLOHA
Seznam použitých zkratek XNA XNA is Not an Acronym WP7 Windows Phone 7 UI User Interface DLL Dynamic-Link Library GSM Game State Management XML Extensible Markup Language XPS (Open) XML Paper Specification
63
A
PŘÍLOHA
Obsah přiloženého CD readme.txt Instalace – Podpora – CagedMathSetup.msi – setup.exe – Install.txt
textový soubor s obsahem CD adresář s instalačními soubory adresář pro případ offline instalace instalační soubor #1 instalační soubor #2 poznámky k instalaci
Spustitelné soubory – CagedMath.exe – CagedMathGamePrinter.exe – ...
adresář se hrou a programem pro tisk hra program pro tisk ostatní soubory
LaTeX – BP_Nohavica_Jan_2012.pdf – ...
adresář s bakalářskou prací výsledné pdf se samotnou prací zdrojové soubory
Zdrojové kódy – BP – CagedMath – GamePrinter – Generator – UnitTest_Generator – WindowsSetup – BP.sln
adresář se všemi zdrojovými kódy obsahuje diagramem obrazovek zdrojové kódy ke hře (PC i WP7) zdrojové kódy k program pro tisk zadání zdrojové kódy ke generátoru zadání unit testy pro generátor zadání projekt pro tvorbu instalačních souborů Visual Studio Solution sdružující všechny zdrojové kódy do jednoho projektu
65
B