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

After long pause, here’s the next edition of XAML gaming series. If you are serious game developer, you should check out some of the gaming frameworks, such as Unity or Cocos2D. You could also be interested in Win2D library if you prefer XNA type of programming. The idea of this series is to have fun and learn XAML/C# and Windows features at the same time.

In this episode we bring our project to Windows 10, and add Xbox 360/One controller support for our game. In next part we talk about adding sounds and some other fun things.

You will need to have Windows 10 and any edition of Visual Studio 2015 installed to go on with this project. First, make a backup of your game, and copy it somewhere safe before proceeding with this guide, just in case something goes haywire while converting the project as the following steps include irreversable deleting of files.

Conversion preparations

Start your project in Visual Studio 2015 and now that you have the backup safely in different folder, you can delete the MySpaceInvanders.WindowsPhone project from the solution. Next you select all the files in the Shared-project, and cut/paste them to the MySpaceInvanders.Windows project. Don’t forget to cut/paste also Assets and Common –folders and their content.

Open the App.xaml.cs file, and find all code which is inside #if WINDOWS_PHONE_APP -block and remove it. Remove also the line #ELSE (not the code inside the block) and #ENDIF line. Now you should have no conditional compilation inside the App.xaml.cs file. We handle the other files later.

There’s no AnyCPU project in Windows 10 by default, so we remove it from our solution. Open the Configuration Manager (the small arrow next to AnyCPU text), and choose Configuration Manager, and from Active Solution Platform dropdown choose Edit... Now select AnyCPU and click Remove and accept the removal. Now you can close the Configuration Manager. Select x86 configuration as active configuration.

Conversion

Unfortunately there’s no conversion tool for Windows Universal apps to Windows 10 build inside the Visual Studio, but luckily Andy Wigley and Jerry Nixon have provided such script for public availability.

Open https://github.com/Win10DevGuideMVA/ProjectUpgradeUtility in your browser, and download the zip file. Unpack these script files to your MySpaceInvanders.Windows folder, and open command prompt, navigating to that folder and type to command prompt:

cd c:\source\MySpaceInvanders\MySpaceInvanders.Windows

where the folder matches your local folder and press enter. You are ready to do the actual conversion, so just run the script by typing:

Run_Upgrade_to_uwp.bat

Your output should match something like the following screenshot (Two Trues and one Done without any errors):

You need to do couple of more steps before you can run your solution.

First open the Package.AppxManifest in code (right click the file in Solution Explorer and select View Code). You must change the text Square30x30Logo to Square44x44Logo. You need later on to upgrade the graphics to match this size as the old icon is too small and will give you error if you try to submit your game to the store.

If you have section called build:Metadata you should remove it completely. Now save the file, change the Build Configuration to ARM and X64 and repeat the previous steps for both configurations, saving the file every time and select lastly the x86 configuration back.

Now you need to remove one more #if WINDOWS_PHONE_APP conditional section from the code, this time from Startpage.xaml.cs where it checks the screen width and height. Your StartPage constructor should look like this:

public StartPage()
{
    this.InitializeComponent();

    ApplicationView view = ApplicationView.GetForCurrentView();

    bool isInFullScreenMode = view.IsFullScreenMode;

    if (!isInFullScreenMode)
    {
        view.TryEnterFullScreenMode();
    }

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

    App.ScreenWidth = Window.Current.Bounds.Width;
    App.ScreenHeight = Window.Current.Bounds.Height;
}

After you’ve done that, you should be able to compile the project without errors and try it out.

Post-conversion

When you start the game, you notice that all the texts from the start screen are missing!

This is a great opportunity to learn a little bit of error resolving with Visual Studio 2015 and about a great new feature called Live Visual Tree. While your app is running, switch back to Visual Studio with alt+tab and go to DebugWindows and select Live Visual Tree. Expand the window so that you can see it clearly.

You should see tree nodes called StartPage and under it Grid and StartButton. There are two TextBlock items there as well. Now go on and select one of them. Right click it and select Show properties. You can see what values have been set to the control while it’s running and you are able to edit them while your game is running.

First thing to check is that what color we have set for the text foreground. There’s no Foreground set on Local -section, so it must be inherited from somewhere else. You can see those values in the Default -section.

Now that you found the Foreground, it is showing Black. Where did that come from? In Windows 10 there’s been one big change in application color schemas, the default theme has been set to light. In light theme the text is black and background is white. There’s easy fix for us – stop the debugger, go to the beginning of the xaml -file, and add the following property to the page element:

RequestTheme="Dark"

Add it also to the GamePage.xaml in the same place, for example as a last property just after mc:Ignorable=”d” -text but before the closing tag.

Now all the text should be visible again and you’re good to go.

You could add a small visual candy to the start screen at this point. In the XAML designer select the UNIVERSAL -text block and click Brush in the property window (bottom right of VS), and select the third box below it (Gradient Brush). Repeat the same for the INVANDERS -text. Change the Black in GradientStop color to DarkGrey for both textblocks in XAML of StartPage.xaml and run the app. Now there’s a small chrome effect in the texts.

Let’s get on with the show and continue the conversion. Open the Ship.xaml.cs and remove the #if WINDOWS_PHONE_APP section (and #else and #endif -lines as well). Now do the same in the GamePage.xaml.cs as well.

We need to change shipHorizontalPosition -variable initializer in GamePage.xaml.cs to following (remove readonly and adjust the size):

private double shipHorizontalPosition = App.ScreenHeight - 80;

Windows 10 has changed so that the Store apps can be windowed as well. Right now we don’t add the code to handle resizing (subject for later posts) but add request to run in full screen mode, which is logical for games. Open the StartPage.xaml.cs and add to the top:

using Windows.UI.ViewManagement; 

Next add the following code to constructor after the InitializeComponent:

ApplicationView view = ApplicationView.GetForCurrentView();

            bool isInFullScreenMode = view.IsFullScreenMode;

            if (!isInFullScreenMode)
            {
                view.TryEnterFullScreenMode();
            }

Now you are ready to run the game!

Xbox 360/One controller support

Now we can finally add some Windows 10 goodies to the project. I think adding the controller support is really fitting as it’s useful not only to games but good to learn because it will be relevant for apps as well to enable your app to be controller on Xbox One later on when the Store opens for submissions for it.

We need to take the controller in use in only one place and then use that object through our app. Open the App.xaml.cs file and add to the top:

using Windows.Gaming.Input;

and following member variable:

public static Gamepad GameController;

When we are starting our app, we need to listen to when the app gets the Xbox controller connection by adding handler for GamepadAdded event in constructor after this.Suspending += this.OnSuspending; -line:

Gamepad.GamepadAdded += Gamepad_GamepadAdded;

Add the following method just below the constructor:

private void Gamepad_GamepadAdded(object sender, Gamepad e)
        {
            GameController = Gamepad.Gamepads.First();
        }

By adding the code above, you have now access to Xbox controller through out your app. At this point your App.xaml.cs should look something like this:

using System;
using System.Linq;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using MySpaceInvanders.Common;
using Windows.Gaming.Input; // XBOX


namespace MySpaceInvanders
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    public sealed partial class App : Application
    {
        public static double ScreenWidth { get; set; }
        public static double ScreenHeight { get; set; }
        public static int Highscore { get; set; }

        public static Gamepad GameController; // XBOX

        /// <summary>
        /// Initializes the singleton instance of the <see cref="App"/> class. This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += this.OnSuspending;
            Gamepad.GamepadAdded += Gamepad_GamepadAdded; // XBOX

        }
        private void Gamepad_GamepadAdded(object sender, Gamepad e)
        {
            GameController = Gamepad.Gamepads.First();
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected async override void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                //Associate the frame with a SuspensionManager key                                
                SuspensionManager.RegisterFrame(rootFrame, "AppFrame");

                // TODO: change this value to a cache size that is appropriate for your application
                rootFrame.CacheSize = 1;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    // Restore the saved session state only when appropriate
                    try
                    {
                        await SuspensionManager.RestoreAsync();
                    }
                    catch (SuspensionManagerException)
                    {
                        // Something went wrong restoring state.
                        // Assume there is no state and continue
                    }
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                if (!rootFrame.Navigate(typeof(StartPage), e.Arguments))
                {
                    throw new Exception("Failed to create initial page");
                }
            }

            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            await SuspensionManager.SaveAsync();
            deferral.Complete();
        }
    }
}

