Sledujte nás na YouTube

Vyvíjíme pro WP v XNA: Triky pro vykreslování grafiky (13. díl)

Ve třináctém díle o programování her pro Windows Phone v XNA vám představíme užitečné triky pro vykreslování grafiky.

V našem seriálu jsme si už popsali mnoho zajímavých tipů a triků pro vývoj her v XNA na Windows Phone. V pátém díle bylo například zmíněno, jak zařídit, aby hra na mobilu běžela rychlostí až 60 snímků za sekundu. V devátém díle bylo popsáno, jak co nejlépe načítat data z akcelerometru, v jedenáctém zase například to, jak řešit ve hrách české texty a lokalizaci do více jazyků. Tentokrát budeme pokračovat v podobném duchu a tento užitečný seznam návodů si rozšíříme o další položky.

Více barev na displeji

Na Windows Phone se ve výchozím nastavení všechny aplikace vykreslují jen s 16bitovou barevnou hloubkou. Je to z důvodu optimalizace výkonu (telefon musí držet v paměti a vykreslovat jen textury poloviční velikosti) a z důvodu kompatibility. I když se ve většině současných telefonů nachází displej s podporou 32 bitů, minimální hardwarové požadavky WP7 povolují i méně kvalitní 16bitové displeje.

-

Naše aplikace nebo hry spuštěné na reálném telefonu mohou místo barevných přechodů zobrazovat jen nepěkné pruhy. Tohoto neduhu se lze zbavit už částečně v počítači, pokud se v grafickém editoru obrázky už předem převedou do 16 bitů a aplikuje se na ně dithering (roztřesení bodů). Nasimulovat barevnou grafickou hloubku umí například editor Paint.NET spolu s pluginem Simulate Color Depth. Možný výsledek si můžete prohlédnout na přiloženém obrázku. Na kvalitnějších monitorech by mezi levou a pravou třetinou neměl být vidět téměř žádný rozdíl (obrázek si můžete zkusit přiblížit).

Tento problém se dá naštěstí vyřešit i jednodušeji, barevná hloubka se může přepnout na 32 bitů přímo při vytváření aplikace nebo hry. V Silverlightu i v XNA se to dělá trochu jinak. Pro aplikace v Silverlightu je potřeba přidat do souboru WMAppManifest.xml do tagu App řetězec BitsPerPixel=“32″.

Pro hru v XNA je místo toho potřeba doplnit určitý kód do události graphics.PreparingDeviceSettings, podobně, jako když se nastavovalo vykreslování 60 FPS. Do konstruktoru Game1() se vloží toto volání:

graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);

A do vygenerované metody se doplní potřebné nastavení. Celý její kód bude vypadat takto:

void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
    var pp = e.GraphicsDeviceInformation.PresentationParameters;
    pp.BackBufferFormat = SurfaceFormat.Color;
}

Ještě je dobré dodat, že v emulátoru tento problém se špatným zobrazením barevných přechodů nebude nastávat. V něm se grafika bude zobrazovat vždy ve standardní 24bitové hloubce (8 bitů na kanál = 256 hodnot pro každou barvu R, G, B).

Zakázání vyhlazování obrázků

V XNA je ve výchozím nastavení zapnuté vyhlazování textur. Toto chování se nám většinou hodí, především zmenšené obrázky díky tomu vypadají lépe. Pokud se ale rozhodneme naprogramovat hru, která by měla vypadat co nejvíce “old school”, může se nám hodit toto vyhlazování vypnout. Obrázky potom budou mít vždy ostré hrany, i když budou zvětšené. Pro aplikaci tohoto nastavení stačí do volání spriteBatch.Begin(); doplnit několik dalších parametrů:

spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);

Jak si můžeme všimnout, objektu typu SpriteBatch se dá nastavit i několik dalších možností, například jestli má být aplikována poloprůhlednost, nebo jak mají být objekty vůči sobě řazeny při vykreslování. Podrobnější informace o těchto parametrech se dají najít například v knížce XNA Game Programming Recipes od Riemera Grootjanse (ve třetí kapitole).

-

Rychlejší načítání obrázků

Už na začátku tohoto seriálu jsme si zmiňovali, že načítání obrázků pomocí Content Pipeline nemusí být na Windows Phone vždy úplně nejideálnější. Pokud velikost stran obrázků neodpovídá mocninám dvojky, při jejich kompilaci do projektu se u nich neprovádí komprese. To znamená, že mohou obrázky z původních stovek kB (například ve formátu .png) narůst až na hodnoty několika MB. Za následek to má neúměrné zvětšení velikosti výsledného XAP balíčku, tyto textury se také budou mnohem pomaleji načítat při každém spouštění hry. Při použití několika velkých obrázků na pozadí může tato doba na reálném telefonu narůst až na několik sekund.

