Getting Started with Windows Phone Development

July 22, 2011

one comment

I must admit I was reluctant to get into Windows Phone development too deeply because I had no actual device running the Windows Phone OS. An emulator, no matter how good, cannot replace the actual device experience, and for some applications such as games, is simply inadequate.

Well, the excuses are over. I got a Windows Phone device (the Samsung Omnia 7) a few days ago. It’s time to take WP7 development more seriously (but not too seriously, as it’s fun…).

Instead of going with the traditional “hello world”, I’ll go for something a little more ambitious: a kind of guessing game, with the following rules:

  • the program selects a 4 digit number, where all digits being different from one another.
  • the player tries to guess the 4 digit number
  • for each guess, the program responds with a set of full or empty circles. A full circle indicates a correct digit in the correct place (but it doesn’t indicate which one). An empty circle indicates a correct digit that’s out of place.
  • this goes on until the player figures it out or the time runs out.

Let’s get started.

Getting the Tools

The first thing to do is download the Windows Phone 7 SDK, in the Beta 2 version of “Mango” at the time of this writing. This installs project templates for Visual Studio, the WP7 emulator and some other useful libraries. You’re naturally going to need some version of Visual Studio 2010 (the express version works as well).

Creating a New Project

After installation, run VS 2010 and create a new project for a Silverlight windows Phone application:

image

There are various templates to get started, but they’re pretty similar, each one adding something beyond the first template. For this project, I’ll use the basic “Windows Phone Application” template, call it GuessNumber and click OK.

Windows Phone supports two pretty distinct way of programming (although they may also be combined): one is using Silverlight and the other using XNA. Both of these technologies are not new, meaning possibly a less steep curve of learning. If you know Silverlight or WPF, then you’re on a good start with WP7 application development. For more graphical games – XNA is the better choice. And again, If you know XNA for Windows or the XBOX 360, you’re mostly ready to tackle WP7. For a good Smile tutorial on basic XNA development, you can check out the tutorial series I did a few months back (here are the first and last posts in the series).

Coding the game

We get a standard WP7 page deriving from the PhoneApplicationPage (similar somewhat to the standard Silverlight Page class). Inside there is some standard XAML that we need to customize. This is the basic screen I want to get:

image

The main area holds an ItemsControl wrapped in a ScrollViewer that’s going to show the guesses and their results as they come in during play. The “New Game” button starts a new game (obviously), “Restart” resets the clock but keeps the same secret number (a kind of cheat). “Quit Now” forfeits the game and shows the secret combination. Here’s an example of a game running inside the emulator:

SNAGHTML1503ca8

A class named GuessNumberGame takes care of the game logic: generating a secret number and evaluating guesses. Here’s the way a new number is generated:

private void GenerateSecret() {
    var ints = Enumerable.Range(0, 10).ToArray();
    var rnd = new Random();
    for(int i = 0; i < 20; i++)
        Helpers.Swap(ref ints[rnd.Next(10)], ref ints[rnd.Next(10)]);
    _secret = string.Join(string.Empty, ints.Take(NumLength).Select(n => n.ToString()).ToArray());
}

The general strategy is creating a range of numbers 0-9, then shuffling them and finally using the first NumLength digits (currently 4, but can be changed to create an easier or more difficult game).

To evaluate a guess, the EvalGuess method is used:

public bool EvalGuess(string guess, out int inpos, out int justin) {
    inpos = justin = 0;
    if(guess == _secret) {
        inpos = NumLength;
        return true;
    }
    Debug.Assert(guess.Length == _secret.Length);
    justin = guess.Intersect(_secret).Count();
    for(int i = 0; i < _secret.Length; i++)
        if(_secret[i] == guess[i]) {
            justin–;
            inpos++;
        }
    return false;
}

The method returns true on a correct guess. inpos returns the number of digits in correct positions and justin returns the number of digits in incorrect positions.

The MainPage class holds a game instance and handles the UI. I have not created any special MVVM style views or view models in this application as it’s too simple to bother. Some data binding does take place, however. The ItemsControl control is built like so:

<ItemsControl Grid.Row="1" ItemsSource="{Binding Guesses}" >
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:GuessItemControl Margin="4" FontSize="25"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate
>
</
ItemsControl
>

There is a data template based around a simple GuessItem class serving as the DataContext of a user control that shows a single row consisting of a guess and its evaluation. The ItemsSource property is bound to a Guesses property, but since no source is indicated, it uses the closest DataContext. In our case, it’s simply set to the MainPage itself (in the constructor). Guesses is an ObservableCollection of GuessItem instances.

Here’s how a GuessItem looks like:

public class GuessItem {
    public string Guess { get; set; }
    public int PosIncorrect { get; set; }
    public int PosCorrect { get; set; }
}

The GuessItemControl class is a user control that builds a line using a combination of code and markup:

<Grid x:Name="LayoutRoot">
     <Grid.ColumnDefinitions>
         <ColumnDefinition />
         <ColumnDefinition />
     </Grid.ColumnDefinitions>
     <TextBlock Text="{Binding Guess}" HorizontalAlignment="Center"/>
     <ItemsControl Grid.Column="1" x:Name="_images">
         <ItemsControl.ItemsPanel>
             <ItemsPanelTemplate>
                 <StackPanel Orientation="Horizontal" />
             </ItemsPanelTemplate>
         </ItemsControl.ItemsPanel>
     </ItemsControl>
 </Grid
>

public GuessItemControl() {
    InitializeComponent();

    Loaded += delegate {
        GuessItem data = DataContext as GuessItem;
        Debug.Assert(data != null);

        for(int i = 0; i < data.PosCorrect; i++)
            _images.Items.Add(new Ellipse { Width = 20, Height = 20, Fill = _fillBrush,
                Stroke = _strokeBrush, StrokeThickness = 2, Margin = new Thickness(2) });
        for(int i = 0; i < data.PosIncorrect; i++)
            _images.Items.Add(new Ellipse { Width = 20, Height = 20,
                Stroke = _strokeBrush, StrokeThickness = 2, Margin = new Thickness(2) });
    };
}

The circles are built dynamically using code. This may not be the most “elegant” way of doing it, but it works and suffices for our purposes here.

Evaluating a guess is handled by the Click event handler of the “Guess” button:

private void OnInputGuess(object sender, RoutedEventArgs e) {
    if(_guess.Text.Length != _game.NumLength) {
        _guess.Focus();
        return;
    }

    int posCorrect, posIncorrect;
    bool win = _game.EvalGuess(_guess.Text, out posCorrect, out posIncorrect);
    _guesses.Add(new GuessItem { Guess = _guess.Text, PosCorrect = posCorrect, PosIncorrect = posIncorrect });
    _guess.Text = string.Empty;
    if(win)
        GameOver(true);
}

The game’s EvalGuess method is consulted, and then a GuessItem object is constructed based on the results and added to the ObservableCollection that is bound to the ItemsControl, so that the results appear immediately.

Running & Debugging the Application

The installed tools allow selecting the target device that we want to deploy to. This is the emulator by default, but we can switch to the actual device (now that I have it…).

image

Debugging is pretty straightforward. You can set breakpoints, inspect variables, etc. whether you’re running on the emulator or the actual device. If running on the device, your app is added to the all applications list and you can run it independently like any other.

If you want to put your creation to the marketplace, you’ll need to tackle a few more details, but that’s for another post.

Other Points of Interest

The TextBox used is just a textbox, but on a phone device the SIP keyboard appears. It’s possible to indicate to WP7 which keyboard style you prefer. In this case, we just need digits, so using the “default” keyboard is inconvenient, causing the player to type way too much and be annoyed. Here’s how we can choose a different set:

<TextBox Width="150" x:Name="_guess" MaxLength="4" TabIndex="0" Background="Green">
    <TextBox.InputScope>
        <InputScope>
            <InputScopeName NameValue="TelephoneNumber" />
        </InputScope>
    </TextBox.InputScope
>
</
TextBox
>

The countdown is handled by a DispatcherTimer object, firing at 1 second intervals. It’s activated when a new game starts:

private void StartNewGame() {
    _game = new GuessNumberGame(4);
    _gameTime = MaximumGameTime;
    _guesses.Clear();
    _timer.Start();
    IsGameRunning = true;
}

It’s configured in the constructor of MainPage. First, some fields:

DispatcherTimer _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
int _gameTime;

Next, handling the Tick event:

_timer.Tick += (s, e) => {
    if(–_gameTime == 0) {
        GameOver(false);
    }
    else
        Caption = string.Format("{0}:{1:D2} Remain", _gameTime / 60, _gameTime % 60);
};

Here’s a link to the entire Solution.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

one comment

  1. dr dre beats wirelessAugust 13, 2013 ב 12:13

    sHyCiWcNhGxUkCdWuCaMePcH [url=http://www.archival-facsimiles.com/dr-dre-beats-wireless-latest-dr-dre-beats-wireless-online-usa-store/]dr dre beats wireless[/url] dr dre beats wireless

    Reply