Let’s start by adding ship movement and firing to the game. Open the Gamepage.xaml.cs -file, and add the following using statement:

using Windows.Gaming.Input;

For better gameplay experience, I have added also bit which prevents Xbox controller autofiring all the time when the trigger is pressed. If you don’t like this, you can just comment it out later on. Add the following member variable:

bool fireSuppressor; // XBOX, prevent autofire

We need a place where we can read the controller values enough often without affecting the gameplay. I have opted in using the MoveStars -method which is not necessary the elegant solution but works anyway nicely. Add the following code to the very beginning of MoveStars -method:

if (App.GameController != null)
            {
                GamepadReading reading = App.GameController.GetCurrentReading();
                
                // Use 0.4 so the stick don't have to be exactly to right or left, but is more forgiving
                if ((double)reading.RightThumbstickX < -0.4)
                {
                    MoveShip(-5);
                }
                else if ((double)reading.RightThumbstickX > 0.4)
                {
                    MoveShip(5);
                }

                if ((int)reading.RightTrigger > 0 && fireSuppressor == false)
                {
                    fireSuppressor = true;
                    OnFire(null, null);
                }
                else if((int)reading.RightTrigger == 0) // require depress of trigger before shoot another
                {
                    fireSuppressor = false;
                }
            }

In the code above we ask from the controller what are all the current readings in it. After that we check if the right thumb stick has been moved. I checked values above and below 0.4 so the user don’t have to move the stick exactly horizontally for the ship to move. After moving the ship I’m checking if the right trigger has been pressed, and it has been released between previous visit to this loop, forcing the player to pull the trigger for each shot.

Now you can test the game and you should be able to move the ship with right thumb stick and shoot with right trigger. I tested it with connecting Xbox One controller with the charging cable to the PC and it worked like a charm. The same code should run as it is with Xbox 360 controller as well.

One more addition is that we should be able to start the game with the controller as well. Go to the Startpage.xaml, change the StartButton Content to:”Start (A)”. Open the StartPage.xaml.cs and add the following using:

using Windows.Gaming.Input; // XBOX

After you’ve done that, find the MoveStars -method. Add the following code to the beginning of it:

           if (App.GameController != null)
            {
                GamepadReading reading = App.GameController.GetCurrentReading();

                if (reading.Buttons == GamepadButtons.A)
                {
                    OnStart(null, null);
                }
            }

Find the OnStart -method, and add the following to the beginning of it:

Move.Completed -= MoveStars;
            Move.Stop();

That’s it, now you can test your game and you should be able to start it by pressing the A-button on your Xbox controller, move your ship and shoot. I hope you are having fun with these and do leave comments what you would like to see next incorporated to the game (sounds are coming next, otherwise I’m open to suggestions).

Posted in Uncategorized | Leave a comment

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

Moving the ship
When we’re doing a universal app, we have to take in account that there are several possible ways for users to control the game. Phones and tablets have touch screens, but on desktop still most of us prefer to use keyboard to play games.

For doing the movements, we need to be aware of the screen dimensions. Add these member variables to App.xaml.cs class:

public static double ScreenWidth { get; set; }
public static double ScreenHeight { get; set; }
public static int Highscore { get; set; }

We set these values in StartPage.xaml.cs, at the end of the constructor, after the Loaded -lambda:

#if WINDOWS_PHONE_APP
            App.ScreenWidth = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Bounds.Width;
            App.ScreenHeight = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Bounds.Height;