Musíme pamatovat na omezení, aby si mohli uživatelé stáhnout hru z Marketplace přes mobilní internet, neměla by být větší, než 20 MB. Maximální velikost hry potom může být až 225 MB. Podmínky pro přijetí do Marketplace také stanovují, že by naše hra měla být schopna do 5 sekund nastartovat alespoň na úvodní obrazovku, do 20 sekund by už ji mělo být možné bez problémů používat.

Při kompilaci obrázků do projektu lze kompletně obejít mechanismus Content Pipeline a jejich načítání si řešit po svém. Použije se přístup, který například popisoval na svém blogu Jake Poznanski. Potřebným souborům je potřeba v paletce Properties přepnout parametr Build action na None a parametr Copy to Output Directory na Copy if newer. Tyto obrázky potom nebudou zpracovávány pomocí Content Pipeline, ale budou přímo zkopírovány do výsledného balíčku. Pro jejich načítání potom bude sloužit metoda LoadTextureFromStream(). Tu si budeme moci připravit například ve statické třídě Operations. Tato metoda bude také definována jako statická, díky tomu bude moci být volána odkudkoliv z projektu.

Kompletní třídu Operations si můžete stáhnout odsud. Můžete si ji vložit do projektu, pouze byste měli změnit na jejím začátku uvedený namespace na jmenný prostor vašeho projektu. Načtení obrázku potom bude moci být zavoláno v metodě LoadContent() ve třídě Game1 takto:

obrazek = Operations.LoadTextureFromStream(GraphicsDevice, "Content\\obrazek.png");

Pro načítání velkých obrázků do projektu může být tento způsob opravdu užitečný. Musíme si ale uvědomit, že tímto přístupem přicházíme o všechny ostatní výhody objektu Content. Budeme si muset řešit sami, aby se více stejných obrázků do projektu načítalo jen jednou, stejně tak si budeme muset udržovat seznam všech textur načtených tímto způsobem, pokud je například budeme chtít později odnačíst najednou.

Komponenta FPS

Pro ladění her se nám také bude určitě hodit komponenta DisplayFramerate, která bude na displej vykreslovat aktuální snímkovací frekvenci. Se znalostí předchozích dílů, odkazovaných videotutoriálů, případně článků na serveru vbnet.cz byste už měli být schopni si ji sami navrhnout. Pro kontrolu sem přikládám její kompletní kód, můžete si ho stáhnout odsud.

Soubor si vložte do projektu, opět si v něm změňte namespace. Tato třída funguje jako samostatná komponenta. Obsahuje metody LoadContent(), Update(), Draw()…, stejně jako třída Game1. Protože dědí od třídy DrawableGameComponent, znamená to, že tyto její metody jsou volány automaticky, hned po metodách stejného názvu ve třídě Game1. Pro její aktivaci stačí přidat do konstrukturu třídy Game1 jediný řádek, všechno ostatní už bude fungovat automaticky:

Components.Add(new DisplayFramerate(this));

Můžete si tuto komponentu prohlédnout, jak je naprogramovaná. Obsahuje vlastní Content Manager, to znamená, že její obsah je udržován v paměti nezávisle na tom, jaká je zobrazena herní obrazovka, nebo jaký je načtený level. Pro vykreslování textu je použit standardní objekt typu SpriteFont. Pro kompletní funkčnost této komponenty je tedy ještě potřeba si přidat do složky Content projektu nový soubor typu Sprite Font, s názvem FpsFont (v něm si můžete zvolit například velikost písma a styl).

Aby tato komponenta fungovala korektně, je také potřeba si zkontrolovat, že se nám ve třídě Game1 na konci metod Initialize(), Update() a Draw() nachází volání base.Initialize(), base.Update() apod. Právě tyto příkazy nám zaručí, že budou zavolány metody s odpovídajícími názvy u všech komponent, které byly přidány do projektu.

Když si nyní spustíme hru, měla by být vidět v levém horním rohu displeje aktuální smínkovací frekvence. Tato hodnota FPS se nám bude samozřejmě lišit podle toho, jestli hra poběží na počítači v emulátoru, nebo na reálném telefonu. Na telefonu bude většinou vykreslování pomalejší.

-

V příštím díle budeme v podobném seznamu tipů a triků pokračovat, povíme si například, jak načítat do hry vstup z klávesnice, nebo jak si jednoduše ukládat a znovu načítat nastavení hry.

Tomáš Slavíček

2 komentáře

  1. Tomáš Slavíček (neregistrovaný)

    Doplnění ke článku: Pokud používáte hybridní projekt (kombinaci Silverlightu a XNA), přepnutí vykreslování na 32 bitů provedete v metodě OnNavigateTo(…), nastavením položky SharedGraphicsDeviceManager.Current.PreferredBackBufferFormat = SurfaceFormat.Color;

    • Tomáš Slavíček (neregistrovaný)

      Oprava: v případě kombinace Silverlight a XNA v jednom projektu je tento řádek potřeba vložit už do konstruktoru GamePage() v GamePage.xaml.cs

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *