TOPlist

Vyvíjíme pro WP v XNA: Rotace displeje, změna rozlišení (5. díl)

Pátý díl seriálu o tvorbě her v XNA vás seznámí s možnostmi rotace displeje, změny rozlišení či spuštění na celou obrazovku. Jdeme programovat!

Jak jsme si odzkoušeli na konci minulého dílu (zobrazit všechny díly seriálu), ve výchozím nastavení se nám hra na Windows Phone spustila “na šířku” displeje (jako bychom drželi telefon naležato). Navíc také ani nebyla zobrazena na celou obrazovku. Toto chování si teď budeme chtít upravit, poslouží nám k tomu konstruktor Game1(). V něm už máme některé parametry předvolené, doplníme si tam ještě:

graphics.IsFullScreen = true;

Otáčení displeje podle orientace telefonu funguje na Windows Phone z velké části automaticky. Aniž bychom museli něco měnit, hra si bude sama vybírat ze zobrazení “napravo naležato” a “nalevo naležato”. Toto chování půjde ovlivnit dvěma způsoby. Zaprvé si do konstruktoru Game1() budeme moci přidat tyto dva řádky:

graphics.PreferredBackBufferWidth = 480;
graphics.PreferredBackBufferHeight = 800;

Těmito příkazy si nastavíme parametry grafické vyrovnávací paměti – zadává se velikost oblasti, do které potom půjde kreslit. Pokud bude zadaná šířka (width) menší, než výška (height), automaticky se na telefonu zvolí zobrazení na výšku. Když si tyto dvě hodnoty prohodíme, hra se nám automaticky spustí na šířku.

-

Pokud budeme chtít, aby bylo na telefonu možné zobrazit jen určité povolené orientace, využijeme k tomu položku SupportedOrientations, například takto:

graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;

Zobrazení na displeji se potom bude moci otáčet jen na jeden z těchto zvolených způsobů. Když si potom následně (například během hry) budeme chtít ověřit, na jaký směr je displej aktuálně otočen, zjistíme to z položky GraphicsDevice.PresentationParameters.DisplayOrientation. Pokud nás bude zajímat skutečná orientace telefonu (nezávisle na povolených orientacích displeje), tu najdeme v položce GameWindow.CurrentOrientation.

 Většinou si zobrazení naší hry omezíme tak, aby byla po celou dobu běžela jen na šířku, nebo jen na výšku. Nebudeme si tak muset připravovat dva různé obrázky na pozadí, odlišné rozmístění objektů apod.Pokud v naší hře přesto budeme chtít využívat všech orientací displeje, budeme to moci udělat doplněním funkcionality ke správné události. Pro naši testovací hru si můžeme vložit do konstruktoru tyto řádky:

graphics.SupportedOrientations = DisplayOrientation.Portrait | DisplayOrientation.LandscapeLeft;
Window.OrientationChanged += new EventHandler<EventArgs>(Window_OrientationChanged);

První řádek jsme si už vysvětlili. Ve druhém příkazu si nastavujeme, jakou metodou bychom chtěli obsloužit událost Window.OrientationChanged. Když tento kód píšeme, stačí nám napsat “Window.OrientationChanged +=” a potom smáčknout dvakrát klávesu Tab. Potřebný zbytek řádku se nám sám doplní a správná metoda se nám automaticky vygeneruje. My už si do ní jen doplníme potřebný kód. Kompletní metoda bude vypadat takto:

void Window_OrientationChanged(object sender, EventArgs e)
{
    if (GraphicsDevice.PresentationParameters.DisplayOrientation == DisplayOrientation.Portrait)
    {
        graphics.PreferredBackBufferWidth = 480;
        graphics.PreferredBackBufferHeight = 800;
    }
    else {
        graphics.PreferredBackBufferWidth = 800;
        graphics.PreferredBackBufferHeight = 480;
    }
    graphics.ApplyChanges();
}

Tato metoda se nám vždy zavolá, když zařízení natočíme na nějakou stranu.Nejdřív si v ní zjistíme aktuální orientaci displeje, potom podle toho změníme parametry grafického zařízení. Na konci zavoláme metodu ApplyChanges(), aby se nám všude správně promítly všechny naše nastavené parametry. Případně si sem ještě doplníme volání dalších našich metod, ve kterých si přenastavíme správné pozice našich herních objektů apod.

Jinak, i když nám naše hra bude běžet na výšku, nebo na šířku, vždy budeme mít správně přepočítané souřadnice. Veškeré tohle přepočítávání se děje interně, nijak to nezpomaluje naše vykreslování. Pokud si naklopíme telefon podle zadané orientace, bod x=0,y=0 budeme mít vždy v jeho levém horním rohu. Skutečnou šířku a výšku obrazovky pak budeme mít uloženou v položkách GraphicsDevice.Viewport.Width a .Height. Pokud nás bude zajímat aktuální poměr stran obrazovky, ten najdeme v položce GraphicsDevice.Viewport.AspectRatio.

-

Další zajímavou vlastností Windows Phone je, že se při nastavování rozlišení displeje nemusíme omezovat jen na konkrétní hodnotu 800×480. Rozlišení si můžeme zvolit i menší, automaticky potom bude přepočítáno na výsledné rozlišení displeje. Výhodou je, že hra potom nebude muset renderovat tolik pixelů. Zvláště u některých 3D her se takto může o hodně zvýšit rychlost vykreslování. Pro srovnání, při omezení na 600×360 pixelů bude potřeba vyrenderovat jen 56% pixelů, oproti plnému rozlišení. Takto snížené rozlišení většinou uživatelé neradi vidí,u nějakých rychle se hýbajících her ale rozdíl nemusí být ani poznatelný. Navíc získáme zadarmo určité “vyhlazování” hran. Toto převzorkování displeje se opět děje automaticky přímo na grafické kartě a neubírá nám nic z výkonu. Pokud si zvolíme rozlišení s jiným poměrem stran, než má displej, doplní se nám na okraje černé pruhy.

Hry standardně na Windows Phone běží maximální rychlostí 30 snímků za sekundu. Je to takový kompromis, přeci jenom tyto telefony mají nižší výkon, než Xbox 360 nebo průměrné PC, navíc také se tím alespoň trochu ušetří baterie. Na malém displeji většinou ani vyšší snímkovací frekvenci neočekáváme (LCD displeje některých značek telefonů dokonce např. běží jen na 50 Hz). Maximální rychlost nastavuje parametr TargetElapsedTime v konstruktoru hry, ve výchozím stavu má takovouto hodnotu:

TargetElapsedTime = TimeSpan.FromTicks(333333);

S Mango aktualizací přišla ale ještě jedna novinka, explicitně si můžeme zapnout, aby naše hra běžela až 60 snímků za sekundu. U některých rychlých akčních her s jednoduchou grafikou se to může hodit. Pro její aktivaci je potřeba změnit parametr TargetElapsedTime na 166666 a přidat implementaci události graphics.PreparingDeviceSettings:

TargetElapsedTime = TimeSpan.FromTicks(166666);
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);

Do této metody (opět se nám vygeneruje po stisku dvakrát Tab) si potom doplníme určení prezentačního intervalu. Nastavení PresentInterval.One znamená, že se má použít nativní snímkovací frekvence displeje. Celá metoda bude vypadat takto:

void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
    e.GraphicsDeviceInformation.PresentationParameters.PresentationInterval = PresentInterval.One;
}

Naše hra by nám teď měla běžet rychlostí až 60 FPS. Nějakou komponentu, která nám na displej bude vypisovat aktuální snímkovací frekvenci, si možná přidáme do projektu až později. Zatím tomu budeme muset věřit. Ještě bych také doplnil, pokud jste na hře pracovali už v době před Mangem a teď si ji jen chtěli upravit pro vyšší rychlost (tj. původně jste si projekt založili pro SDK verze 7.0), zatím vám 60 FPS nepoběží. Budete si ještě muset v paletce Solution Explorer kliknout pravým tlačítkem na projekt a zvolit Upgrade to Windows Phone 7.1.

Zajímavých vlastností XNA na Windows Phone potkáme určitě ještě hodně. Příště si už konečně prozradíme, jakou hru budeme společně vytvářet a naplno sepustíme do programování herní logiky.

Autor článku Tomáš Slavíček
Tomáš Slavíček

Kapitoly článku