#endif
#if WINDOWS_APP
            
            App.ScreenWidth = Window.Current.Bounds.Width;
            App.ScreenHeight = Window.Current.Bounds.Height;
#endif

Here we used #if statements to run different code depending on the platform we’re running, the code will be compiled to include just the platform specific code for each build for Phone and Windows.

Now we open the GamePage.xaml.cs and add the following member variables to keep track of the ship position:

private double shipPosition;
private readonly double shipHorizontalPosition = App.ScreenHeight - 50;

Now we’re ready to create the actual method to move the ship. We add first this to the top of the GamePage.xaml.cs:

using Windows.System;

And then this to the end of the GamePage.xaml.cs:

private void MoveShip(int amount)
{
    shipPosition += amount;
 
    // Let's make sure that the ship stays in the screen
    if (shipPosition > LayoutRoot.ActualWidth - 30)
    {
        shipPosition = LayoutRoot.ActualWidth - 30;
    }
    else if (shipPosition < 0)
    {
        shipPosition = 0;
    }
 
    Rocket.Margin = new Thickness(shipPosition, shipHorizontalPosition, 0, 0);
}

The method moves the ship the amount specified in the calling function (in pixels), and checks that it doesn’t go over the boundaries from left or right.

Next we’ll capture the keyboard in case the user is playing with desktop machine. Let’s create the event handler for key events. Open GamePage.xaml.cs constructor, and add the following after InitializeComponent():

Loaded += (sender, args) =>
{
    // Resize move controls to fit the area
    LeftCanvas.Width = LeftCanvas.Height = (LeftArea.ActualWidth / 2) - 10;
    RightCanvas.Width = RightCanvas.Height = (LeftArea.ActualWidth / 2) - 10;

    // Position the ship to the bottom center of the screen
    shipPosition = LayoutRoot.ActualWidth / 2;
    Rocket.Margin = new Thickness(shipPosition, shipHorizontalPosition, 0, 0);
 
    Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
};

Next we add the actual code to handle the key presses by adding the following method:

private void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
{
    switch (args.VirtualKey)
    {
        case VirtualKey.Left:
            MoveShip(-5);
            break;
        case VirtualKey.Right:
            MoveShip(5);
            break;
        case VirtualKey.Space:
            OnFire(null, null);
            break;
        default:
            break;
    }
}

Star field background
We had one type of particle engine on the start screen, but I think we need something of a more traditional kind to create sense of moving for the ship. First we need to add one using –statement to the top of the file:

using Windows.UI;

Then we need to add some more member variables for the starfield:

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

Here’s altered versions of CreateStar and MoveStars methods, which we add to the GamePage.xaml.cs:

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

    foreach (Dot star in stars)
    {
        Canvas.SetLeft(star.Shape, Canvas.GetLeft(star.Shape) + star.Velocity.X);
        Canvas.SetTop(star.Shape, Canvas.GetTop(star.Shape) + star.Velocity.Y);

        if (Canvas.GetTop(star.Shape) > LayoutRoot.ActualHeight)
        {
            int left = randomizer.Next(0, (int)LayoutRoot.ActualWidth);
            Canvas.SetLeft(star.Shape, left);
            Canvas.SetTop(star.Shape, 0);
        }
    }
    Move.Begin();
}
private void CreateStar()
{
    var star = new Dot()
    {
        Shape = new Ellipse() { Height = 2, Width = 2 },
        Velocity = new Point(0, randomizer.Next(1, 5))
    };

    int left = randomizer.Next(0, (int)LayoutRoot.ActualWidth);
    Canvas.SetLeft(star.Shape, left);
    Canvas.SetTop(star.Shape, 0);
    Canvas.SetZIndex(star.Shape, 1);
            
    // Set color
    byte c = (byte)randomizer.Next(10,255);
    star.Shape.Fill = new SolidColorBrush(Color.FromArgb(c, c, c, c));

    stars.Add(star);
    LayoutRoot.Children.Add(star.Shape);
}

