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

A classic memory game: Part 3 - Porting the game to Windows Phone 7

(3 votes)
Levente Mihály
>
Levente Mihály
Joined Apr 27, 2010
Articles:   7
Comments:   14
More Articles
7 comments   /   posted on Feb 04, 2011
Categories:   Gaming , Windows Phone 7

This article is compatible with the latest version of Silverlight for Windows Phone 7.

Don't miss...

        

             Show more books

This article is Part 3 of “A classic memory game”.

The series is about building the following classic memory game in Silverlight, and porting it to Windows Phone 7. In the first article we started a new MVVM Light project, created the controls and designed the game-states. In the second part we put the logic behind the game, and connected it with the View thus completing the Silverlight version of the game. In this final part we will port the game to Windows Phone 7.

You can download the original Silverlight version of the game here and the phone port from here.

First Steps

As you already know Windows Phone 7’s application platform is Silverlight. The version of Silverlight on the phone is not Silverlight 4, and it’s not Silverlight 3 either, I think we can put it somewhere between version 3 and 4, with some limitations (like the missing sockets API) and with some extras (the phone specific things).

The tools are totally free, both Visual Studio 2010 Express and Microsoft Expression Blend for Windows Phone, you can download the tools here. For the WrapPanel we will also need the Silverlight for Windows Phone Toolkit.

Since the Silverlight versions are not so different I just threw my original source code into a new Windows Phone 7 MVVM Light project:

I’ve added the original source (except App.xaml and App.xaml.cs) as already existing items. Of course to get it built I had to make a few modifications mainly in the namespaces.

The Toolkit’s namespace changes

from
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
to
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 

Interactivity and Interactions namespace becomes

from
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
to
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

Only one thing was incompatible with the phone’s version of Silverlight and that was the text formatting in bindings. Once I removed that the project could be built successfully. (A workaround is using a converter.)

The Phone UI

So the projects was built, and it actually ran. Too bad I could only see the edge of my start-menu, some resizing was needed. The display size of the phone is fixed: 480x800 pixels on all phones. This means we can rely on this size and use fixed elements. As well as resizing I converted my Grids to Canvases where it didn’t interfere with the animations. Canvas is a perfect fit for a fixed scenario and also it’s easier on the CPU as it won’t need to do complex calculations about the layout. An easy way to convert grids to canvases in Blend is the Change layout-type function:

I’ve also changed the card sizes to fill the screen better, so it’s 3x4 on easy, 4x5 on medium and 5x6 on hard.

 

After these adjustments the game was working fine in the emulator. And I finished these modifications in about 20 minutes, that’s pretty cool I think! Deploying it to the device is another story though, the game is working on the phone too, but it’s not a great experience yet.

Adapting the UI to the phone – buttons

First, let’s see the problems with the UI.

I’ve increased the size of the buttons, but it still felt a little hard to tap on them. It is strange, because the original buttons are smaller than the ones in the game, but they’re still easier to press. Let’s inspect the original button’s style in the phone. I dragged a button on the page, and edited a copy of its style, this is what I got:

  phone5

The UI Design and Interaction Guide states:

“Touch targets should not be smaller than 9 mm or 34 pixels square and provide at least 2 mm or 8 pixels between touchable controls. In exceptional cases, controls can be smaller but never more than 9 mm or 26 pixels square.”

This is achieved by giving the buttons a bigger border which is transparent (highlighted red in the picture). So the actual button is bigger than what you see, and this way it enables you to be less accurate when tapping on them.

I simply copied this behavior in my custom controls. For the RadioButton I set up a fix sized rectangle, increased the size of the button and gave the outer Grid a transparent background. This last part is very important, because without a background the grid wouldn’t accept the input.

 

The end result is an increased touch target, giving a much better experience on the phone:

For the cards I gave a margin to the image to keep the hosting grid bigger.

Adapting the UI to the phone – back button

Currently, pressing the Back button will exit the game immediately. Games on the phone usually pause on the first Back key, exit on second press. I’ve introduced a PauseState and to change the Back button’s behavior I had to override the OnBackKeyPress method:

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    if (currentState == "GameState")
    {
        Messenger.Default.Send<string>(Constants.PauseMessage, Constants.PauseMessage);
        VisualStateManager.GoToState(this, PauseState.Name, false);
        e.Cancel = true;
    }
    else
    {
        base.OnBackKeyPress(e);
    }
}
 
