Click here to Skip to main content
Click here to Skip to main content

Tap Madness, Windows 8 Metro game for Ultrabooks

By , 17 Oct 2012
Rate this:
Please Sign up or sign in to vote.

Introduction

In this article you will have opportunity to follow me on the path of making Metro game from scratch. I've decided on a game because, most importantly, it is a great way to showcase unique hardware capabilities of an Ultrabook. Meaning - throughout the course of this article we will have opportunity to talk about different types of touches, detect gestures like shake, work with gyroscope and implement all kinds of crazy stuff that will make our game an interesting experience.

As you can see from my track record – I like to write articles as detailed guides that (hopefully) leave people with good idea on how they should proceed after reading. Since developing for Windows 8 is somewhat new topic, I presume that lots of readers are interested in jumpstarting their own development. That’s the biggest reason why I organized the article as a kind of jumpstart introduction to Windows 8 development. Meaning that I will not only touch on how to work with unique hardware features of an Ultrabook, but will also try to provide a more general tips throughout the article – the ones that helped me start developing - the ones that I hope can also save you some time.

Please note that this article is a work in progress. That, along with the fact that it is meant to be a comprehensive guide, implies that feedback is more than welcome. If you have an idea on how to do something I’ve mentioned in the article better – please post in comments and I’ll try my best to incorporate your advice in the article and properly reference you.

Article will be split into three chapters, namely:

  1. Foundation – how to setup IDE and evade common installation problems, what options you have when it comes Metro development, what base knowledge you’ll need to kickstart your Metro development.
  2. Coding startup – how are to do common tasks (like Modal Popup) in Metro, save user settings, architect your application, handle styling etc.
  3. Going deep – advanced talk on UIElements and animation, data biding, types of touch gestures and how to handle them in code, working with data sent over the wire

But before we start, let’s take a quick glance on the game screen in the middle of tapping frenzy:

Game in Action

Now that we have idea on how result will look like - let's try to build it, shall we?

Foundation

One quick suggestion for those who have Windows 8 & Visual Studio 2012 and have already went through bunch of Metro “Hello World” apps - please feel free to jump straight to the coding part.

Everyone else, let’s quickly go over setting up Windows 8 and Visual Studio 2012.

Installing Windows 8 and Visual Studio 2012

  1. I wholeheartedly recommend that you install Windows 8 in a virtual machine so you can run it in parallel with your everyday Windows. My guide presumes you will be using VirtualBox – because it is excellent VM and on top of that it works regardless of version of Windows you have.

    If you have Professional version of Windows 7 / Vista, you can go with Virtual PC
  2. Once you download and install VirtualBox make sure to set following parameters within the VM you create for Windows 8 installation; otherwise you may run into weird problems (VisualStudio or your application may crash for no obvious reason):
    • General -> Advanced
      • Shared Clipboard -> Bidirectional (we’ll need to install Guest Additions to enable clipboard sharing, step 5)
    • System -> Motherboard
      • Chipset : ICH9
      • Check Enable IO APIC
      • Base Memory >= 2048
    • System -> Processor >= 2
    • Display
      • Uncheck 3D Acceleration
      • Uncheck 2D Video Acceleration
    • Network -> Adapter 1
      • Check Enable Network Adapter
      • Attached to: Bridged Adapter
      • Name: (Select your LAN network card from the list)
  3.  Download Windows 8 Release Preview ISO
  4. Attach downloaded ISO image to Virtual Machine you’ve created in step 2 and install Windows 8
  5.  After Windows 8 installation is completed, install Guest Additions for Virtual Box (Devices -> Install Guest Additions)
    • a. If you need help with this step, check out following guide http://www.sysprobs.com/guide-install-windows-8-virtualbox
  6. 6. Be sure not to get into whole mumbo-jumbo of installing Microsoft Visual Studio 2012 Express as it most cases it won’t work with Windows 8 RC. Instead – download 90 day Ultimate evaluation (here is the direct link)
  7. That’s it! Fire up Visual Studio once done!

Random things that helped me to navigate around Windows 8 when I installed it for the first time:

  • The fastest way to Desktop is still WindowsKey+D
  • If you are missing My Computer (and other icons): right click on Desktop -> Personalize -> Change Desktop Icons -> check the ones you want
  • To show file extensions: Open My Computer -> View (top bar) -> check File name extensions