Now we go to the constructor of the same class, and add inside the end of the Loaded lambda the following code:

// Starfield background
CreateStar();
Move.Completed += MoveStars;
Move.Begin();

Now if you run the game, you see how stars are falling in different speeds from the top of the screen, creating sense of depth and speed.

Adding enemies
What would a shoot’em up be without any enemies to shoot? Next we’ll add some enemies to the screen to get some action to the screen.

Let’s create a new UserControl, and call it Bobo by right clicking the Shared project, and Add, New Item, User Control. You could give it some nice bitmap images, but for this exercise I’m using XAML to draw the the creature. Open Bobo.xaml and copy/paste the following on top the XAML:

<UserControl
    x:Class="MySpaceInvanders.Bobo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Width="60" Height="60">
 
    <Canvas Width="60" Height="60">
        <Ellipse x:Name="InsideEllipse" Width="60" Height="60" Margin="0,0"/>
        <Polygon Stroke="Black" Fill="Green" Points="10,10,5,0,15,5"/>
        <Polygon Stroke="Black" Fill="Green" Points="45,5,55,0,50,10"/>
        <Ellipse Width="5" Height="5" Fill="Gold" Margin="20,20" />
        <Ellipse Width="5" Height="5" Fill="Gold" Margin="35,20" />
        <Ellipse Width="30" Height="8" Fill="HotPink" Margin="15,40" />
    </Canvas>
</UserControl>

Open the Bobo.xaml.cs and add the following member variables to the class:

public int AreaWidth { get; set; }
public Point Location { get; set; }
public bool Dead { get; set; }
public int Worth { get; set; } // amount of score for kill
public int Type; // 1 - green, 2 - blue, 3 - mega
private readonly Random randomizer = new Random();
public double Velocity;
private int direction;
private int directionCount = 0; // don't change direction on every loop

Add also the velocity and type randomizer to the constructor, just after the InitializeComponent –call:

Velocity = randomizer.Next(1, 3);
Type = randomizer.Next(1, 4);
if (Type == 3)
{
    Velocity = 4;
}
SetType();

Now we have three different types of enemies, and one of them moves faster than the others. For the enemy to move on the screen, we’ll add the Move method for it:

public void Move()
 {
     int move;
 
     // Randomize the move direction
     if (directionCount == 0)
     {
         direction = randomizer.Next(1, 3);
     }
     if (direction == 1)
     {
         move = -1;
     }
     else
     {
         move = 1;
     }
     directionCount++;
 
     // Change direction every 30 count
     if (directionCount > 30)
     {
         directionCount = 0;
     }
 
     // Check that the bobo doesn't go through the game area walls
     if (Location.X + direction < 0)
     {
         move = 0;
     }
     if (Location.X + direction > AreaWidth)
     {
         move = AreaWidth;
     }
 
     // Set the new location
     Location = new Point(Location.X + move, Location.Y + Velocity);
 }

We need to add also method to set the color according to the type of the enemy and give them unique kill score. Add the following method to Bobo.xaml.cs:

private void SetType()
{
    switch (Type)
    {
        case 1:
            SetFill(Color.FromArgb(0xFF, 0x00, 0xA2, 0x07), Color.FromArgb(0xFF, 0x3A, 0xFF, 0x00));
            Worth = 10;
            break;
        case 2:
            SetFill(Color.FromArgb(0xFF, 0x00, 0x00, 0xa0), Color.FromArgb(0xFF, 0x00, 0x0F, 0xff));
            Worth = 20;
            break;
        case 3:
            SetFill(Color.FromArgb(0xFF, 0xaf, 0x00, 0x00), Color.FromArgb(0xFF, 0xff, 0x0F, 0x00));
            Worth = 50;
            break;
    }
}

