Digital Transfusion

Putting the internet in your veins!

XNA Development: Demo code and presentation

no comment

Thanks to everyone that attended my presentation on “XNA Development Creating Games For Windows, Xbox 360, and Windows Phone 7.” As promised, here is both the source code and the power point presentation. Feel free to ask any questions you may still have, and I will get back with you as soon as I can.

This is a sample pong XNA game that works on Xbox 360, WP7, and Windows.

Source code download it here
Powerpoint presentation download it here

The way I see CacheMode in Silverlight

2 comments

If you have been doing any kind of Silverlight or WP7 work then you are probably already aware of a property called CacheMode on all of your controls. This magical little property can improve the speed of your applications by caching the visuals instead of redrawing them every time.

This was EXTREMELY noticeable when I converted Zero Gravity to WP7. My jaw literally dropped to the floor the first time I ran the game. The speed was far from adequate… In fact the game was barely able to run. Here I saw demos at Mix with a device that were able to run full 3D without so much as a flicker; and here this very, very simplistic game was being brought to its knees. There is hardly any animation the screen is full of mostly static content. So how could this be performing so very poorly?

Of course with a liberal dose of the CacheMode=”BitmapCache” the application soon started to perform pretty well. But, did I use CacheMode correctly? Should I have included it on more elements? None of them? All of them? I am left with a problem of knowing “when is the application optimized to its peak efficiency?” This begs the question…

Why do we need CacheMode=”BitmapCache?”

Asking a developer to handle caching like this is like asking a  2nd grader to do their homework and then leaving them alone and unsupervised. Sure, some kids will buckle down and get their homework done, but more often then naught the 2nd grader is going to get distracted. This could make them take longer to do their homework or worse yet they won’t do it at all. (I know playing a game on Xbox would seem pretty awesome compared to doing homework!)

Caching is something that should absolutely be taken care of by the framework. Nobody is going to know performance enhancements better than the developers that create the API’s we all know and love. Go watch Seema’s performance presentation at Mix10 for an example of how complicated performance can be. Sure, there may be edge case scenarios that require developers to reach in and take the reigns, but by taking the initial performance enhancements out of the hands of the developers you ensure that EVERYONE will participate “out of the box.” Seema’s presentation illustrates how very fragile the current Silverlight rendering pipeline is. Anything we can do to remove “problem points” can only help the framework in the long run.

There are many Silverlight (desktop) applications in circulation today do not implement CacheMode at all. They didn’t need to because the applications ran fast enough on today’s beefy computers. But imagine if all of these applications were optimized from the start! The UI could be more responsive and CPU usage could be reduced without the end developers writing a single line of code, and THAT is what we should be striving for.

Lets hope that future versions of Silverlight take control so everyone participates. Opt-out, not Opt-In.

Wp7 Manifest validation fails?

2 comments

I just had the oddest error on a new project (nothing added by me) WP7 project.

  • Manifest validation fails: Error code: ValidationInvalidAuthor .

At least the error is semi descriptive, lets go check the manifest….

<?xml version="1.0" encoding="utf-8"?>

<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment"
            AppPlatformVersion="7.0">
    <App xmlns=""
         ProductID="{eb48b96b-98f1-4179-9d44-0c7541f756ee}"
         Title="DigitalTransfusion.Silverlight.Wp7.Project.Client"
         RuntimeType="Silverlight"
         Version="1.0.0.0"
         Genre="apps.normal"
         Author="DigitalTransfusion.Silverlight.Wp7.Project.Client author"
         Description="Sample description"
         Publisher="DigitalTransfusion.Silverlight.Wp7.Project.Client">
        <IconPath IsRelative="true"
                  IsResource="false">ApplicationIcon.png</IconPath>
        <Capabilities>
            <Capability Name="ID_CAP_GAMERSERVICES"/>
            <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
            <Capability Name="ID_CAP_IDENTITY_USER"/>
            <Capability Name="ID_CAP_LOCATION"/>
            <Capability Name="ID_CAP_MEDIALIB"/>
            <Capability Name="ID_CAP_MICROPHONE"/>
            <Capability Name="ID_CAP_NETWORKING"/>
            <Capability Name="ID_CAP_PHONEDIALER"/>
            <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
            <Capability Name="ID_CAP_SENSORS"/>
            <Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
        </Capabilities>
        <Tasks>
            <DefaultTask  Name ="_default"
                          NavigationPage="MainPage.xaml"/>
        </Tasks>
        <Tokens>
            <PrimaryToken TokenID="DigitalTransfusion.Silverlight.Wp7.Project.ClientToken"
                          TaskName="_default">
                <TemplateType5>
                    <BackgroundImageURI IsRelative="true"
                         IsResource="false">Background.png</BackgroundImageURI>
                    <Count>0</Count>
                    <Title>DigitalTransfusion.Silverlight.Wp7.Project.Client</Title>
                </TemplateType5>
            </PrimaryToken>
        </Tokens>
    </App>
</Deployment>

Well, it looks like I do have an author (Author="DigitalTransfusion.Silverlight.Wp7.Project.Client author") so what is going on here? Well it turns out there is a character limit 50 characters for an author.

