Windows Phone Mango – Integracja Silverlight i XNA  

Udostępnij na: Facebook

Autor: Maciej Grabek

Opublikowano: 2011-07-18

Pobierz i uruchom

Wprowadzenie

Windows Phone oferuje możliwość tworzenia aplikacji w dwóch podstawowych technologiach – Silverlight i XNA. Do tej pory mogliśmy korzystać z pewnych możliwości oferowanych przez jedną technologię w aplikacjach stworzonych w innej technologii. Sprowadzało się to jednak do użycia pewnych przestrzeni nazw i klas, które były przez nie oferowane. Najnowsza odsłona platformy deweloperskiej daje możliwość połączenia tych dwóch platform w obrębie jednej aplikacji, a nawet  w ramach jednego widoku danej aplikacji, dając zupełnie nowe możliwości tworzenia aplikacji o rozbudowanej grafice wraz z wygodą tworzenia interfejsu użytkownika oferowanym przez Silverlight.

Po przeczytaniu tego artykułu poznasz nową funkcjonalność pozwalającą zintegrować aplikację stworzoną w Silverlight z możliwościami graficznymi XNA.

Kod źródłowy zawartych w tym artykule przykładów jest do pobrania tu.

Jak zacząć

Aby skorzystać z możliwości połączenia Silverlight i XNAw ramach jednej aplikacji, skorzystamy z szablonu widocznego na rysunku 1.

Rysunek 1. Szablon projektu aplikacji.

 

W tym celu wybieramy grupę projektów Silverlight for Windows Phone, a następnie wybieramy szablon Windows Phone 3D Graphics Application. Po jego wykorzystaniu uzyskujemy solucję, która znacząco różni się od znanych nam do tej pory rozwiązań dla Windows Phone. W standardowej solucji korzystającej z Silverlight mamy na początku tylko jeden projekt zawierający wszystkie niezbędne dla tego typu aplikacji elementy, takie jak plik startowy aplikacji (App.xaml), główna strona (MainPage.xaml), manifesty i ikonki wykorzystywane przez system. W przypadku rozwiązań opartych na XNA, mamy dwa projekty. Pierwszy zawiera elementy podobne do tych z Silverlight (przy czym mamy tu do czynienia z klasą gry w miejsce strony, a plik startowy jest definiowany dla systemu Windows lub konsol XBOX). Drugi projekt ma nazwę z postfiksem Content i służy do przechowywania wszystkich dodatkowych elementów wykorzystywanych przez grę (w ich skład wchodzą czcionki, obrazy, tekstury, modele obiektów, dźwięki itp.).

Nowy szablon projektu jest swego rodzaju połączeniem tych dwóch rozwiązań, gdyż zawiera trzy projekty. Pierwszy z nich zawiera aplikację stworzoną w Silverlight, drugi służy do przechowywania elementów dodatkowych dla XNA (z postfiksem Content), natomiast trzeci jest referencją do tego właśnie projektu. Struktura solucji widoczna jest na rysunku 2.

Rysunek 2. Struktura nowej solucji.

 

W projekcie SampleSilverlightAndXnaApplication oprócz strony startowej mamy również stronę o nazwie GamePage.xaml. Zawiera on przykład, w jaki sposób możemy wykorzystać silnik XNA do wyrenderowania grafiki. Podobnie jak w przypadku standardowych gier, musimy zwrócić uwagę na kilka podstawowych metod, które realizują cykl życia takiej gry. Metody te wraz z ich odpowiednikami z platformy XNA widoczne są w tabeli 1.

Metoda Silverlight Metoda XNA Przeznaczenie
OnNavigatedTo LoadContent Ładowanie zasobów
OnUpdate Update Odświeżenie stanu gry
OnDraw Draw Odrysowanie klatki
OnNavigatedFrom UnloadContent Zwolnienie zasobów

Tabela 1. Metody Silverlight wraz z ich odpowiednikami w XNA.

 

Metody OnUpdate oraz OnDraw są obsługą zdarzeń Update i Draw dla obiektu typu GameTimer, który jest tworzony i wykorzystywany wewnątrz tak przygotowanej strony xaml. Analogicznie do gier, będziemy w nich odpowiednio uaktualniać stan i rysować pojedynczą klatkę.

Gdy przyjrzymy się metodom OnNavigatedTo i OnNavigatedFrom, zauważymy w nich bardzo istotne (wręcz niezbędne) operacje na obiekcie SharedGraphicsDeviceManager widoczne poniżej.

/* OnNavigatedTo*/
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
/* OnNavigatedFrom*/
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

Ich zadaniem jest, odpowiednio, włączenie i wyłączenie renderowania grafiki przez XNA.  Po uruchomieniu projektu o domyślnej zawartości w rezultacie otrzymujemy stronę główną z przyciskiem Play, po wciśnięciu którego uzyskujemy efekt generowany przez XNA, czyli poruszający się po ekranie kwadrat widoczny na rysunku 3.