private void SetFill(Color start, Color end)
{
    var startGradient = new GradientStop();
    var endGradient = new GradientStop();
    startGradient.Color = start;
    startGradient.Offset = 1;
    endGradient.Color = end;
    var collection = new GradientStopCollection();
    collection.Add(startGradient);
    collection.Add(endGradient);

    InsideEllipse.Fill = new LinearGradientBrush(collection, 0);
}

Now we have a nasty looking foe for our ship to shoot at. Next we open the GamePage.xaml.cs and add again some prerequisites for our swarm of enemies. Add the following member variables:

private List<Bobo> enemies = new List<Bobo>();
private int maxEnemies = 20;
private DispatcherTimer timer = new DispatcherTimer();
private int Level { get; set; } // Player level 
private int Score { get; set; } // Game score

You can adjust the game difficulty by increasing maxEnemies at later level of the game for example.

We have everything set for our enemies to appear on the screen. We need to just add them to the GamePage.xaml.cs. First edit the Loaded –lambda on constructor to include the following at the bottom of it:

timer.Tick += TimerOnTick;
timer.Interval = new TimeSpan(0, 0, 0, 2);
timer.Start();

And then the Tick method to call:

/// <summary>
/// Create a new enemy if not max amount on the screen already
/// </summary>
/// <param name="sender"></param>
/// <param name="o"></param>
private void TimerOnTick(object sender, object o)
{
    if (enemies.Count < maxEnemies)
    {
        var enemy = new Bobo
        {
            AreaWidth = (int)LayoutRoot.ActualWidth,
            Location = new Point(randomizer.Next(0, (int)LayoutRoot.ActualWidth - 80), 0)
        };
        if (enemy.Type == 3)
        {
            // Make the red enemy smaller and more difficult to hit
            var scaleTransform = new ScaleTransform();
            scaleTransform.ScaleX = scaleTransform.ScaleX * 0.50;
            scaleTransform.ScaleY = scaleTransform.ScaleY * 0.50;
            enemy.RenderTransform = scaleTransform;
            enemy.Width = 30;
            enemy.Height = 30;
        }
        enemy.Velocity = enemy.Velocity * ((Level / (double)10) + 1);
        enemies.Add(enemy);
        Canvas.SetZIndex(enemy, 7);
        LayoutRoot.Children.Add(enemy);
    }
}

All this code will create different types of monsters to the screen, but they’re still sitting static on the top. That’s kind of boring, so let’s add the long awaited game loop to move them:

private void GameLoop(object sender, object e)
{
    if (goingRight)
        MoveShip(5);
    if (goingLeft)
        MoveShip(-5);
    // TODO - collision test

    // TODO - move bullets

    // Move enemies
    for (int i = 0; i < enemies.Count; i++)
    {
        if (enemies[i].Dead == false)
        {
            enemies[i].Move();
            enemies[i].Margin = new Thickness(enemies[i].Location.X, enemies[i].Location.Y, 0, 0);
        }
 
        if (enemies[i].Margin.Top > App.ScreenHeight || enemies[i].Dead)
        {
            LayoutRoot.Children.Remove(enemies[i]);
            enemies.Remove(enemies[i]);
        }
    }
}

Now we just have to make sure our game loop gets called, so we open the constructor, and add as very last line, after the Loading –lambda has closed, the following line:

CompositionTarget.Rendering += GameLoop;

Go ahead, try the project now, and you should see the star field moving, ship should respond to the keyboard and enemies should move randomly from top to down.

Open fire!
Now our little game seems to be a bit boring, enemies come and sail through your ship and you can’t shoot. We need to add collision detection and possibility to shoot the enemies to make it a bit more interesting. Let’s start with shooting! Add the following member variables to GamePage.xaml.cs:

private List<Ellipse> bullets = new List<Ellipse>(); // Bullets on the screen
private bool gameRunning = true; // Did we die already

and for ellipses we need to add also this using:

using Windows.UI.Xaml.Shapes;

Now we edit the OnFire –method we added on the second part of the tutorial. Add the following code to it:

