(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

XNA for Silverlight developers: Part 12 - Mango (1)

(8 votes)
Peter Kuhn
>
Peter Kuhn
Joined Jan 05, 2011
Articles:   44
Comments:   29
More Articles
4 comments   /   posted on Jun 08, 2011
Categories:   Gaming , Windows Phone , General
Are you interested in creating games for Windows Phone 7 but don't have XNA experience?
Watch the recording of the recent intro webinar delivered by Peter Kuhn 'XNA for Windows Phone 7'.

This article is compatible with Windows Phone "Mango".
Latest update: Aug 1, 2011.

Although it'll take some months until the final release, the upcoming update for the Windows Phone 7 platform has already drawn a lot of attention, both in the developer community as well as for customers. We were able to see demonstrations of some of the new features early, for example at Microsoft's conference MIX, but the real excitement started when a beta version of the developer tools was released to the public a few weeks ago. In this article we'll take a look at what will change regarding game development; and if you haven't had time to get your teeth into the upcoming features and improvements yet, you'll be surprise just how much is in the box for us with this update.

Integration of Silverlight and XNA

This is one of the biggest improvements of the Mango update, and something that developers have been crying for since the very first moments of Windows Phone 7. Some – like the creative minds in that linked thread – have invented workarounds to enable this feature in some way, but of course all these efforts were futile, since the certification requirements explicitly forbid mixing both technologies. This will change with Mango, in a controlled way that allows integration of both technologies within the same application. Let's see how that works.

Creating the Application

To set up a project that combines Silverlight and XNA, you can use one of the two new templates that come with the beta developer tools for this purpose. The first one can be found in the "Silverlight for Windows Phone" node of the "New Project" dialog of Visual Studio and is named "Windows Phone 3D Graphics Application":

image

The other template is located in the "XNA Game Studio 4.0" node and named "Windows Phone Rich Graphics Application":

image

When you compare both templates, you can see that they create the same project structure. The difference is that the template that can be found in the Silverlight node adds some minimal game content (a moving rectangle) whereas the template in the XNA node only has the usual blank cornflower blue screen. If you want to learn about the new feature I therefore recommend using the first template, as the pre-built content helps you understand the involved concepts a bit better.

The Project Structure

The first interesting thing to note when you look at the project is the structure of the solution itself:

image

As you can see, three projects are created:

  • A Silverlight project that is set as the startup project in the solution.
  • An XNA content project.
  • An XNA class library project.

The reason for this setup is that on the one hand Silverlight always takes the leading role in an integrated XNA/Silverlight application (which might actually be a big advantage for those of you coming from Silverlight development). On the other hand, Silverlight doesn't know anything about XNA content and how to handle it. To solve this problem, the XNA class library is used as "the glue" between the two, meaning the content project is processed by the class library, and Silverlight in turn uses the class library to get access to the processed content.

image

Apart from that there's nothing special to the XNA parts in this structure. You can use the content project just like we have learned in part 1 of this series. And although you can add code to the XNA class library, you don't need to and simply can leave it completely empty if you like.

The SharedGraphicsDeviceManager

Like I just wrote, Silverlight takes the lead in the concept of integrated XNA/Silverlight apps, which means that the navigation features and concept of pages of normal Silverlight applications fully apply, and none of the central infrastructure elements of XNA, like the Game or GameComponent classes, are used. The idea instead is to explicitly tell the runtime when you want to use XNA rendering, on a per-page basis.

To this end, a new assembly Microsoft.Xna.Framework.Interop is introduced which contains the SharedGraphicsDeviceManager class. That class enables you to use XNA's immediate rendering mode in your Silverlight application and provides access to a graphics device through a property named the same. In the templates, the manager is declared in the application lifetime objects in the App Xaml, and from there on can be accessed using a static "Current" property on the manager class throughout your application, whenever you need to access it.

 1: <Application.ApplicationLifetimeObjects>
 2:     <!--Required object that handles lifetime events for the application-->
 3:     <shell:PhoneApplicationService 
 4:         Launching="Application_Launching" Closing="Application_Closing" 
 5:         Activated="Application_Activated" Deactivated="Application_Deactivated"/>
 6:         
 7:     <!--The SharedGraphicsDeviceManager is used to render with the XNA Graphics APIs-->
 8:     <xna:SharedGraphicsDeviceManager />
 9: </Application.ApplicationLifetimeObjects>

The pattern to activate XNA rendering is to turn on the so-called sharing mode when the user navigates to a page that contains XNA content, and to turn it off again once the user navigates away. For this, an extension method "SetSharingMode" was added to the GraphicsDevice class.

 1: protected override void OnNavigatedTo(NavigationEventArgs e)
 2: {
 3:     // Set the sharing mode of the graphics device to turn on XNA rendering
 4:     SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
 5:  
 6:     base.OnNavigatedTo(e);
 7: }
 8:  
 9: protected override void OnNavigatedFrom(NavigationEventArgs e)
 10: {
 11:     // Set the sharing mode of the graphics device to turn off XNA rendering
 12:     SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
 13:  
 14:     base.OnNavigatedFrom(e);
 15: }

It's important to activate sharing mode before you do anything XNA related in your application (like loading content or drawing things), or you will end up with exceptions.

The "Game Loop"

Speaking of drawing things, you might wonder where you put all your update and drawing logic now that there's no Game class anymore? The solution to this is another core component : the GameTimer class. When you look at the members of that class you should see some familiar faces. It has Draw and Update events, and the GameTimerEventArgs passed into the event handlers has ElapsedTime and TotalTime properties. This is all very similar to the update and draw mechanism of normal XNA games and the information the GameTime class provides. The game timer has additional features though, for example it is also responsible for setting the desired frame rate (corresponds to the TargetElapsedTime property of the Game class). A typical setup of the GameTimer hence looks like:

 1: public GamePage()
 2: {
 3:     InitializeComponent();
 4:  
 5:     // Create a timer for this page
 6:     timer = new GameTimer();
 7:     timer.UpdateInterval = TimeSpan.FromTicks(333333);
 8:     timer.Update += OnUpdate;
 9:     timer.Draw += OnDraw;
 10: }

Like other timers you know from Silverlight and .NET, this one has to be started to actually work too, and it can and also should be stopped in certain situations. Once again the pattern is to activate the timer when the user navigates to an XNA-enabled page, and to stop it when the user navigates away. Combined with the shared graphics devices manager, the code then looks like:

 1: protected override void OnNavigatedTo(NavigationEventArgs e)
 2: {
 3:  
 4:     // Set the sharing mode of the graphics device to turn on XNA rendering
 5:     SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
 6:  
 7:     // Start the timer
 8:     timer.Start();
 9:  
 10:     base.OnNavigatedTo(e);
 11: }
 12:  
 13: protected override void OnNavigatedFrom(NavigationEventArgs e)
 14: {
 15:     // Stop the timer
 16:     timer.Stop();
 17:  
 18:     // Set the sharing mode of the graphics device to turn off XNA rendering
 19:     SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
 20:  
 21:     base.OnNavigatedFrom(e);
 22: }

In the Update event handler you can place all your update logic like you would in the Update override of the XNA Game class, for example to move your sprites, compute AI moves and similar things. The same is true for the Draw event handler. Here you use the shared graphics device manager to get access to the required GraphicsDevice instance that you need to e.g. clear the screen and draw your primitives. The rest of the method again works like in normal XNA games.

… and the Rest

When you look at the template that we're using, you can find a few additional elements you know from your XNA games here. The App class for example has a ContentManager instance. This central place of definition allows you to access it from anywhere to load your game content. In fact, you are free to load your content at any time you like, as long as you have activated sharing mode before. The recommendation though is to also load the content in the OnNavigatedTo overload of a page where it is safe to do and doesn't interfere with the update and draw events of the timer.

Another thing to note is the "InitializeXnaApplication" method in the App class which creates another GameTimer instance to call the Update method of the FrameworkDispatcher. This is not particularly new to the Mango update. If you wanted to use certain XNA features like the advanced sound playback in your Silverlight application before, you already had to use the FrameworkDispatcher manually to make this work. The template only uses the new GameTimer class to set this up. It's nice to know though that everything's already prepared to also use sound and other XNA features in your mixed XNA/Silverlight app.

Rendering Silverlight and XNA on the Same Page

Without writing any code, the new templates already show how you can mix Silverlight and XNA pages in the same application. But wait, there's more! You can also mix Silverlight content with XNA on the same page. This brings us to another important new class in the Mango update, the UIElementRenderer. This class has only one purpose: to render a Silverlight UIElement into a texture. The texture in turn can then be used in your draw method to be used and rendered in any way you like. To demonstrate this feature, I add the following code to the "GamePage.xaml", which didn't contain any elements until now:

 1: <Grid x:Name="LayoutRoot">
 2:     <TextBlock HorizontalAlignment="Center"
 3:                 VerticalAlignment="Center"
 4:                 Text="Silverlight and XNA"
 5:                 FontSize="36"
 6:                 RenderTransformOrigin="0.5, 0.5">
 7:         <TextBlock.RenderTransform>                 
 8:             <RotateTransform x:Name="Rotate" />
 9:         </TextBlock.RenderTransform>
 10:         <TextBlock.Triggers>
 11:             <EventTrigger RoutedEvent="FrameworkElement.Loaded">
 12:                 <BeginStoryboard>
 13:                     <Storyboard>
 14:                         <DoubleAnimation Storyboard.TargetName="Rotate"
 15:                                             Storyboard.TargetProperty="Angle"
 16:                                             From="0"
 17:                                             To="360"
 18:                                             Duration="0:0:2.0"
 19:                                             RepeatBehavior="Forever" />
 20:                     </Storyboard>
 21:                 </BeginStoryboard>
 22:             </EventTrigger>
 23:         </TextBlock.Triggers>
 24:     </TextBlock>
 25: </Grid>

As you can see this looks like normal Silverlight content. I added a grid and a text block. The latter one has a rotate transform and a storyboard that changes the rotation angle so the text does a whole 360 degrees spin in two seconds. Would you run the application at this point, you could not see anything; although the content is defined in the Xaml, rendering of this page is handled by XNA, so the Silverlight bits don't affect what's visible on the screen. To make this work, I have to use a UIElementRenderer:

 1: UIElementRenderer uiElementRenderer;
 2:  
 3: ...
 4:  
 5: protected override void OnNavigatedTo(NavigationEventArgs e)
 6: {
 7:     ...
 8:  
 9:     // create the UI element renderer that covers the whole page
 10:     uiElementRenderer = new UIElementRenderer(LayoutRoot,
 11:         SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Width,
 12:         SharedGraphicsDeviceManager.Current.GraphicsDevice.Viewport.Height);

The constructor of the UIElementRenderer expects the element to render, and the dimensions of the texture to use as a target. In my case I'm simply using the root element and a texture the size of the screen. Of course you can optimize this and only render the actual required parts of the visual tree to the screen, but that's not necessary in this example.

The fact that the UIElementRenderer is fixed to a certain width and height should give you a clue that you need to recreate it e.g. once the layout changes (screen orientation or similar) – you cannot change its texture dimensions after you created it. The important part is that any existing renderer needs to be cleaned up using the Dispose method before you throw it away and recreate it. The same is true if e.g. the user navigates away from the page. Just make sure you be nice and free the resources used by the renderer when necessary.

The last thing to do is to actually render the Silverlight content, first into the UIElementRenderer's internal textures, and then (using that texture) onto the screen. For the first part the renderer has a Render method, and for the second part you can use a normal sprite batch and access the renderers Texture property.

 1: // let the UI element renderer render the current state
 2: // of the Silverlight content to its texture
 3: uiElementRenderer.Render();
 4: spriteBatch.Draw(uiElementRenderer.Texture,
 5:     Vector2.Zero,
 6:     Color.White);

To draw 2D Silverlight elements on top of your other game content, you would make drawing this texture the very last thing in your Draw event handler (so it is rendered on top of everything else). The result is something like this:

image

The red square is completely handled by XNA (it's actually a red texture from the XNA content project that is moved around in the Update event handler), whereas the text is the Silverlight content rendered on top. The animation of that text is taken care of by Silverlight's animation system. Once again there's potential for optimization – e.g. if you know the Silverlight content's visual appearance has not changed, you do not re-render the texture in each frame.

Even though it looks simple, for other scenarios handling the Silverlight rendering can become more complex. Nick Gravelyn has made a nice helper for full-screen scenarios that deals with some of these difficulties.

Advantages

This feature of integrating XNA with Silverlight has some obvious and some not so obvious advantages and creates new possibilities. One of the obvious uses is to create user interfaces. As we have learned in part 10 of this series creating even simple controls in XNA is tedious and requires a lot of work compared with Silverlight. Some more advanced features like text input can even require a tremendous amount of code on your side if you're trying to integrate it nicely into your game. The possibility to use existing Silverlight UI features to create menu pages for XNA games, or even to create HUD overlays or similar on top of your game content is a great improvement and will speed up those parts of game development a lot.

Not so obvious improvements are that this feature now enables scenarios that previously simply were not possible with XNA, like using the WebBrowser control or embed video directly in your game. To read more about the revised decision process of choosing between XNA and Silverlight, click here.

Drawbacks

There are also some potential drawbacks of this new feature. One is that if you are a developer who targets all "three screens" (desktop, console, phone) and try to share as much code as possible between those platforms, mixing Silverlight and XNA can even become a handicap, because it is a feature unique to the phone and doesn't port very well.

Another issue is that if you have already invested some time in developing your game in XNA, you may now have to spend some more time to migrate to the new concept. For example, as I mentioned some elements like game components cannot be used in hybrid applications, so you have to at least partly rewrite those and/or change your game code structure. More information and tips on moving from the Game class to XNA/Silverlight can be found in this migration guide.

Conclusion

Even though it has some drawbacks and it's not perfect in every detail (yet), the possibility to mix XNA and Silverlight content has been received extremely well by most developers. I hope that this article has provided some insights into the basic ideas and concepts, and also sparked some ideas how you can use that feature to speed up your development or create exciting new things. Let me if you have any questions or feedback in the comments below, or by contacting me directly. You can download the sample project here:

Download source code


Subscribe

Comments

  • leoInTx

    Re: XNA for Silverlight developers: Part 12 - Mango (1)


    posted by leoInTx on Aug 05, 2011 16:41

    Will you be able to embed the browser control in an xna app??  thanks!

  • MisterGoodcat

    Re: XNA for Silverlight developers: Part 12 - Mango (1)


    posted by MisterGoodcat on Aug 05, 2011 18:34

    I think for pure XNA applications nothing will change regarding that. You will be able to use it in combined Silverlight/XNA apps, but not in XNA.

  • ashish_0x90

    Re: XNA for Silverlight developers: Part 12 - Mango (1)


    posted by ashish_0x90 on 10:30

    Hi Peter,

    Great article!!. However i have following query, In Mango, is it allowed to link to a pure silverlight based assembly (.dll) from within a otherwise pure XNA application, from app certification perspective.

  • MisterGoodcat

    Re: XNA for Silverlight developers: Part 12 - Mango (1)


    posted by MisterGoodcat on 13:05

    Yes it is. If you did not violate the requirements about mixing Silverlight UI and XNA, that was also possible pre-Mango. That requirement (4.2.5) is still in place; so even for Mango, if you want to mix Silverlight UI and XNA, you have to follow the above setup; but referencing and using other components written in SL is not a problem.


Add Comment

Login to comment:
  *      *       

From this series