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:
- 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.
- Coding startup – how are to do common tasks (like Modal Popup) in Metro, save user settings, architect
your application, handle styling etc.
- 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:
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
- 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
- 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)
- Download Windows 8 Release Preview
ISO
-
Attach downloaded ISO image to Virtual Machine you’ve created in step 2 and install Windows 8
- 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. 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)
-
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?
- 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)
- 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 ;)
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.
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:
- Right click on Project
- Add -> New Item
- Select Windows Metro style -> Basic Page
- Give the file name TitlePage.xaml and press OK
- 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:
- Start Game – core of our development effort, we’ll have whole chapter for this Page
- High Scores – working with remote data, saving user scores
- About – will allows us to talk about TextBlocks, linking text to websites and Styling
- 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:
- 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();
- 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.
- 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>
- 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>
- 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)
{
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;
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:
Now that modal dialog is in place, let’s look into loading and saving of application settings. Here
is how PlayerName property is implemented:
public string PlayerName
{
get
{
if (_playerName == null)
_playerName = UtilFunctions.LoadRoamingSetting
<string>("userName");
return _playerName;
}
set
{
_playerName = value;
UtilFunctions.SaveRoamingSetting("userName", _playerName);
}
}
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:
Shape rect = new Rectangle();
rect.Width = 10;
rect.Height = 10;
rect.Fill = new SolidColorBrush(Colors.Blue);
Canvas.SetLeft(rect, 300);
Canvas.SetTop(rect, 300);
mainFrame.Children.Add(rect);
DoubleAnimation da = new DoubleAnimation();
da.From = 10;
da.To = 100;
da.Duration = new Duration(TimeSpan.FromSeconds(5));
da.AutoReverse = true;
da.EnableDependentAnimation = true;
Storyboard sb = new Storyboard();
Storyboard.SetTarget(da, rect);
Storyboard.SetTargetProperty(da, "Width");
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;
HolderPosition.X -= delta / 2;
HolderPosition.Y -= delta / 2;
HolderRotation.CenterX = HolderPosition.X;
HolderRotation.CenterY = HolderPosition.Y;
}
private Shape Holder;
}
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;
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:
- 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.
- 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:
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; _initalPoint = e.GetCurrentPoint((UIElement)Holder.Parent).RawPosition;
}
void Holder_PointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
e.Handled = true; 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; _initalPoint = new Point(0, 0);
}
void Holder_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
e.Handled = true; Score();
}
private void Score()
{
sb.Stop();
Holder.Width = 0;
Holder.Height = 0;
_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