if (gameRunning)
{
    var bullet = new Ellipse
    {
        Width = 5, Height = 5, Fill = new SolidColorBrush(Colors.Red)
    };
    bullet.Margin = new Thickness(shipPosition + (Rocket.Width/2) - (bullet.Width/2),
        shipHorizontalPosition + 2, 0, 0);
    LayoutRoot.Children.Add(bullet);
    bullets.Add(bullet);
}

The code above checks that the player is still alive, and if yes, creates a new ellipse as a bullet and adds it to the bullet list, so we can later easily check if any of the bullets hit anything on the screen. At this point we have static bullets in the screen, so logical step is to add moving functionality to the game by adding this:

private void MoveBullet(Ellipse ellipse)
{
    if ((ellipse.Margin.Top - 10) > 0)
    {
        ellipse.Margin = new Thickness(ellipse.Margin.Left, ellipse.Margin.Top - 10, 0, 0);
        HitTest(ellipse);
    }
    else
    {
        bullets.Remove(ellipse);
        LayoutRoot.Children.Remove(ellipse);
    }
}

The code above moves the bullet 10 pixels upwards until it goes off the screen. At that point it is removed from the bullet list. Let’s add the HitTest method to see if our bullets actually hit anything:

private void HitTest(Ellipse ellipse)
{
    for (int i = 0; i < enemies.Count; i++)
    {
        var enemyInFire = new Rect(enemies[i].Location.X, enemies[i].Location.Y, enemies[i].ActualWidth, enemies[i].ActualHeight);
        if (enemyInFire.Contains(new Point(ellipse.Margin.Left, ellipse.Margin.Top)))
        {
            Score += enemies[i].Worth;
            ScoreBoard.Text = Score.ToString();
            if (Score > App.Highscore)
            {
                App.Highscore = Score;
                HighscoreBoard.Text = Score.ToString();
            }
            LayoutRoot.Children.Remove(ellipse);
            bullets.Remove(ellipse);
            enemies[i].Dead = true;
            return;
        }
    }
}

To move the bullets, add this to the GameLoop -method, over the // TODO – move bullets text:

for (int i = 0; i < bullets.Count; i++)
{
    MoveBullet(bullets[i]);
}

At this point, you’re ready to shoot some aliens from outer space! But it kind of gets boring as there’s no way you can die yet, as we’re not testing if the aliens hit you. Let’s add few more things and it starts to come together. First we need the famous game over notification. Add this member variable to GamePage.xaml.cs:

private TextBlock GameOver = new TextBlock();

After that we need a crash test method:

private void CrashTest()
{
    for (int i = 0; i < enemies.Count; i++)
    {
        var enemyCreature = new Rect(enemies[i].Location.X, enemies[i].Location.Y, enemies[i].ActualWidth, enemies[i].ActualHeight);
        enemyCreature.Intersect(new Rect(Rocket.Margin.Left, Rocket.Margin.Top, Rocket.ActualWidth,
            Rocket.Margin.Top));
        if (!enemyCreature.IsEmpty)
        {
            CompositionTarget.Rendering -= GameLoop;
            Move.Completed -= MoveStars;
 
            GameOver.Text = "Game Over!";
            GameOver.FontSize = 48;
            GameOver.VerticalAlignment = VerticalAlignment.Center;
            GameOver.HorizontalAlignment = HorizontalAlignment.Center;
            Grid.SetColumn(GameOver, 1);
 
            MainGrid.Children.Add(GameOver);
            gameRunning = false;
 
            if (App.Highscore < Score)
            {
                App.Highscore = Score;
            }
        }
    }
}

Finally we need to add to the GameLoop call to the CrashTest, overwriting the // TODO – collision test with call to our method: CrashTest();

If you try the game, you soon realize that if the enemies crash to your ship, that’s the end of you! This is the end of part three of Universal Games for Windows. On the next post we’ll continue to improve the game by adding universal high score system, levels, navigation and other relevant things to finish up the game.

Download the solution so far from here

Posted in Uncategorized | Leave a comment

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