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

Creating the game field and player

On previous parts we set up the project and created a nice start screen. But game needs more than just the start screen. On this post we’ll create a game screen, enable navigation to it from the start screen, and 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 simple as possible, on this tutorial we’ll just do 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 option to have 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 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 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.

Check out the part 3

Posted in Uncategorized | Leave a comment

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

I believe that games are still one of the most fun ways to get to know a new programming language. As there’s currently shortage of beginner level game programming tutorials for Universal Apps, I thought I’d share you how I did a simple shoot’em up for Windows and Windows Phone with shared code.

I tried to include all the steps, so you can follow it like a hands on lab while doing your own version. You can find the finished tutorial from the Windows Store and Windows Phone Store to download and try it out. I also made the finished tutorial source available for you to play with.

Creating the project
Creating the game project doesn’t differ from creating a normal app, so you would open the Visual Studio, go to File.. New, Project, and select from under Visual C#, Store Apps and Universal Apps. As this is the most basic version of a game, we’re not doing MVVM but keep it as simple as possible. For the same purpose, we select Hub App as a project type, and give it a name, for example “MySpaceInvanders”.

When you got the project set up, you got three projects in your solution tree in the right, “MySpaceInvanders.Windows”, “MySpaceInvanders.WindowsPhone” and “MySpaceInvanders.Shared”. We’ll do some housekeeping, and remove everything else from the solution by pressing Delete key on top of the files, until you’re left with a solution which looks like this:

We’re going to put all the logic to the Shared project so it will be really easy to upkeep and keep adding features.

Next we’ll do some basic settings for the projects by going to the project settings. First open the Package.appxmanifest in MySpaceInvanders.WindowsPhone.
On the Application –tab, select from Supported rotations “Landscape”. Now open the same file from MySpaceInvanders.Windows, and select also only “Landscape” and save your changes. Go to Visual Assets –tab in Package.appxmanifest and change Background color to #000000 for both projects as well.

Creating a start page
We’re forgetting the splash screens for now, and focusing on the first screen which will be where the game can be started, and high scores are visible. Right click on the solution explorer on the Shared –project, select Add, New Item, and Blank Page. Give the page name “StartPage.xaml” and click ok. Next we’ll set it as a start page by opening the App.xaml.cs file in the Shared –project, and going to the OnLaunched -method. There you will find a line of code like this:

if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))

Now we changed the MainPage text from that line to StartPage to launch our custom start up page when the app launches.

Open the StartPage.xaml, and copy the following on top of the <Grid> … </Grid> area of code:

<Grid>
    <Button x:Name="StartButton" Content="Start" 
            Margin="0,12,0,0" 
            HorizontalAlignment="Center" 
            VerticalAlignment="Bottom" 
            Height="105" Width="370" 
            FontFamily="Georgia" 
            FontSize="48" 
            Click="OnStart"/>
    <TextBlock Text="UNIVERSAL "
               HorizontalAlignment="Center" 
               VerticalAlignment="Top" 
               Margin="0,53,0,0" TextWrapping="Wrap" 
               FontFamily="Georgia" FontSize="48"/>
    <TextBlock Text="INVANDERS" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Top" 
               Margin="0,103,0,0" 
               TextWrapping="Wrap" 
               FontFamily="Georgia" FontSize="48"/>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="Highscore:" 
                   Grid.Column="0" 
                   HorizontalAlignment="Right" 
                   VerticalAlignment="Top" 
                   Margin="0,203,0,0" 
                   TextWrapping="Wrap" 
                   FontFamily="Georgia" 
                   FontSize="32"/>
        <TextBlock x:Name="HighScoreBlock" Text="0" 
                   Grid.Column="1" 
                   HorizontalAlignment="Left" 
                   VerticalAlignment="Top" 
                   Margin="0,203,0,0" 
                   TextWrapping="Wrap" 
                   FontFamily="Georgia" 
                   FontSize="32"/>
    </Grid>
    <Canvas x:Name="LayoutRoot">
        <Canvas.Resources>
            <Storyboard x:Name="Move"/>
        </Canvas.Resources>
    </Canvas>
</Grid>

Add the following to StartPage.xaml.xs:

private void OnStart(object sender, RoutedEventArgs e)
{
 
}

Adding some animation
Now that we have the start screen set up, it looks kind of dull. Let’s put emitter there to shoot some stars to make it look more alive. If you look at the XAML we just added, you notice a Canvas element which has a Storyboard element inside it. That is our animation container, which will show the emitter.

First we need a particle for the emitter. We’ll create class called Dot by right clicking the MySpaceInvanders.Shared -project, and selecting Add, New Item, Class. Make sure the Name –field has Dot.cs written in it before clicking ok. Next we’ll open the Dot.cs and add some properties to the particle. Each particle will have two different properties: Shape and Velocity. Add the following member variables to class Dot

