How to make a Windows Store game with C# and XAML, part 2

This guest blog post is the second of a 3-part series written by Windows developer Jani Nevalainen. Please see the original 2nd post on Jani’s blog here, and refer to Part 1 here. Stay tuned for Part 3, coming soon. 

Creating the game field and player

In my previous post, we set up the project and created a nice start screen. But games need more than just the start screen. In this post we’ll create a game screen, enabling navigation to it from the start screen, and we’ll also add the player ship to it.

We create the game field by creating a new blank page called GamePage. We add it to the Shared –project (right click, Add, New Item, Blank Page). Because we support Windows and Windows Phone, we need to adjust our game page depending if we’re on a small phone screen or a larger screen such as tablet or desktop. Typically this is done by using VisualState manager, but for the sake of keeping things as simple as possible, on this tutorial we’ll just do the required adjustment in code.

Next step is to add the player ship to Shared project, so create a new user control and name it Ship.

Replace the Ship.xaml with the following:

<UserControl
    x:Class="MySpaceInvanders.Ship"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MySpaceInvanders"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:foundation="using:Windows.Foundation"
    mc:Ignorable="d">

    <Polygon x:Name="BodyShape" Stroke="Black" Fill="Red"/>
</UserControl>

and then the constructor content in Ship.xaml.cs with:

public Ship()
        {
            this.InitializeComponent();
#if WINDOWS_PHONE_APP
            Width = 20;
            Height = 40;
            BodyShape.Points = new PointCollection()
            {
                new Point(0, 40), new Point(10,0), new Point(20,40)
            };
#else
            Width = 40;
            Height = 80;
            BodyShape.Points = new PointCollection()
            {
                new Point(0, 80), new Point(20,0), new Point(40,80)
            };
#endif
        }

In that code, we’re using #if WINDOWS_PHONE_APP to define the code which we use to give size to the control when running on phone. And in #else we are defining the shape for Windows app. Currently they are just different size, and we could have handled that in XAML by just stretching the ship accordingly, but this leaves us the option to have a different ship shape in each platform.

Copy the following to the MySpaceInvanders.Shared -project’s GamePage.xaml, overwriting all the existing markup:

<Page
    x:Class="MySpaceInvanders.GamePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MySpaceInvanders"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" >
<Page.Resources>

</Page.Resources>
    <Grid x:Name="MainGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="LeftArea" Width="2*"/>
            <ColumnDefinition x:Name="MiddleArea" Width="12*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>
        <Grid Grid.Column="0" Background="RoyalBlue">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

The code above divides the field in three different sectors, one for scores and ship controls, one for play field and for the fire button. Copy the following code under the code above:

            <TextBlock Text="Highscore:" Grid.Row="0" Margin="5,0"/>
            <TextBlock x:Name="HighscoreBoard" Grid.Row="0" Text="0" Margin="5,32"/>
            <TextBlock x:Name="ScoreTitle" Text="Score:" Grid.Row="0" Margin="5,64"/>
            <TextBlock x:Name="ScoreBoard" Grid.Row="0" Text="0" Margin="5,73,0,0"/>
            <Grid x:Name="LeftCanvas" Grid.Row="2" 
                    VerticalAlignment="Bottom" 
                    HorizontalAlignment="Left" 
                    PointerPressed="ToLeftPressed" 
                    PointerReleased="ToLeftReleased" 
                    PointerExited="ToLeftExited" >
                <Ellipse x:Name="ToLeft" Stretch="Uniform" Fill="Azure"/>
                <Polygon Stroke="Black" Fill="Blue" Stretch="Uniform"
                         Points="5,40,60,10,60,70" RenderTransformOrigin="0.5,0.5">
                      <Polygon.RenderTransform>
                        <ScaleTransform ScaleX="0.75" ScaleY="0.75"/>
                    </Polygon.RenderTransform>
                </Polygon>
            </Grid>
            <Grid x:Name="RightCanvas" Grid.Row="2" 
                    VerticalAlignment="Bottom" 
                    HorizontalAlignment="Right" 
                    PointerPressed="ToRightPressed" 
                    PointerReleased="ToRightReleased" 
                    PointerExited="ToRightExited" >
                <Ellipse x:Name="ToRight" Stretch="Uniform" Fill="Azure"/>
                <Polygon Stroke="Black" Fill="Blue" Stretch="Uniform"
                         Points="75,40,25,10,25,70" RenderTransformOrigin="0.5,0.5">
                    <Polygon.RenderTransform>
                        <ScaleTransform ScaleX="0.75" ScaleY="0.75"/>
                    </Polygon.RenderTransform>
                </Polygon>
            </Grid>
        </Grid>

The code above sets the score, highscore and player moving controls to the screen. Notice that we are using PointerReleased and PointerExited events for controlling the ship, those are the only events which will give you smooth control over the ship movement. Copy the following code under the code above:

<Canvas x:Name="LayoutRoot" 
                Background="Black" 
                Grid.Column="1">
            <Canvas.Resources>
                <Storyboard x:Name="Move"/>
            </Canvas.Resources>

            <local:Ship x:Name="Rocket"/>
        </Canvas>

The code above sets the playing field, and sets the ship on the screen. Copy the following code under the code above:

<Grid x:Name="FireButton" Grid.Column="2" 
              VerticalAlignment="Bottom" 
              HorizontalAlignment="Right" 
              Tapped="OnFire">
            <Ellipse Width="100" Height="100" 
                     VerticalAlignment="Top" 
                     HorizontalAlignment="Center">
                <Ellipse.Fill>
                    <LinearGradientBrush>
                        <GradientStop Color="#9AA20000" Offset="1"/>
                        <GradientStop Color="Red"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Ellipse Width="70" Height="70" 
                     VerticalAlignment="Center" 
                     HorizontalAlignment="Center">
                <Ellipse.Fill>
                    <LinearGradientBrush>
                        <GradientStop Color="#00FF8585" Offset="0"/>
                        <GradientStop Color="#1AFFFFFF" Offset="1"/>
                        <GradientStop Color="#3FF5C2C2" Offset="0.349"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
        </Grid>
    </Grid>
</Page>

Code above draws the firing button on the screen. We’re using two ellipses to give impression of dimension for the button surface.

As mentioned earlier, we’re doing the differences in code to handle phone and desktop/tablet versions. For the GamePage we do it so that we open the GamePage.xaml.cs and edit the constructor public GamePage() and add the following just under the this.InitializeComponent:

#if WINDOWS_PHONE_APP
            MiddleArea.Width = new GridLength(6, GridUnitType.Star);
            Style style = new Style(typeof(TextBlock));
            style.Setters.Add(new Setter(TextBlock.FontSizeProperty, 24));
            style.Setters.Add(new Setter(VerticalAlignmentProperty, VerticalAlignment.Top));
            style.Setters.Add(new Setter(HorizontalAlignmentProperty, HorizontalAlignment.Left));
            Resources.Add(typeof(TextBlock), style);
            HighscoreBoard.Margin = new Thickness(5, 22, 0, 0);
            ScoreTitle.Margin = new Thickness(5, 44, 0, 0);
            ScoreBoard.Margin = new Thickness(5, 73, 0, 0);
#else
            MiddleArea.Width = new GridLength(12, GridUnitType.Star);
            Style style = new Style(typeof(TextBlock));
            style.Setters.Add(new Setter(TextBlock.FontSizeProperty, 32));
            style.Setters.Add(new Setter(VerticalAlignmentProperty, VerticalAlignment.Top));
            style.Setters.Add(new Setter(HorizontalAlignmentProperty, HorizontalAlignment.Left));
            Resources.Add(typeof(TextBlock), style);
            HighscoreBoard.Margin = new Thickness(5, 32, 0, 0);
            ScoreTitle.Margin = new Thickness(5, 64, 0, 0);
            ScoreBoard.Margin = new Thickness(5, 96, 0, 0);
#endif

Now that we have the UI set, we’ll add some functionality to enable the ship to move later on. Open the GamePage.xaml.cs and add these members to the class:

private bool goingLeft = false, goingRight = false;

After that we need to add the event handlers under the constructor:

private void ToLeftPressed(object sender, PointerRoutedEventArgs e)
        {
            goingLeft = true;
        }
 
        private void ToRightPressed(object sender, PointerRoutedEventArgs e)
        {
            goingRight = true;
        }
 
        private void ToLeftReleased(object sender, PointerRoutedEventArgs e)
        {
            goingLeft = false;
        }
 
        private void ToLeftExited(object sender, PointerRoutedEventArgs e)
        {
            goingLeft = false;
        }
        private void ToRightReleased(object sender, PointerRoutedEventArgs e)
        {
            goingRight = false;
        }
 
        private void ToRightExited(object sender, PointerRoutedEventArgs e)
        {
            goingRight = false;
        }
private void OnFire(object sender, TappedRoutedEventArgs e)
{
}

To enable navigation to game screen from the start page, we’ll open the StartPage.xaml.cs and add to the OnStart -method the following code:

this.Frame.Navigate(typeof (GamePage));

Now we can test that launching the app, and pressing the Start-button should show us a screen with controls and ship, which is still not positioned correctly and not moving.

Stay tuned for Part 3, coming next week.