Rysunek 3. Wynik uruchomienia domyślnego projektu.

 

To nie wszystko

W tym momencie w obrębie aplikacji mamy zintegrowane dwie technologie na różnych stronach. Okazuje się jednak, że nic nie stoi na przeszkodzie, aby pójść krok dalej i wykorzystać interfejs użytkownika stworzony za pomocą Silverlight z grafiką generowaną przez XNA w ramach jednej strony.

Do tej pory strona wyświetlająca grafikę dzięki XNA nie zawierała żadnych elementów interfejsu Silverlight. Nie oznacza to, że takiej zawartości może tam nie być. W związku z tym do strony dodamy przycisk, który będzie odpowiadał za zmianę aktualnego koloru kwadratu poruszającego się po ekranie. W tym celu do pliku xaml dodajemy następujący kod:

<Grid>
    <Button Content="Change color" Height="72" HorizontalAlignment="Left" Margin="12,716,0,0" Name="btnChangeColor" VerticalAlignment="Top" Width="213" Click="btnChangeColor_Click" />
</Grid>

Obsługa przycisku wygląda następująco:

int selectedTexture = 0;
List<Texture2D> availableTextures = new List<Texture2D>();

protected override void OnNavigatedTo(NavigationEventArgs e)
{
…
availableTextures.Add(content.Load<Texture2D>("redRect"));
availableTextures.Add(content.Load<Texture2D>("yellowRect"));
availableTextures.Add(content.Load<Texture2D>("greenRect"));
…
}

private void btnChangeColor_Click(object sender, RoutedEventArgs e)
{
    selectedTexture++;
    if (selectedTexture >= availableTextures.Count)
    {
        selectedTexture = 0;
    }
}

W metodzie OnDraw wystarczy jeszcze skorzystać z tak przygotowanej tablicy tekstur. Realizuje to następująca linijka kodu:

spriteBatch.Draw(availableTextures[selectedTexture], spritePosition, Color.White);

Oczywiście należy również dodać odpowiednie obrazy do projektu *Content.

Okazuje się jednak, że po uruchomieniu aplikacji na ekranie nie ma dodanego przez nas przycisku. Musimy więc zastosować kolejny istotny element, a mianowicie klasę UIElementRenderer. Pozwala ona przekształcić interfejs użytkownika w teksturę tak, aby mógł on być wyświetlony przez XNA. W związku z tym dodajemy do kodu fragment widoczny poniżej:

UIElementRenderer uiRenderer;

public GamePage()
{
…
LayoutUpdated += new EventHandler(GamePage_LayoutUpdated);
}

void GamePage_LayoutUpdated(object sender, EventArgs e)
{
    int width = (int)ActualWidth;
    int height = (int)ActualHeight;
 
    if (width <= 0 || height <= 0)
        return;
 
    if (uiRenderer != null &&
        uiRenderer.Texture != null &&
        uiRenderer.Texture.Width == width &&
        uiRenderer.Texture.Height == height)
    {
        return;
    }
 
    if (uiRenderer != null)
        uiRenderer.Dispose();
 
    uiRenderer = new UIElementRenderer(this, width, height);
}

Dzięki tworzeniu obiektu uiRenderer w momencie zmiany layoutu aplikacji mamy pewność, że będzie on generował poprawny rezultat niezależnie od tego, jaki on będzie. W tym momencie możemy w metodzie OnDraw skorzystać z utworzonego renderera interfejsu użytkownika, modyfikując jej treść do widocznej poniżej:

private void OnDraw(object sender, GameTimerEventArgs e)
{
    // Draw the Silverlight UI into the texture
    uiRenderer.Render();
 
    SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
 
    // TODO: Add your drawing code here
 
    // Draw the sprite
    spriteBatch.Begin();
    spriteBatch.Draw(availableTextures[selectedTexture], spritePosition, Color.White);
 
    // Draw the UI on top of the scene
    spriteBatch.Draw(uiRenderer.Texture, Vector2.Zero, Color.White);
    spriteBatch.End();
}

W tym momencie po uruchomieniu aplikacji na telefonie mamy do dyspozycji nie tylko dodany przycisk, lecz również możliwość interakcji z użytkownikiem, która w wyniku zmienia kolor poruszającego się po ekranie prostokąta. Widać to na rysunku 4.

Rysunek 4. Wynik połączenia renderowania grafiki przez XNA wraz z interfejsem Silverlight.

 

Podsumowanie

W tym artykule omówiliśmy sposób na połączenie wygody oprogramowania interakcji z użytkownikiem, którą oferuje Silverlight, z możliwościami generowania grafiki oferowanymi przez XNA. Jak widać na przedstawionych przykładach, połączenie to nie jest trudne, a dzięki tej funkcjonalności tworzenie między innymi gier jest dużo prostsze i szybsze.