So this got me thinking, I wonder what the the character limits are? Well, wonder no more!

  • Publisher = 50 characters
  • Author = 50 characters
  • Title = 80 characters

So if you get errors for ValidationInvalidPublisher, ValidationInvalidAuthor, or ValidationInvalidTitle, chances are that your strings are too long.

Zero Gravity: Moving to WP7

7 comments

In a previous post I released the source code to Zero Gravity. In this post I am going to dive in and explain the changes that had to be made to make the game ready for Windows Phone 7. I was actually surprised at how little actually had to change considering the code was originally written back when WPF/e was still walking around.

There can be only one!

The original game was written with a lot of MediaElements. The sound effects were loaded using something like this:

MediaElement toAdd = new MediaElement();
toAdd.SetSource(GetType().Assembly.GetManifestResourceStream(soundFileToPlay));

There are a couple of problems with this in Wp7. The first problem is that the MediaElement.SetSource method no longer accepts a type stream(even though the intellisense says it does).  Instead it requires an IsolatedStorageFileStream. Whether this was a bug, or an intentional change,  A quick fix would seem apparent:

IsolatedStorageFile v = IsolatedStorageFile.GetUserStoreForApplication();
if (!v.FileExists(musicFileToPlay))
{
    using (IsolatedStorageFileStream isfs =
                new IsolatedStorageFileStream(musicFileToPlay,
                FileMode.CreateNew, FileAccess.Write, v))
    {
        using (Stream s =
                this.GetType().Assembly.
                     GetManifestResourceStream(musicFileToPlay))
        {
            byte[] buffer = new byte[s.Length];
            s.Read(buffer, 0, buffer.Length);
            isfs.Write(buffer, 0, buffer.Length);
            s.Close();
        }
        isfs.Close();
    }
}
musicPlayer.SetSource(new
        IsolatedStorageFileStream(musicFileToPlay,
        FileMode.Open,
        FileAccess.Read, v));

Of course, you would notice that this effectively doubles the storage space needed for the audio files (once in the .xap, once in isolated storage). That isn’t a good thing, but with a little management you can make sure the application cleans up after itself…but there are more problems.

If you were to run this in the game, you would find that the background music would work. However nothing else would work. The movie transition between levels would fail and there would be no sound effects as you move around the boards.  Needless to say, it is a very bad user experience.

So what is going on?

One thing that a lot of developers forget about with regards to Silverlight on Windows Phone 7 is that you can only have 1 active media element. In fact I forgot about this little tidbit of information, and had to be reminded of this fact. (Thanks Bill!) For anyone else that needs a reminder, I recommend watching Davit Cutler’s presentation from MIX 2010.

So what is the solution to this? Well, on Windows Phone 7, there this is a little bleed over beteween XNA and Silverlight. The solution is to use the XNA framework to handle all the audio. For the ease of transition, I kept the movie inside the MediaElement (since I am allowed to have one).

To make this work, I added a reference to “Microsoft.Xna.Framework.” This gives us access to the  Microsoft.Xna.Framework.Audio.SoundEffect Class, which is used in XNA to play sound effects. So now the code to load the audio files went to something like this:

SoundEffect se = SoundEffect.FromStream(TitleContainer.OpenStream(soundFileToPlay));

Note: I could be wrong here, I am not an expert in XNA, but all audio files had to be converted to .wav files. The desktop MediaElements accepted the .mp3 file format, so there was an increase in size in the WP7 version.

Night of the living dead

The next change from the desktop version stems from the fact that the phone can’t multitask (at least not yet). So when the game is interrupted by something (maybe a phone call, or someone needs to check their email) it is a best if the game doesn’t dump them out to the main game menu when they return (leaving them to start completely over). This is accomplished by a process that has been dubbed “Tombstoning.”

In the app.xaml.cs file there are four methods to worry about if you want to implement Tombstoning:

  • Application_Launching
    • This is ran when the game is started for the first time. Otherwise known as a cold boot. It does not run when the game is resuming.
  • Application_Activated
    • This is ran when the game resumes from being put into the background or unloaded. This process has been referred to as “reanimation” (the process of coming back to life after being deactivated/unloaded).
  • Application_Deactivated
    • This is fired when the application is “interrupted”, but not shut down. So if you answer a phone call, swap to another application or just press the windows key.
  • Application_Closing
    • This is fired when the game is being closed down, but not when the game is being deactivated.

So what does this mean for the game? Well if there is an active game and the user decides to press the windows button I want to store off the current level and score, and restart the user from the beginning of that level. This is accomplished by putting the following code into the Application_Deactivated:

IsolatedStorageSettings store = IsolatedStorageSettings.ApplicationSettings;
MainPage page = ((MainPage)RootFrame.Content);
DisplayStack view = page.View;
if (view.IsPlaying)
{
    Player p = view.GameModel.GetPlayer();
    store["wasPlaying"] = true;
    store["password"] = view.BoardHolder.Password;
    store["score"] = page.GetCumulativeScore();
}
store.Save();