public Ellipse Shape { get; set; }
public Point Velocity { get; set; }

Next we need to create the emitter itself, which will be shooting these particles we just created. Open the StartPage.xaml.cs, add on the top of the file:

using Windows.UI;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

Then we need to add these member variables to StartPage class

private const int StarCount = 200;
private List<Dot> stars = new List<Dot>(StarCount);
private Random randomizer = new Random();

After we have a list to keep the particles, and set the number of particles, we’ll create a new method:

private void CreateStar()
{
    var star = new Dot()
    {
        Shape = new Ellipse() { Height = 2, Width = 2},
        Velocity = new Point(randomizer.Next(-5, 5), randomizer.Next(-5, 5))
    };

    // Center the star
    Canvas.SetLeft(star.Shape, LayoutRoot.ActualWidth / 2 - star.Shape.Width / 2);
    Canvas.SetTop(star.Shape, (LayoutRoot.ActualHeight / 2 - star.Shape.Height / 2) + 20);

    // Prevent stars getting stuck
    if ((int)star.Velocity.X == 0 && (int)star.Velocity.Y == 0)
    {
        star.Velocity = new Point(randomizer.Next(1, 5), randomizer.Next(1,5));
    }

    // Set color
    
    stars.Add(star);
    LayoutRoot.Children.Add(star.Shape);
}

Now we have created a particle, but it’s sitting idle on the screen, as generic and dull as the next one. Let’s give it some personality by adding some color to it by adding the following code under //Add color –line:

var colors = new byte[4];
    randomizer.NextBytes(colors);
    star.Shape.Fill = new SolidColorBrush(
        Color.FromArgb(colors[0], colors[0], colors[0], colors[0]));

We’re using the Random class to get a new color value. If you prefer to have colorful particles, you can change the Color constructor like this:

Color.FromArgb(colors[0], colors[1], colors[2], colors[3]);

At this point we have a lot of particles staying static at one point. What we need is a method to move particles, reset those which have gone off the screen back to the center. Add the following code under the CreateStar method:

void MoveStars(object sender, object e)
{
    if (stars.Count < StarCount)
    {
        CreateStar();
    }

    foreach (var star in stars)
    {
        double left = Canvas.GetLeft(star.Shape) + star.Velocity.X;
        double top = Canvas.GetTop(star.Shape) + star.Velocity.Y;

        Canvas.SetLeft(star.Shape, left);
        Canvas.SetTop(star.Shape, top);

        // Star is off the screen
        if ((int)left < 0 ||
            (int)left > LayoutRoot.ActualWidth ||
            (int)top < 0 ||
            (int)top > LayoutRoot.ActualHeight)
        {
            Canvas.SetLeft(star.Shape, LayoutRoot.ActualWidth / 2 - star.Shape.Width / 2);
            Canvas.SetTop(star.Shape, (LayoutRoot.ActualHeight / 2 - star.Shape.Height / 2) + 20);
        }
    }
    Move.Begin();
}

As the effect of all the stars coming to screen at once is quite ugly, we’re adding them one by one each pass to the screen until we have max number of them visible. After that the method goes through all the particles and sets their new position according to their velocity. In the last part we’re checking if the particle has gone off the screen and center it back if it’s not visible anymore.

Now we need to just activate these methods and we’re set to try how does it look like. Add the following code to constructor, just after InitializeComponent() –line:

Loaded += (sender, args) =>
{
    CreateStar();
    Move.Completed += MoveStars;
    Move.Begin();
};

Now you’re set to try how does it look! Just select the Windows project and run on local machine. Keep building the game on the part 2

Posted in Uncategorized | Leave a comment

Taking high res photos with Windows Phone 8.1

There was previously no access to high res resolutions on the camera, but you had to know which model supports which high resolution. Now with the universal apps, you can actually get the all supported resolutions from the camera easily, including the high res and init your camera to use them. Here’s a quick sample snippets to init your camera, select the highest possible resolution and change your camera to use that.

Assumption is that you have CaptureElement in your XAML called captureElement, and MediaCapture element called mediaCapture as a member variable in your code behind in MainPage.xaml.cs

Select the back camera:

var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Enumeration.DeviceClass.VideoCapture);
var backCameraId = devices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back).Id;
await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
{ VideoDeviceId = backCameraId});

Next query all the supported resolutions, and select the highest possible and set that to the camera.

var resolutions = this.mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo);

if (resolutions.Count >= 1)
{
var hires = resolutions.OrderByDescending(item => ((VideoEncodingProperties)item).Width).First();

await mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, hires);
}

Now you’re ready to start video preview and do photo capturing with these last calls

captureElement.Source = mediaCapture;
await mediaCapture.StartPreviewAsync();