Creating your first project

When you start Visual Studio you’ll be probably wondering which project you should select when you go: File -> New -> Project.

Basically, the Windows 8 will feature two types of apps: “Classic” and “Metro”. What’s the difference, you ask?

  1. Classical - Apps are standard, “old”, desktop Windows apps. Meaning, they’ll look and feel like apps look and feel on Windows 7 and earlier versions of Windows. There are no restrictions on distribution of these apps, and you can make one of these for Ultrabook competition (there are 6 categories)
  2. Metro – new breed of apps, specifically designed for Windows 8. It is expected that these apps will be exclusively distributed through Microsoft’s AppStore. They will need to follow bunch of Microsoft guidelines and integrate fully with “Windows 8 experience”. Ultrabook competition features 1 category for these type of app.

In this article I will be building a Metro app – since we are learning new tricks, we may well go all out, right?

You have choice

Please note that you can build Windows Metro app using different flavors:

  • JS & HTML5
  • C# & XAML
  • VB.NET & XAML
  • C++ & DirectX

For sake of brevity, I won’t dwelve more in this topic – if you guys wish to see this guide in JS & HTML5, I’m sure you will let me know in the comments Wink | ;)

So, for us, for now – it is File -> New -> Project -> Visual C# -> Windows Metro style -> Blank App

Coding startup

Before we dig deep into the code, let’s take a look at some important concepts that we need under our belt.

The first thing we need to wrap around our heads is the application lifecycle management of a Windows Metro app. Unlike on “standard Windows 7 PC desktop”, personal computers like Ultrabook will function similary to how smartphones function right now – user may quite often initiate suspend power state. Apps are expected to take notice of this and save their state once suspend notice hits in.

Also, there are some changes in traditional “close app” pattern. In fact, if you want to have a good laugh, Google for “How to close Windows 8 Metro app”. Most of the Windows 8 apps don’t have “Exit” button (as Windows Metro App guidelines suggest) and as majority of people don’t know about ALT+F4, you can find some pretty crazy “close tutorials”. Keep in mind however, that even if you use ALT+F4, application is not immediately closed – your application is first suspended (and notified about it) and then terminated after 10 seconds.

You should know that you only get notified from OS when your application goes from running to suspended state. You won’t get notified when your application is terminated! This is important because suspended applications may be terminated at any time – if OS needs to free up memory for other apps or to save power. So, if user ALT-TABs out of your app, it’s not a guarantee that it’ll remain suspended in the background indefinitely.

Game in Action

The biggest thing to take away from previous paragraph is that you should save any critical data whenever you get suspended notification. Luckily, Microsoft has eased implementation of this and pretty much generates everything you need with just few clicks. Let’s see how this works:

  1. Right click on Project
  2. Add -> New Item
  3. Select Windows Metro style -> Basic Page
  4. Give the file name TitlePage.xaml and press OK
  5. You will be prompted to add “missing files automatically”. Select Yes.

Now, if you take a look into Common directory, you’ll find that, other than adding TitlePage.xaml to the root directory, Visual Studio generated bunch of files (the only one previously there was StandardStyles.xaml). For topic we are currently on, the most important classs are SuspensionManager and LayoutAwarePage.

Unlike traditional apps, Metro apps are more like websites. You don’t have forms, but pages. And in 99% of cases you won’t have several forms opened – there will rather always be one page which takes up full screen.

Taking into account what we previously said about app lifecycle management – regardless of whether your application was suspended and then resumed (in which case state will be automatically restored) or whether your application was terminated and is now activated (in which case you need to manually restore the state), when user ALT-TABs back to your application (or starts it again), he expects to see app as he left it.

SuspensionManager class helps because it streamlines state saving process. First, if you call SuspensionManager.RegisterFrame(root, "appFrame"); your navigation history as you move between LayoutAwarePages will be automatically saved. Then, all you need to do to jump right back to the "right" page once your application is relaunched is to call SuspensionManager.RestoreAsync. Second, LayoutAwarePage class gives you SaveState and LoadState events that are automatically invoked when State of the pages needs to be saved or loaded.