When the game is resumed, it is reloaded using the following code:

IsolatedStorageSettings store = IsolatedStorageSettings.ApplicationSettings;
if (store.Contains("wasPlaying"))
{
    if ((bool)store["wasPlaying"])
    {
        if (store.Contains("password") &&
            store.Contains("score") &&
            store.Contains("position"))
        {
            ((MainPage)RootFrame.Content).ReanimateGame((string)store["password"],
                                                       (int)store["score"],
                                                       (Point)store["position"],
                                                        0,
                                                        0,
                                                        TimeSpan.Zero);

            store.Remove("wasPlaying");
            store.Remove("password");
            store.Remove("score");
            store.Remove("position");

            store.Save();
        }
    }
}

How do I get there again?

One of the biggest differences between WP7 and most desktop environments is the user interface. that is to say that on the computer you have a keyboard. On a WP7 device you use gestures to get around, and it only makes sense to use swipe gestures to control the direction Lt. Bennett goes.

There is a really nice set of gesture helpers inside the wp7 Silverlight Toolkit. They make wiring the whole thing up a lot easier.

Inside the constuctor, store off a reference to the listener:

_gestureListener = GestureService.GetGestureListener(LayoutRoot);

There are two methods that enable or disable user input:

//disable input method
if (_gestureListener != null)
{
    _gestureListener.DragCompleted -= GestureListenerDragCompleted;
}
//enable input method
if (_gestureListener != null)
{
    _gestureListener.DragCompleted += GestureListenerDragCompleted;
}

And last but not least, the DragCompleted method that actually determines the direction to send Lt. Bennett on:

private void GestureListenerDragCompleted(object sender, DragCompletedGestureEventArgs e)
{
    if (e.Direction == System.Windows.Controls.Orientation.Vertical)
    {
        if (e.VerticalChange > 0)
        {
            _playerMover.MoveByMouse("Down");
        }
        else
        {
            _playerMover.MoveByMouse("Up");
        }
    }
    else
    {
        Debug.WriteLine("Horizontal:" + e.HorizontalChange);
        if (e.HorizontalChange > 0)
        {
            _playerMover.MoveByMouse("Right");
        }
        else
        {
            _playerMover.MoveByMouse("Left");
        }
    }
}

Always check performance with a device

I can still hear all the presenters at MIX reverberating the same message in every single session, “always check the performance of your app with a real device before deployment.” This cannot be understated. The emulator works fine, but generally performance on an actual device is even slower (though they have brought the difference between device and emulator speed differences down considerably).

The game runs at 60 FPS on a desktop without any issues, but if you did a straight conversion the game stutters a lot. Animations flicker, animations skip frames, and in general it just runs slow (15 FPS at certain points).

What this means is that you have to go through your code and basically copy/paste CacheMode=”BitmapCache” into many, many areas to help ensure that the game is sufficiently cached. This keeps the compositing on the GPU and not on the CPU, allowing there to be more clock cycles to process things like game logic. This equated to a HUGE difference in gameplay and animation speed.

While this is a really simple thing to copy/paste ClientMode, it is error prone. I can’t for the life of me figure out why the Silverlight team decided to leave performance enhancements like this to the developer and not to the underlying framework. If we leave it to the developers, there are going to be a lot of applications that don’t use the settings at all, or miss setting a few key objects here and there. But since it is left to the developer to do it, don’t forget to go through and test your application. “App.Current.Host.Settings.EnableCacheVisualization = true;” is your friend in this matter, so use it.

And that is it!

The rest of the application is exactly the same as the desktop version. While I know the code base is old, and by no means follows any of the modern patterns (lets face it, we were writing against an unknown architecture at the time), it is still a testament to how good a job the team is doing at backwards compatibility.

I for one was very shocked that the transition went as smoothly as it did.

Zero Gravity: Conquering new frontiers

16 comments

It seems like only yesterday that Tim Heuer was  showing off Zero Gravity and the lovable antics of Lt. Bennett. It is hard to believe that was over 3 years ago. The Silverlight platform has grown up by leaps and bounds in that amount of ltbennett-ship time, and with the looming release of Windows Phone 7, it seems only fitting that I get the opportunity to go back an take a look at the first game built in Silverlight with the intent of bringing it to the modern age. That’s right, Zero Gravity is now available on WP7 as well.

What amazed me the most out of this whole experience is that the codebase written back in WPF/e was able to be recompiled with very little modification into the latest version of silverlight. Sure, there were a few namespace changes, but nothing in the code needed to structurally change. Even the old way of using a pre-loader (back before there was such a thing as a “splashScreenSource”) runs without a hitch. In my next post, I will go into the changes that were necessary to get the game to work in WP7 but until then…

Just give me the source!

So without further adieu, I give you the source code for the original zero gravity

Desktop – Silverlight 4: ZeroGravity.Desktop.zip
WP7 – Silverlight 3: ZeroGravity.Wp7.zip

Please note that the Wp7 version you will need the Toolkit which can be found on codeplex.

If you just want to play the original game, you can check it out right over here!