Check out my previous post about setting the camera preview correctly, otherwise your image is going to be tilted quite funkily.

Posted in Uncategorized | Leave a comment

Windows Phone 8.1 camera orientation

Using the cameras of Windows Phone 8.1 live viewfinder in Universal apps can be a bit of a challenge. The behavior is different with front and main cameras and most likely you end up with upside down image on your preview, if you run the same code which works for Windows 8.1 when using the front camera. The design of the camera driver is based on WP8.1 chassis specs, and camera orientation is dependent on the native landscape orientation of the display.

Issue here is that the rotation of the front camera and display happens in opposite direction, resulting to inverted image. This all can be a bit confusing, so let’s give you a code which runs on WP8.1 correctly. Note that you need to ifdef this code in Windows for the rotations, or your front camera on tablet will be incorrectly rotated.

First we define the capture element to the XAML like this:

<CaptureElement x:Name="captureElement" 
HorizontalAlignment="Center" 
VerticalAlignment="Center" 
Stretch="UniformToFill">
</CaptureElement>

In the following code we check if front camera is available, and take it in use, otherwise fall back to the main camera. After that we set the camera mirroring according to the chosen camera, as it differs with front and main camera as well. Lastly we subscribe to the orientation change event:

bool frontCam;

...

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    mediaCapture = new MediaCapture();
    DeviceInformationCollection devices = 
await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

    // Use the front camera if found one
    if (devices == null) return;
    DeviceInformation info = devices[0];

    foreach (var devInfo in devices)
    {
        if (devInfo.Name.ToLowerInvariant().Contains("front"))
        {
            info = devInfo;
            frontCam = true;
            continue;
        }
    }

    await mediaCapture.InitializeAsync(
        new MediaCaptureInitializationSettings
        {
            VideoDeviceId = info.Id
        });
            
    CaptureElement.Source = mediaCapture;
    CaptureElement.FlowDirection = frontCam ? 
FlowDirection.RightToLeft : FlowDirection.LeftToRight;
    await mediaCapture.StartPreviewAsync();

    DisplayInformation displayInfo = DisplayInformation.GetForCurrentView();
    displayInfo.OrientationChanged += DisplayInfo_OrientationChanged;

    DisplayInfo_OrientationChanged(displayInfo, null);
}

Now we need to adjust the orientation of the capture element according to the screen orientation (the animation makes your eyes bleed, but there’s no way to disable orientation animations for a control). This code is modified from the MSDN Windows 8.1 advanced camera sample.

private void DisplayInfo_OrientationChanged(DisplayInformation sender, object args)
{
if (mediaCapture != null)
{
mediaCapture.SetPreviewRotation(frontCam
? VideoRotationLookup(sender.CurrentOrientation, true)
: VideoRotationLookup(sender.CurrentOrientation, false));
var rotation = VideoRotationLookup(sender.CurrentOrientation, false);
mediaCapture.SetRecordRotation(rotation);
}
}

For the last piece we need to check the video rotation according to the chosen camera like this:

private VideoRotation VideoRotationLookup(DisplayOrientations displayOrientation, bool counterclockwise)
{
switch (displayOrientation)
{
case DisplayOrientations.Landscape:
return VideoRotation.None;

case DisplayOrientations.Portrait:
return (counterclockwise) ? VideoRotation.Clockwise270Degrees : VideoRotation.Clockwise90Degrees;

case DisplayOrientations.LandscapeFlipped:
return VideoRotation.Clockwise180Degrees;

case DisplayOrientations.PortraitFlipped:
return (counterclockwise) ? VideoRotation.Clockwise90Degrees :
VideoRotation.Clockwise270Degrees;

default:
return VideoRotation.None;
}
}

That’s all it requires, have fun with it!

Posted in Uncategorized | Leave a comment

Format your date in Universal app according to user preferences

With the new Universal app model, many things have changed, and there’s very little documentation available to find out how you need to address certain things in the new app model. One of those things is formatting your date according to the region settings chosen by the user. CultureInfo is no longer recommended class to be used, and if you tried to dig out yourself the chosen regional format, you might have found it to be quite difficult in cases where user has chosen to use different language (en-US) and different regional settings, for example de or fi.

It’s pretty easy still, only figuring it out where to find that info is not. So here’s the codeblock which formats datetime according to the chosen regional setting:

DateTime date = DateTime.Now;
GeographicRegion userRegion = new GeographicRegion();
var userDateFormat = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("shortdate",new [] {userRegion.Code});
var dateDefault = userDateFormat.Format(date);

We use the GeographicRegion to get the chosen region, and then we create DateTimeFormatter according to that culture, which we use to format the date on the last line. Hope this snippet helps you!

Posted in Uncategorized | Leave a comment