void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
{
    currentState = e.NewState.Name;
}
 
string currentState = "";

If we are in game state, the Back key enters PauseState, otherwise it exists. Here’s the Pause state:

Performance Optimizations

Originally I added the images to the project as “contents”. The game loaded fast, starting the game on easy level was okay, but on hard it was very slow, meaning a 3-4 seconds pause before the cards appeared. That seemed slow even on a pc, but on the phone it felt forever. On a touchscreen the interaction between the user and the software is more direct than on pc using a mouse, so the user expectation is that s/he would immediately see some result when pressing/tapping a button. But the CPU of the phone is of course much less powerful than on a desktop computer so we need to address optimizations.

Databindings and converters in lists are very costly so I removed the converters from the cards’ bindings by adding the specific properties to the MemoryCard model. The Solved property became a Visibility type instead of boolean, and the Image property became an ImageSource instead of just a string pointing to the location of the image.

Jpegs are rendered faster on the phone, but the images of the memory cards are using rounded corners which needs transparency so they remained pngs. Adding the images as content resulted a speedy start for the app but a longer pause when the images needed to load. Adding the images as resources means a slower start for the app – the images load with the application – but better loading times for the images themselves. The LowProfileImageLoader gets the best of two worlds by loading/downloading images in the background without freezing the UI when they are on the web or added as content.

I ended up not using the LowProfileImageLoader, just adding the images as resources to the project:

and creating the BitmapImages on startup:

_imageCache = new List<BitmapImage>();
for (int i = 0; i < 15; i++)
{
 
    var bi = new BitmapImage();                
    bi.UriSource = new Uri(string.Format("Images/mm{0}.png", i), UriKind.Relative);
    _imageCache.Add(bi);
}

This way and by eliminating the converters, the load-time on hard difficulty went down from 3-4 seconds to 1,5 seconds.

The pause still felt long so I added some animation to make it look shorter. After opting out adding the images in a BackgroundWorker (in the end it needed much more time, and the images appeared in very unbalanced intervals), I simply added a ProgressBar. I‘ve used Jeff Wilcox’s PerformanceProgressBar which really made my life easy. His version of the progress bar works in a background thread, and lets the animation finish. That meant I didn’t have to worry about working in a background thread, just switching the progress bar on and off  would display the standard indeterminate progress animation:

<extra:PerformanceProgressBar Width="320" Canvas.Top="710" Foreground="White" 
RenderTransformOrigin="0.5,0.5" Canvas.Left="80" IsLoading="{Binding IsBusy}" >
    <extra:PerformanceProgressBar.RenderTransform>
        <CompositeTransform ScaleX="1.5" ScaleY="1.5"/>
    </extra:PerformanceProgressBar.RenderTransform>
</extra:PerformanceProgressBar>
public void Start()
{
   _gameEnded = false;
   IsBusy = true;
   LoadCards();
   IsBusy = false;
   StartGame();
}

Please note, that the PerformanceProgressBar too costs CPU time, however it wasn’t significant in this case.

Tombstoning

The last phone-specific feature I wanted to add is tombstoning. Basically it means that the game can resume from its last state when it is interrupted by something, e.g a phone call. Every application has to handle interruption itself. Well, it is not obligatory, but if you want to give your users a good experience you should handle it. I really hope it will change in the future, and the OS will give some basic tombstoning out of the box, because it is not easy to handle. It seems easy to implement, in some cases it is easy, but usually it’s not. You really need to plan ahead.

We have four events to help us with implementing tombstoning:

  • Application_Launching – occurs when the application starts
  • Application_Activated – occurs when the application resumes
  • Application_Deactivated – occurs when the application is sent to background (e.g. phone call)
  • Application_Closing

Storing the state we have two options:

  • IsolatedStorage – will remain permanent
  • PhoneApplicationService.Current.State – a dictionary which stays in memory for a time when the application is deactivated

I’ve created an AppState class storing all the info of the game that it needs to resume and used Mike Talbot’s SilverlightSerializer to serialize and save it.

Here’s the AppState class:

public class AppState
{
    public List<MemoryCard> MemoryCardList { get; set; }
    public int TimeCounter { get; set; }
    public int MoveCounter { get; set; }
    public int PairCounter { get; set; }
    public int CardSize { get; set; }
    public Difficulties Difficulty { get; set; }
    public AppState()
    {
    }
}