Now that we know how navigation between different pages is handled, let’s see what pages we’ll need and look into implementing them.

Title Page (Main Menu)

On our Main Menu, we want to provide user several options, each of which will serve us to tackle and illustrate different development challenges:

  1. Start Game – core of our development effort, we’ll have whole chapter for this Page
  2. High Scores – working with remote data, saving user scores
  3. About – will allows us to talk about TextBlocks, linking text to websites and Styling
  4. Exit – just for fun button – so that our users don’t search for “Terminate Windows 8 App guide”

Since we only need 4 buttons, our XAML won’t be too complicated:

<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="30" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="200" />
    </Grid.ColumnDefinitions>

    <Button x:Name="btnStartGame" Grid.Row="0" Content="{StaticResource StartGame}" Click="btnStartGame_Click_1" Style="{StaticResource MainMenuButtonStyle}" />
    <Button x:Name="btnHighScores" Grid.Row="1" Content="{StaticResource HighScores}" Click="btnHighScores_Click_1" Style="{StaticResource MainMenuButtonStyle}" />
    <Button x:Name="btnAbout" Grid.Row="2" Content="{StaticResource About}" Click="btnAbout_Click_1" Style="{StaticResource MainMenuButtonStyle}" />
    <TextBlock Grid.Row="3" />
    <Button x:Name="btnExit" Grid.Row="4" Content="{StaticResource Exit}" Click="btnExit_Click_1" Style="{StaticResource MainMenuButtonStyle}" />
</Grid>

Several things deserve additional explanation:

  1. Implementing “just-for-fun” Exit button is not too hard. Interestingly enough, even though guidelines suggest Metro Apps without Exit option, shutting down your app is pretty straightforward - in btnExit_Click_1 event handler method we just need to invoke: App.Current.Exit();
  2. StaticResources can reference both resources you define in-line or in external files. In our case, for sake of demonstration, I am defining Strings in-line and Styles in external Styles/CustomStyle.xaml file.
  3. So, Strings are defined in-line are within <Page.Resources>, like this:
    <Page.Resources>
        <x:String x:Key="AppName">Tap Madness</x:String>
    
        <x:String x:Key="StartGame">Start Game</x:String>
        <x:String x:Key="HighScores">High Scores</x:String>
        <x:String x:Key="About">About</x:String>
        <x:String x:Key="Exit">Exit</x:String>
    </Page.Resources>        
  4. Note that you need to "register" any external style file you have within App.xaml by adding entry. After that is done, you can populate that file with different styles:
    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TapMadness">
           
        <Style x:Key="MainMenuButtonStyle" TargetType="Button">
            <Setter Property="HorizontalAlignment" Value="Stretch" />
            <Setter Property="FontSize" Value="40" />
        </Style>        
    
    </ResourceDictionary>
    
  5. It is possible to style controls without manually adding Style attribute to every UIElement (Style="{StaticResource MainMenuButtonStyle}"). We will do this within MainPage to style all TextBlocks, so keep your eyes peeled.

For High Scores we will obviously need user’s name. This can be done in numerous ways, but in order to investigate popups and settings, let’s follow this path: when application starts for the first time, we'll make modal dialog and ask user to enter his name. Modal dialog shouldn’t be too hard, right?

Well, as you’ll find it – a real Modal dialog is currently not part of .NET Framework. MessageBox (or MessageDialog as it is called now) is there:

var v = new Windows.UI.Popups.MessageDialog("Content", "Title");
v.ShowAsync();

But unfortunately you can only pass string into this class; you can't use your custom UserControl (for example).

If you are working with JS/HTML5 you can use with nice looking WinJS.UI.Flyout, but for all the other technologies – you need to utilize base Popup class and do dirty work yourself.

After search for a library that would allow me to invoke Flyout-like modal dialog yielded no results, I was forced to come up with my own class for this. The class allows you to wrap up your user control and display it nicely:

public class PopupBase : UserControl
{
    public Popup ShowPopup(FrameworkElement source)
    {
        if (ParentPopup == null)
        {
            // prepare popup and grid
            Popup flyout = new Popup();
            Grid rootGrid = new Grid();

            rootGrid.RowDefinitions.Add(new RowDefinition());
            rootGrid.RowDefinitions.Add(new RowDefinition());
            rootGrid.RowDefinitions.Add(new RowDefinition());

            addGrid(rootGrid, Color.FromArgb(150, 0, 0, 0), 0);
            addGrid(rootGrid, Color.FromArgb(150, 0, 0, 0), 2);
            Grid cont = addGrid(rootGrid, Color.FromArgb(255, 19, 135, 67), 1);

            cont.Children.Add(this);

            var windowBounds = Window.Current.Bounds;

            rootGrid.Width = windowBounds.Width;
            rootGrid.Height = windowBounds.Height;

            flyout.IsLightDismissEnabled = false;

            flyout.Child = rootGrid;

            // spread control
            this.HorizontalAlignment = HorizontalAlignment.Center;
            this.VerticalAlignment = VerticalAlignment.Center;

            //
            ParentPopup = flyout;
        }

        ParentPopup.IsOpen = true;
        return ParentPopup;
    }

    private static Grid addGrid(Grid rootGrid, Color background, int at)
    {
        Grid dark1 = new Grid();
        dark1.Background = new SolidColorBrush(background);
        Grid.SetRow(dark1, at);
        rootGrid.Children.Add(dark1);

        return dark1;
    }

    public Popup ParentPopup { get; set; }
    public void ClosePopup()
    {
        ParentPopup.IsOpen = false;
    }
}

To use the class, simply create XAML UserControl and make it inherit from PopupBase. Finally, when you need the popup, simply instantiate your UserControl and call ShowPopup and pass in your pageRoot. In our game, we want to make sure that we popup is displayed on the first launch, when we don’t have user’s name. So here is how we would do that:

private ProfileUserControl _pu = new ProfileUserControl();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    if (GameState.Instance.PlayerName == null)
    {
        _pu.ShowPopup(pageRoot);
    }
}

And here is the result:

Popup

Now that modal dialog is in place, let’s look into loading and saving of application settings. Here is how PlayerName property is implemented:

// GameState class
public string PlayerName
{
    get
    {
        if (_playerName == null)
            _playerName = UtilFunctions.LoadRoamingSetting
<string>("userName");
        return _playerName;
    }
    set
    {
        _playerName = value;
        UtilFunctions.SaveRoamingSetting("userName", _playerName);
    }
}

// ...

// UtilFunctions class
public static T LoadRoamingSetting<T>(string key)
{
    Windows.Storage.ApplicationDataContainer roamingSettings =
        Windows.Storage.ApplicationData.Current.RoamingSettings;
    if (roamingSettings.Values.ContainsKey(key))
    {
        return (T)roamingSettings.Values[key];
    }
    else
    {
        return default(T);
    }
}
public static void SaveRoamingSetting(string key, object val)
{
    Windows.Storage.ApplicationDataContainer roamingSettings =
        Windows.Storage.ApplicationData.Current.RoamingSettings;
    roamingSettings.Values[key] = val;
}

It’s important to say that application settings come in two flavors: RoamingSettings and LocalSettings. You want to use LocalSettings when settings you are saving are specific to the machine user is currently working on. On the other hand, you want to use RoamingSettings when you want settings to propagate across different machines - this class automatically uploads them to the clound in the background. Meaning, if our user logged in to another machine using same Windows credentials and started the game – he wouldn't need to setup in-game name twice.

About page

-Coming soon

High Score page

-Coming soon

Going deep

Now that we have foundation of our game setup it’s time to go deep into the main part – coding the engine.

The first order of business when it comes to the engine is generating and animating shapes we will be interacting with by using touch, accelerometer and other fancy hardware that comes with Windows 8 Ultrabook. So how to do that?

Making the shapes dance

Animating shapes is actually tougher than it seems on the first glance. Let’s take a look at the easiest animation code we can come up with:

// generate shape
Shape rect = new Rectangle();
rect.Width = 10;
rect.Height = 10;
rect.Fill = new SolidColorBrush(Colors.Blue);
// add to canvas
Canvas.SetLeft(rect, 300);
Canvas.SetTop(rect, 300);
mainFrame.Children.Add(rect);

