Universal Apps
Overview
C# is one of the most popular languages in the industry today. Its managed interface and wide variety of built-in components make developing rapid and efficient. Coupled with XAML, a powerful mark-up language, you can build a great game with very little code! Wordament, from Microsoft Studios is built entirely on-top of C# and XAML!
What You’ll Learn
- Building a C#/XAML game sharing code across a Windows Phone app and Window Store app
Tools You’ll Use
- Visual Studio
The Challenge
We will start by creating a new project in VS Express 2013 for Windows – launch VS (Visual Studio) from the task bar or the Start Menu.
From the File Menu (1), select New Project (2).
Using the New Project window, you will create a blank Universal App from the provided project templates.
Expand the template tree on the left-hand side of the menu to get to the Store App templates for Visual C#: Installed Templates Visual C# Store Apps
To build the Tic Tac Toe game, we’ll start first with code that can be shared between both Windows and Windows Phone projects – the game board and logic. We’ll create a new XAML + C# file for this code and layout to live in. In the Solution Explorer, right-click the TicTacToe.Shared project and go to Add New Item.
To create our GameControl we’ll use the User Control template. Expand the tree on the left-hand side Installed Visual C# and select the User Control template. Call the XAML file GameControl.xaml and click Add to continue.
We’ll use the main Grid on this page to host our control and break it down into two rows, one to hold whose turn it is, the other for the actual game board.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="8*" />
</Grid.RowDefinitions>
Next, we need to create a TextBlock to hold the current player, we’ll create this inside of our grid and put it in the first row:
<TextBlock
x:Name="CurrentPlayerLabel"
Grid.Row="0"
Grid.Column="0"
TextWrapping="Wrap"
Text="Current Player"
FontSize="36"
VerticalAlignment="Top"
TextAlignment="Center"
HorizontalAlignment="Stretch">
</TextBlock>
Next inside of the main grid, we’ll create our own grid for the GameBoard. Paste the following code to create a Grid that spans the entire UserControl. The grid will be a 5x5 grid that uses Rectangles to separate the Buttons which users can click to make their move.
<Grid x:Name="GameGrid" Grid.Column="0" Grid.Row="1" Margin="0,25,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10" />
<RowDefinition Height="*" />
<RowDefinition Height="10" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--Styling to stretch the buttons to fit the grid -->
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<!--Create the lines for the gameboard-->
<Rectangle Grid.Row="0" Grid.Column="1" Grid.RowSpan="5" Fill="Gray" />
<Rectangle Grid.Row="0" Grid.Column="3" Grid.RowSpan="5" Fill="Gray" />
<Rectangle Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" Fill="Gray" />
<Rectangle Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="5" Fill="Gray" />
<!--Create Buttons for the X's and O's-->
<Button x:Name="Button_0_0" Grid.Row="0" Grid.Column="0" Click="Button_Click"/>
<Button x:Name="Button_0_1" Grid.Row="2" Grid.Column="0" Click="Button_Click"/>
<Button x:Name="Button_0_2" Grid.Row="4" Grid.Column="0" Click="Button_Click"/>
<Button x:Name="Button_1_0" Grid.Row="0" Grid.Column="2" Click="Button_Click"/>
<Button x:Name="Button_1_1" Grid.Row="2" Grid.Column="2" Click="Button_Click"/>
<Button x:Name="Button_1_2" Grid.Row="4" Grid.Column="2" Click="Button_Click"/>
<Button x:Name="Button_2_0" Grid.Row="0" Grid.Column="4" Click="Button_Click"/>
<Button x:Name="Button_2_1" Grid.Row="2" Grid.Column="4" Click="Button_Click"/>
<Button x:Name="Button_2_2" Grid.Row="4" Grid.Column="4" Click="Button_Click"/>
</Grid>
The buttons are named Button_x_y so we can distinguish which button has been clicked by name where x and y are the x and y coordinates of the Button. To save lines of code, all buttons are hooked up to the same event handler Button_Click.
Next, we will edit the code behind to handle our game logic. You can get to the code behind file in the Solution Explorer by expanding the chevron by the GameControl.xaml and selecting GameControl.xaml.cs.
For our game logic, we will use two properties to help keep track of logistics: the current player and the current state of the game. We will create these just inside of the class and initialize them in the constructor.
private string CurrentPlayer { get; set; }
private bool IsGameOver { get; set; }
Helper Functions
Before working on the game logic, let’s first write some helper functions that we’ll need. We’ll create a function to tell if the game is over, switch current players and to end the game.
Since we have a global variable for CurrentPlayer, switching players is very easy. Essentially we want to flip the current player from ‘X’ to ‘O’ or vice-versa:
/// <summary>
/// Switch the current player
/// </summary>
private void SwitchCurrentPlayer()
{
CurrentPlayer = CurrentPlayer == "X" ? "O" : "X";
CurrentPlayerLabel.Text = CurrentPlayer;
}
The GameOver function is a bit more to write. Create the function header
private bool GameOver(out bool isDraw)
{
}
Since we’re using an output variable, we have to make sure it’s set right away. By default, we’ll set it to false and only set to true if we know it’s a draw:
isDraw = false;
There are a few ways a game of tic-tac-toe can be over: Draw (all boxes are filled and no-one has won), X or O wins (there are 3 Xs or Os either vertically, horizontally or diagonally.
We’ll check for the draw case first by seeing whether or not all of our buttons have existing content. If all buttons aren’t empty, we know we have a draw and that the game is in fact over.
// if all boxes have content, draw
if (Button_0_0.Content != null &
Button_0_1.Content != null &
Button_0_2.Content != null &
Button_1_0.Content != null &
Button_1_1.Content != null &
Button_1_2.Content != null &
Button_2_0.Content != null &
Button_2_1.Content != null &
Button_2_2.Content != null)
{
isDraw = true;
return true;
}
Next, we’ll look for instances where there are 3 vertical matches, 3 horizontal matches or the two diagonal buttons match. We also have to check to make sure there is content in the button to avoid a NullReferenceException. If the box is empty, we know this set cannot indicate a winner.
// Check all winning scenarios + draw scenario
return
// Check rows
(Button_0_0.Content != null & Button_0_1.Content != null & Button_0_2.Content != null &
Button_0_0.Content.ToString() == Button_0_1.Content.ToString() &
Button_0_0.Content.ToString() == Button_0_2.Content.ToString()) ||
(Button_1_0.Content != null & Button_1_1.Content != null & Button_1_2.Content != null &
Button_1_0.Content.ToString() == Button_1_1.Content.ToString() &
Button_1_0.Content.ToString() == Button_1_2.Content.ToString()) ||
(Button_2_0.Content != null & Button_2_1.Content != null & Button_2_2.Content != null &
Button_2_0.Content.ToString() == Button_2_1.Content.ToString() &
Button_2_0.Content.ToString() == Button_2_2.Content.ToString()) ||
// Check columns
(Button_0_0.Content != null & Button_1_0.Content != null & Button_2_0.Content != null &
Button_0_0.Content.ToString() == Button_1_0.Content.ToString() &
Button_0_0.Content.ToString() == Button_2_0.Content.ToString()) ||
(Button_0_1.Content != null & Button_1_1.Content != null & Button_2_1.Content != null &
Button_0_1.Content.ToString() == Button_1_1.Content.ToString() &
Button_0_1.Content.ToString() == Button_2_1.Content.ToString()) ||
(Button_0_2.Content != null & Button_1_2.Content != null & Button_2_2.Content != null &
Button_0_2.Content.ToString() == Button_1_2.Content.ToString() &
Button_0_2.Content.ToString() == Button_2_2.Content.ToString()) ||
// Check diags
(Button_0_0.Content != null & Button_1_1.Content != null & Button_2_2.Content != null &
Button_0_0.Content.ToString() == Button_1_1.Content.ToString() &
Button_0_0.Content.ToString() == Button_2_2.Content.ToString()) ||
(Button_0_2.Content != null & Button_1_1.Content != null & Button_2_0.Content != null &
Button_0_2.Content.ToString() == Button_1_1.Content.ToString() &
Button_0_2.Content.ToString() == Button_2_0.Content.ToString());
Before initializing these values, let’s first create a helper function to give us a random start player, Player X or Player O:
/// <summary>
/// Set the current player to a random player (X or O)
/// </summary>
private void SetRandomCurrentPlayer()
{
Random random = new Random();
CurrentPlayer = random.Next() % 2 > 0 ? "X" : "O";
CurrentPlayerLabel.Text = CurrentPlayer;
}
Lastly, we’ll write the logic to handle the end of the game. Create the function stub as follows:
/// <summary>
/// End the current game by showing the "Game Over" dialog and starting a new game.
/// </summary>
/// <param name="isDraw"</param>
private void EndGame(bool isDraw)
{
}
Since the game is over, we can set the IsGameOver property right away.
IsGameOver = false;
We need to next show the user that the game is over. A great way to do that is using a Flyout. Add the following just before the closing tag of the User Control:
<FlyoutBase.AttachedFlyout>
<Flyout x:Name="GameOverPopup" Placement="Full">
<StackPanel VerticalAlignment="Center" >
<TextBlock FontSize="26" HorizontalAlignment="Center">Game Over</TextBlock>
<TextBlock x:Name="winnerTextBlock" FontSize="26" HorizontalAlignment="Center"/>
</StackPanel>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="MaxHeight" Value="180"/>
<Setter Property="MinWidth" Value="320"/>
</Style>
</Flyout.FlyoutPresenterStyle>
</Flyout>
</FlyoutBase.AttachedFlyout>
And hook that up in the EndGame function with:
winnerTextBlock.Text = isDraw ? "Draw!" : CurrentPlayer + " Wins!";
FlyoutBase.ShowAttachedFlyout(this);
Game Logic
Next, we will set up initialize our properties inside of the constructor:
SetRandomCurrentPlayer();
IsGameOver = false;
We need to create a handler for when a button is pressed – create the definition of the Button_Click function as follows
private void Button_Click(object sender, RoutedEventArgs e)
{
}
When a button is pressed, if the game is over, we don’t want to do anything. So right away, in this function, we’ll check if the game is already over by adding these lines to the Button_Click call:
if (IsGameOver)
{
return;
}
Next, we need to know which button was clicked. The generic button click function created by Visual Studio passes in the sender as a general object. Since we know the object can only be button if this function is called, we can safely cast it to a Button. Also, if the button has already been clicked in the game, it has content already and thus we don’t want to mark it as the current players:
// if this button has already been filled, skip...
Button clickedButton = sender as Button;
if (clickedButton.Content != null)
{
return;
}
clickedButton.Content = CurrentPlayer;
Since a move has been made, we next need to process the move. We will call our helper function (that we’ll write shortly) GameOver to figure out if the game is over or not. Since the function returns true/false based on whether the game is over and there is more information we want to know, i.e. did anyone win, we need to use an output variable.
bool isDraw = false;
if (GameOver(out isDraw))
{
EndGame(isDraw);
return;
}
Finally, we have processed the move and know the game isn’t over, we can switch players by calling another helper function and wait for another click.
SwitchCurrentPlayer();
Now that we have complete game logic, we need to present the UI to the user. We’ll create one more XAML page shared between the two projects. In the Solution Explorer, right-click the TicTacToe.Shared project and go to Add New Item.
To create our GamePage we’ll use the Blank Page template. Expand the tree on the left-hand side Installed Visual C# and select the Blank Page template. Call the XAML file GamePage.xaml and click Add to continue.
Name the main Grid control so that we can easily access it in the code-behind file. The control should then look like this
<Grid x:Name="GameContainer" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
Additionally, we’ll use the AppBar to give us a New Game button. The following snippet creates an AppBar with a New Game button:
<Page.BottomAppBar>
<CommandBar>
<AppBarButton x:Name="NewGameButton" Icon="Add" Label="New Game" Click="NewGameButton_Click" />
</CommandBar>
</Page.BottomAppBar>
Next, go to the code behind file by right-clicking in the XAML window and selecting View Code.
We need code to handle whenever there is a new game. This can be invoked by either the app bar or the first time the game is launched. We can create a new function to abstract this behavior and share the code.
private void NewGame()
{
GameContainer.Children.Clear();
GameControl gameControl = new GameControl();
Grid.SetRow(GameContainer, 0);
Grid.SetColumn(GameContainer, 0);
GameContainer.Children.Add(gameControl);
}
Having the helper function makes the constructor very simple. After the IntializeComponent call, we just call our NewGame helper function.
NewGame();
Next, we need to handle the NewButton click event. Copy the following code snippet to call the helperfunction on the NewGame button click:
private void NewGameButton_Click(object sender, RoutedEventArgs e)
{
NewGame();
}
Lastly, we need to change the default XAML that is shown on start up. Open App.xaml.cs from the TicTacToe.Shared project. Find the navigation code that handles the start-up page:
if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
Instead of starting MainPage.xaml, we’ll be using our shared GamePage.xaml. Simply update the MainPage reference to GamePage:
if (!rootFrame.Navigate(typeof(GamePage), e.Arguments))
Since all the XAML we’ve used is supported on both Windows Phone 8.1 and Windows 8.1, you now have a working Tic Tac Toe game! Your support costs are also lower since you only have to maintain one code base.
To see the app run, right-click each of the projects and go to the Debug menu. From there, you can select Start new instance. To debug on the device for the Windows Phone sample, right click the Phone project, and chose Set as StartUp Project. Afterwards, you can access the configuration via the chevron by the green play button. Select Device to debug locally.
If you did want to add platform specific code, you can leverage the dedicated projects for each platform.
Wrap Up
Congratulations on completing this challenge.
Want more?
Visit and check out our full collection of Quick Start Challenges.