Nobody wants to continue a memory game several hours later, so I handled only the activation/deactivation events, and store the state in the temporary Dictionary. You can easily modify the code to do the state saving on the closing event too, and save it to IsolatedStorage instead of the State dictionary.

// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    try
    {
        var storage = PhoneApplicationService.Current.State;
        if (storage.ContainsKey(AppStateKey))
        {
            byte[] appStateBytes = storage[AppStateKey] as byte[];
            AppState appState = SilverlightSerializer.Deserialize<AppState>(appStateBytes);
            MemoryViewModelLocator.SetAppState(appState);                    
        }
    }
    catch { }
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    var appState = MemoryViewModelLocator.MainStatic.GetAppState();
    if (appState != null)
    {
        var storage = PhoneApplicationService.Current.State;
 
        byte[] stateBytes = SilverlightSerializer.Serialize(appState);
 
        if (storage.ContainsKey(AppStateKey))
        {
            storage[AppStateKey] = stateBytes;
        }
        else
        {
            storage.Add(AppStateKey, stateBytes);
        }
    }
}

We can tell SilverlightSerializer which properties not to serialize with the DoNotSerialize attribute, e.g. the MemoryCard’s Image property:

[DoNotSerialize]
public ImageSource Image { get; set; }

You can try the tombstoning by pressing the windows-key during the game and then press the back-key to resume the game.

Summary

Porting the game to Windows Phone 7 was quite easy, Microsoft did a really great job. In this article we adopted the game to the phone in terms of UI and performance and we implemented tombstoning. With Windows Phone 7 Silverlight is becoming a real multi-platform framework, and I hope it is just the beginning.

Please, don’t hesitate to drop a comment if you have questions, I hope you enjoyed this project at least half as much I did!

About the Author

Levente MihalyMy name is Levente Mihaly. I've entered the .NET world in 2006, and after graduating at Budapest University of Technology (Msc in Computer Science) I started working as a .NET software developer. After meeting technologies like WinForms and ASP.NET, Silverlight quickly became my favourite platform from the early Silverlight 2 beta stages. I was always interested in mobile development and now I'm very happy since with Windows Phone 7 I can easily expand my knowledge to the mobile world. Nowadays beside following Silverlight I'm focusing on WP7 in my free time. I'm also the runner-up of the 2010 Silverlight ecoContest. You can reach me on twitter (@leventemihaly).
 


Subscribe

Comments

  • -_-

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by Moez on Mar 14, 2011 20:27
    Hello, I started to develop an application (organizer of tasks) with Windows phone 7.
    but I'm stuck in the push notification.
    I can not understand the phenomenon.
    tuto all speak of a notification from a web service.
    but in my application I need only receive a notification when the date of a task arrival.
    you can tell me please what am I to do?
    Many thank you:)

    I know you from the constraints of your work and you do not have much free time but please help a sudden I'll be very happy:)
  • -_-

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by wildfox on Mar 14, 2011 21:03

    Hi Moez,

    you will find articles about push notifications here on Silverlightshow, like Andrea Boschin's article: Understanding Push Notifications as well on MSDN: Push Notifications Overview for Windows Phone. There's also a good helper library we are currently using in our app.

    The concept in a nutshell is that the client app registers to a notification channel (gets an url from MS), and sends this url to your server (via webservice). Then your server can send messages to this url that will arrive to the phone as push notification.

  • -_-

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by Moez on Mar 16, 2011 14:21

    thank you very much

    links are very interesting :-)

  • -_-

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by kennywoo on Apr 08, 2011 18:35

    Awesome Article

    Thanks dude.

  • wildfox

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by wildfox on Apr 08, 2011 18:51

    Thanks :)

  • -_-

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by Matt on Apr 26, 2011 20:42
    Thanks for the great example of porting an app to Windows Phone. Currently I do most of my development in VB.NET - I am giving back by writing tutorials as well (like this one on Automatic Properties). But tutorials like your make me think I can switch pretty easily to C# if need be. Thanks for taking the time to give back to the development community.
  • wildfox

    RE: A classic memory game: Part 3 - Porting the game to Windows Phone 7


    posted by wildfox on Apr 28, 2011 01:25

    Thanks Matt, glad you like it. Switching between C# and VB.NET is quite easy indeed. I'll check back to your tutorials, seem very promising.

Add Comment

Login to comment:
  *      *       
Login with Facebook

From this series