// generate animation
DoubleAnimation da = new DoubleAnimation();
da.From = 10;
da.To = 100;
da.Duration = new Duration(TimeSpan.FromSeconds(5));
da.AutoReverse = true;
da.EnableDependentAnimation = true;  // animation won’t work without this 


// generate storyboard
Storyboard sb = new Storyboard();

Storyboard.SetTarget(da, rect);
Storyboard.SetTargetProperty(da, "Width");
// Storyboard.SetTargetProperty(da, "Height"); //Only one property unfortunately :(

sb.Children.Add(da);

sb.Begin();

Looking at code, the first and most obvious problem is that we can’t use one DoubleAnimation for both Width and Height of the Shape – we would need to make two instances. Which is not a big deal - if that was the end of the road. But because we plan on using Canvas.SetLeft and Canvas.SetTop – and are not defining the middle point of the Shape, but rather Top and Left position, we would need to modify those two properties as too.

Obviously there are lots of approaches for solving this problem, but let’s take the path of implementing one “animation” property per shape to keep things straightforward. And we’ll try to do it “less exciting” way by using EnableDependentAnimation; if you want to take a look at how complicated this task of animating property can get – read post on this page.

Here is a foundation of our class that will hold Shapes:

public class FunkyShape : UserControl
{
    public double Animator
    {
        get { return (double)GetValue(AnimatorProperty); }
        set { SetValue(AnimatorProperty, value); }
    }

    public static DependencyProperty AnimatorProperty;
    static FunkyShape()
    {
        AnimatorProperty = DependencyProperty.Register("Animator", typeof(double), typeof(FunkyShape),
        new PropertyMetadata(DependencyProperty.UnsetValue, new PropertyChangedCallback(Animator_Changed)));
    }

    private static void Animator_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        double delta = (double)e.NewValue - (double)e.OldValue;

        ((FunkyShape)d).ProcessDelta((double)e.NewValue, delta);
    }

    private void ProcessDelta(double val, double delta)
    {
        Holder.Width = val;
        Holder.Height = val;

        // Keep shape centered
        HolderPosition.X -= delta / 2;
        HolderPosition.Y -= delta / 2;
            
        // Keep shape centered
        HolderRotation.CenterX = HolderPosition.X;
        HolderRotation.CenterY = HolderPosition.Y;       
    }

    private Shape Holder;

    // Rest of the class...
}

Note that we are required to register Animator as DependencyProperty. This in turn means that we are forced to handle changes through Animator_Changed method. In that method we not only increase/decrease size of our shape, but also make sure that it remains in place.

Now, let’s look at the code within our FunkyShape class that will deal with Shape creation, and adding it to the Canvas:

public static FunkyShape GenerateRandom(Canvas canvas, Action
<FunkyShape> tapped, Action<FunkyShape> expired)
{
    Shape s = null;
    int shapeType = UtilFunctions.Rand.Next(3);

    if (shapeType == 0)
    {
        s = new Ellipse();
    }
    else if (shapeType == 1)
    {
        s = new Rectangle();
    }
    else if (shapeType == 2)
    {
        s = new Triangle();
    }

    Color c = new Color()
    {
        A = byte.MaxValue,
        R = (byte)UtilFunctions.Rand.Next(0, 256),
        G = (byte)UtilFunctions.Rand.Next(0, 256),
        B = (byte)UtilFunctions.Rand.Next(0, 256)
    };
    s.Fill = new SolidColorBrush(c);

    int margin = 10;
    Point p = new Point()
    {
        X = UtilFunctions.Rand.Next(margin, (int)Window.Current.Bounds.Width - margin),
        Y = UtilFunctions.Rand.Next(margin, (int)Window.Current.Bounds.Height - margin)
    };

    return new FunkyShape(canvas, s, p, tapped, expired, 200, 6000);
}

private Action<FunkyShape> _tapped;
private Action<FunkyShape> _expired;
public FunkyShape(Canvas playground, Shape shapeToInit, Point position, Action<FunkyShape> tapped, Action<FunkyShape> expired, int growToSize, int halfTimeTap)
{
    Holder = shapeToInit;

    TransformGroup myTransformGroup = new TransformGroup();
    var tt = new TranslateTransform()
    {
        X = position.X,
        Y = position.Y
    };
    myTransformGroup.Children.Add(tt);
    RotateTransform rt = new RotateTransform()
    {
        CenterX = tt.X,
        CenterY = tt.Y,
        Angle = UtilFunctions.Rand.Next(360)
    };
    myTransformGroup.Children.Add(rt);

    Holder.RenderTransform = myTransformGroup;
    Holder.RenderTransformOrigin = new Point(0.5, 0.5);
    Holder.Tapped += Holder_Tapped;

    // init done
    playground.Children.Add(Holder);

    //
    g1 = GrowAnimation(growToSize, halfTimeTap);

    //
    _tapped = tapped;
    _expired = expired;
}

Storyboard sb = new Storyboard();
DoubleAnimation g1;
void Holder_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
    sb.Stop();

    Holder.Width = 0;
    Holder.Height = 0;

    e.Handled = true;
    _tapped(this);
}

public void Animate()
{   
    Storyboard.SetTarget(g1, this);
    Storyboard.SetTargetProperty(g1, "Animator");
    sb.Children.Add(g1);
    sb.Completed += sb_Completed;
    sb.Begin();
}

void sb_Completed(object sender, object e)
{
    _expired(this);
}

public DoubleAnimation GrowAnimation(int growToSize, int halfTapTime)
{
    DoubleAnimation growAnimation = new DoubleAnimation();
    growAnimation.Duration = TimeSpan.FromMilliseconds(halfTapTime);
    growAnimation.From = 0;
    growAnimation.To = growToSize;
    growAnimation.AutoReverse = true;
    growAnimation.EnableDependentAnimation = true;
    return growAnimation;
}

All that code is there so we can easily add shape to the game canvas whenever we need it:

private void addShape()
{
    FunkyShape fs = FunkyShape.GenerateRandom(mainFrame, ShapeTapped, ShapeExpired);
    fs.Animate();
}

private void ShapeExpired(FunkyShape fs)
{
    Logic.GameState.Instance.ExpiredShape(fs);
    mainFrame.Children.Remove(fs);
}

private void ShapeTapped(FunkyShape fs)
{
    Logic.GameState.Instance.ScoreShape(fs);
    mainFrame.Children.Remove(fs);
}

You would expect that this is it – that we should now be able to implement invocation of addShape within 1 second Timer, run our solution by pressing F5 and see Shape creation galore shine all over the screen.

But if you tried to do that, you would be greeted with following Exception:
WinRT information: Cannot resolve TargetProperty Animator on specified object.

So, we actually need to do one more, simple thing that took me a whole day of trial-and-error and digging around the Internet to find. You need to add an instance of FunkyShape in the XAML where the Canvas is (this is the reason we made FunkyShape class inherit from UserControl):

<Canvas Name="mainFrame" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
	<Tm:FunkyShape />
</Canvas>

I am unsure why this is requirement as MSDN doesn’t have much to say on this subject. Also, if you go over MSDN examples on animation, you’ll see that most of them are simplistic with StoryBoards and Animation instances defined within XAML - doing animation with code-behind approach is mostly left out. So, if anybody can shed more light on this subject – feel free to do so in comments.

Touch me in different ways

Looking at code for generation of Shapes, you can see that we are already handling tapping on our Shapes. Even more – when Shape is tapped we score the tap. And if Shape is not tapped by the time in gets back to size 0, we score it against the player.

But what if we wanted to provide a more diverse experience by requiring user to tap if Shape is a Circle, but slide it away if it is a Square? Or pinch it if Shape is a Triangle?

Luckily, .NET Framework provides high-level events for some of the gestures. We already saw Tapped, but DoubleTapped, RightTapped and Holding are also available. And you can disable handling of any of these events by changing right property (IsTapEnabled, IsDoubleTapEnabled, IsRightTapEnabled, IsHoldingEnabled).

As for the more complex touch gestures, like Slide, Pinch or Rotate – you need to handle them manually. What gestures you’ll be able to implement depends on what input schemes you want to support. Microsoft gives you two sets of Events depending on amount of touch support you want to implement in your application:

  1. Pointer Events – these events are meant for situations where you want to support both mouse and touch input. There are 5 events within this group, with pretty self-explanatory names:
    • PointerPressed
    • PointerMoved
    • PointerReleased
    • PointerExited
    • PointerEntered
    Through these events, you are able to handle simple touch gestures like Slide.
  2. Manipulation Events – you need to utilize these events when you want to provide advanced, multi-finger interactions within your app. Similarly to previous group, we also have 5 events:
    • ManipulationStarting
    • ManipulationStarted
    • ManipulationDelta
    • ManipulationInertiaStarting
    • ManipulationCompleted
    For these events you need a computer with a touch screen. Alternatively, you can use Simulator for development, just use left click and mouse wheel to emulate Pinch/Zoom/Rotate.

Now that we know all this, how would we implement a requirement that user need to slide a Rectangle if he wants to score? Well, actually not too hard; even using Pointer Events. First we need to make a distinction during initialization:

if (shapeToInit is Ellipse)
{
    Holder.Tapped += Holder_Tapped;
}
else if (shapeToInit is Rectangle)
{
    Holder.PointerPressed += Holder_PointerPressed;
    Holder.PointerMoved += Holder_PointerMoved;
    Holder.PointerReleased += Holder_PointerReleased;
}

And then implement EventHandlers:

// Handling Slide gesture
private const int MOVE_TO_COUNT = 20;
private Point _initalPoint;
private void Holder_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
    e.Handled = true; // do not propagate to other elements
    _initalPoint = e.GetCurrentPoint((UIElement)Holder.Parent).RawPosition;
}

void Holder_PointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
    e.Handled = true; // do not propagate to other elements
    if (_initalPoint.X != 0 && _initalPoint.Y != 0)
    {
        var currentPoint = e.GetCurrentPoint((UIElement)Holder.Parent).RawPosition;
        HolderPosition.X = currentPoint.X - (Holder.Width / 2);
        HolderPosition.Y = currentPoint.Y - (Holder.Height / 2);

        if (Math.Abs(currentPoint.X - _initalPoint.X) >= MOVE_TO_COUNT ||
            Math.Abs(currentPoint.Y - _initalPoint.Y) >= MOVE_TO_COUNT)
        {
            Holder_PointerReleased(sender, e);
            Score();
        }
    }
}

void Holder_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
    e.Handled = true; // do not propagate to other elements
    _initalPoint = new Point(0, 0);
}

// Handling simple tap
void Holder_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
    e.Handled = true; // do not propagate to other elements
    Score();
}


//
private void Score()
{
    sb.Stop();

    // TODO: Implement more fancy "exit" effect
    Holder.Width = 0;
    Holder.Height = 0;

    // Score
    _tapped(this);
}

Other than Tap, Hold and Slide; Windows 8 Touch guidelines recognize Swipe (short-distance Slide), Pinch, Rotate and Strech as a “common gestures”. Adding more shapes and implementing these gestures will be added to the article as it evolves.

Shake me, break me

-Explanation of gyroscope and basic development contents.

-Illustration of gyroscope usage through implementation of power-ups.

-Rewarding user with “Shake power up” for tapping streaks. Shake power up destroys all shapes on the screen.

-Rewarding users with “Slide power up” for executing Shake power-up on more than 10 shapes. Slide power-up allows user to slide shapes off the screen by tilting device. Double points scored for every shape destroyed this way.

Keeping the score fair

-Exploration of Binding concepts for showing the score while game is progressing

-Handling Game Over event and saving score

-Short introduction on async

-Developing simple serverside to accept High scores, keeping in mind that we may have different game modes eventually

-Uploading and downloading the data

Wrap up

Even though some pieces are missing and article is still a work in progress, I do hope I was able to provide you with solid introduction to Windows 8 development. As I said in the opening, I am looking forward to your feedback – do help me out and guide the direction in which you would wish this article to evolve.

Resources

I’ll try to keep a list of links to interesting webpages related to Windows 8 development. Feel free to contribute:

History

October 18th - Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Predrag Tomasevic
Software Developer Atama Group
United States United States
http://www.linkedin.com/in/ptomasevic

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 18 Oct 2012
Article Copyright 2012 by Predrag Tomasevic
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid