Building a simple game using XAML/C#: Part 3 – Make it a game

Now that we have our basic interactions working the way we want, it’s time to add some game logic. We’ll do this by:
  • Refactoring the game logic into a Game class and adding a “Level” class that will encapsulate the logic for a level
  • Add a game loop that will be used to animate the game
  • Align the application to the game state
Refactoring
Many developers can find refactoring to be time consuming and tedious. However, refactoring is one of the many realities when you are creating manageable code so don’t look at it as a bad thing but as a good thing because you will be creating code that is ultimately more maintainable (not just for others but for you too!). In some cases I have seen refactors go wrong and the code got more confusing… but that’s a story for another time. There’s definitely a spectrum of right to wrong ways of refactoring.
Let’s get started! Add new classes to your application: Game and Level. You can do this by right-clicking on your project in solution explorer or with the keyboard shortcut SHIFT+ALT+C. The Game class will encapsulate all of the Game logic and the Level class will encapsulate the related Level logic.
Next, we’ll add some new enumerations to the application’s namespace:
    enum GameSwitches { red = 0, blue = 1, green = 2, yellow = 3 };
    enum GameState { challengeUser = 0, responseUser = 1, notRunning = 2, levelComplete = 3, levelFailed = 4 };
Refactoring Game methods to the Game class
First, move all of the methods we have created so far that are sloppily placed into the MainPage.xaml.cs partial class into our Game class because these methods are related to the Game; move the variables that were used in the partial to the Game class; and move the includes for Windows.UI.Xaml, Windows.UI.Xaml.Controls, Windows.UI.Xaml.Shapes, and Windows.UI.Xaml.Media to the Game class.
We’ll add a constructor so that we can pass in the canvas for drawing, the media elements that were created in XAML, and the status TextBlock that is used for status and displaying text messages for the user. Note: The canvas object (and others) are passed by reference because copied instances of these objects will become detached from the MainPage.
The following code is the complete Game class up to this point:
Game.cs
-----------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// for the squares
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Media;

namespace Application1
{
    class Game
    {         

        // UI from the mainpage.xaml
        Rectangle redRect, greenRect, blueRect, yellowRect, cheatRect;
        GradientBrush redBrush, greenBrush, blueBrush, yellowBrush;
        MediaElement yellowSound, greenSound, blueSound, redSound;
        TextBlock statusBox;
        Canvas gameCanvas;

        int score;        

        double centerX, centerY = 0.0;       

        // Game state enumeration
        GameState theState;

        // for spinning the board
        //, boardRotation = 0.0;

        // configuration variables, toTweak
        const float lowOpacity = .75f;
        const float hiOpacity = 1.0f;

        // new snippet
        public Game(ref Canvas _gameCanvas,
            ref MediaElement _redSound,
            ref MediaElement _yellowSound,
            ref MediaElement _blueSound,
            ref MediaElement _greenSound,
            ref TextBlock _statusBox)
        {
            redSound = _redSound;
            yellowSound = _yellowSound;
            blueSound = _blueSound;
            greenSound = _greenSound;
            statusBox = _statusBox;
            gameCanvas = _gameCanvas;

            theState = GameState.notRunning;
            score = 0;
        }
        // new snippet

        // XAML First snippet begin
        // UI from the mainpage.xaml
        public void SetupSquare(Rectangle r, double rectWidth, double rectHeight, GradientBrush br, double offset1, double offset2, double rotation, Color c)
        {
            // really annoying code for creating the gradients
            GradientStop grPri = new GradientStop();
            grPri.Color = c;
            grPri.Offset = offset1;
            GradientStop grrBlk = new GradientStop();
            grrBlk.Color = Colors.Black;
            grrBlk.Offset = offset2;

            br.GradientStops.Add(grPri);
            br.GradientStops.Add(grrBlk);

            RotateTransform gRot = new RotateTransform();
            gRot.Angle = rotation;
            br.Transform = gRot;
            // END gradient code

            r.Fill = br;
            r.Height = rectHeight;
            r.Width = rectWidth;
            //r.RadiusX = rectWidth/6;
            //r.RadiusY = rectHeight/6;
        }

        public void SetupSquares()
        {

            //  -------------
            // | R    |  G   |
            // |______|______|
            // | B    |  Y   |
            // |______|______|
            //
            // All linear gradients are calculated with outer gradient pointing inward

            double height = Window.Current.Bounds.Bottom;
            double width = Window.Current.Bounds.Right;

            double rectWidth = width / 3;  // thirds of the screen for rect width
            double rectHeight = height / 3; // thirds of the screen for height

            double rectSpacing = 15;

            double wMid = rectWidth / 2;    // midpoints for width/height for rect placement
            double hMid = rectHeight / 2;

            centerX = ((wMid * 2) + rectSpacing) / 2; // between the rectangles
            centerY = ((hMid * 2) + rectSpacing) / 2;

            redRect = new Rectangle();
            redBrush = new LinearGradientBrush();

            SetupSquare(redRect, rectWidth, rectHeight, redBrush, 0.0, 1.5, 0.0, Colors.Red);

            Canvas.SetTop(redRect, hMid);
            Canvas.SetLeft(redRect, wMid);

            gameCanvas.Children.Add(redRect);

            greenRect = new Rectangle();
            greenBrush = new LinearGradientBrush();

            SetupSquare(greenRect, rectWidth, rectHeight, greenBrush, 0.0, 1.5, 90.0, Colors.Green);

            Canvas.SetTop(greenRect, hMid);
            Canvas.SetLeft(greenRect, wMid + rectWidth + rectSpacing);

            gameCanvas.Children.Add(greenRect);

            blueRect = new Rectangle();
            blueBrush = new LinearGradientBrush();

            SetupSquare(blueRect, rectWidth, rectHeight, blueBrush, 1.0, -.5, -90.0, Colors.Blue);

            blueRect.Fill = blueBrush;
            blueRect.Height = rectHeight;
            blueRect.Width = rectWidth;

            Canvas.SetTop(blueRect, hMid + rectHeight + rectSpacing);
            Canvas.SetLeft(blueRect, wMid);

            gameCanvas.Children.Add(blueRect);

            yellowRect = new Rectangle();
            yellowBrush = new LinearGradientBrush();

            SetupSquare(yellowRect, rectWidth, rectHeight, yellowBrush, 1.0, -0.5, 0.0, Colors.Orange);

            Canvas.SetTop(yellowRect, hMid + rectHeight + rectSpacing);
            Canvas.SetLeft(yellowRect, wMid + rectWidth + rectSpacing);

            gameCanvas.Children.Add(yellowRect);

            // set all opacity down
            redRect.Opacity = lowOpacity;
            greenRect.Opacity = lowOpacity;
            blueRect.Opacity = lowOpacity;
            yellowRect.Opacity = lowOpacity;

            // Add event handlers for each button click
            redRect.PointerPressed += new Windows.UI.Xaml.Input.PointerEventHandler(redRect_PointerPressed);
            redRect.PointerReleased += new Windows.UI.Xaml.Input.PointerEventHandler(redRect_PointerReleased);
            redRect.PointerEntered += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerEntered);
            redRect.PointerExited += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerExited);

            greenRect.PointerPressed += new Windows.UI.Xaml.Input.PointerEventHandler(greenRect_PointerPressed);
            greenRect.PointerReleased += new Windows.UI.Xaml.Input.PointerEventHandler(greenRect_PointerReleased);
            greenRect.PointerEntered += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerEntered);
            greenRect.PointerExited += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerExited);

            blueRect.PointerPressed += new Windows.UI.Xaml.Input.PointerEventHandler(blueRect_PointerPressed);
            blueRect.PointerReleased += new Windows.UI.Xaml.Input.PointerEventHandler(blueRect_PointerReleased);
            blueRect.PointerEntered += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerEntered);
            blueRect.PointerExited += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerExited);

            yellowRect.PointerPressed += new Windows.UI.Xaml.Input.PointerEventHandler(yellowRect_PointerPressed);
            yellowRect.PointerReleased += new Windows.UI.Xaml.Input.PointerEventHandler(yellowRect_PointerReleased);
            yellowRect.PointerEntered += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerEntered);
            yellowRect.PointerExited += new Windows.UI.Xaml.Input.PointerEventHandler(genericPointerExited);
        }

        // XAML
        // Highlight glow / etc
        void genericPointerEntered(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            ((Rectangle)sender).Opacity = hiOpacity;
        }

        void genericPointerExited(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            ((Rectangle)sender).Opacity = lowOpacity;
        }

        // Click / unclick
        // TODO: encapsulate this in the class to make it possible to just call some
        // methods on self, reduce defects, etc.
        // TODO: use a factory
        void yellowRect_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOffYellow();
        }

        void yellowRect_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOnYellow();
        }

        void blueRect_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOffBlue();
        }

        void blueRect_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOnBlue();
        }

        void greenRect_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOffGreen();
        }

        void greenRect_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOnGreen();
        }

        void redRect_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOffRed();
        }

        void redRect_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            triggerOnRed();
        }

        // trigger sound + color
        public void triggerOnYellow()
        {
            yellowRect.Fill = new SolidColorBrush(Colors.Orange);
            yellowSound.Play();
        }
        public void triggerOffYellow()
        {
            yellowRect.Fill = yellowBrush;
        }

        public void triggerOnBlue()
        {
            blueRect.Fill = new SolidColorBrush(Colors.Blue);
            blueSound.Play();
        }
        public void triggerOffBlue()
        {
            blueRect.Fill = blueBrush;
        }

        public void triggerOnGreen()
        {
            greenRect.Fill = new SolidColorBrush(ColorHelper.FromArgb(255, 0, 255, 0));
            greenSound.Play();
        }
        public void triggerOffGreen()
        {
            greenRect.Fill = greenBrush;
        }

        public void triggerOnRed()
        {
            redRect.Fill = new SolidColorBrush(Colors.Red);
            redSound.Play();

        }
        public void triggerOffRed()
        {
            redRect.Fill = redBrush;
        }
        // END XAML Snippet 2

    }
}
Now that we have an updated Game class, it’s time to instantiate a Game from the main partial page. Create a Game variable within the MainPage partial:
 MainPage.xaml.cs: ---------------------- Game theGame; 
Construct the Game passing in references to the XAML elements used:
MainPage.xaml.cs:
-----------------------
theGame = new Game(ref gameCanvas, ref redSound, ref yellowSound, ref blueSound, ref greenSound, ref statusbox);
theGame.SetupSquares();
Through the magic of refactoring, you will now have a much cleaner separation of the Game logic from the application logic while still retaining the functionality that we had before. Building and running should make the app work exactly as before.
Add the Level class
The Level class will contain the logic for the level. This class will need to be able to do things like trigger squares during the challenge phase of the Game and will need to also be able to contain logic like whether it is complete. Set up your level with the following variables:
Level.cs
-----------
        // some configuration stuff
        bool levelRandom = false; // random levels every time...
        bool cheat = false;

        // member variables
        int difficulty, chimesAdded, lastQueued;
        Queue triggers, prevTriggers;

        Random randNum;
        bool levelCreated = false;
        bool levelComplete = false;

        // externals
        TextBlock statusBlock;
Note, you will need to include Windows.UI.Xaml.Controls for TextBlock.
Next, we’ll add a constructor that will setup a level given a difficulty and the status block that we’ll be using for sending debugging messages.
Level.cs
-----------
        public Level(int _difficulty, ref TextBlock _statusBlock)
        {
            chimesAdded = 0;
            lastQueued = -1;
            difficulty = _difficulty;
            statusBlock = _statusBlock;

            if (cheat)
            {
                statusBlock.Text = "Cheating: ";
            }

            triggers = new Queue();
            prevTriggers = new Queue();

            randNum = new Random(DateTime.Now.Millisecond);
        }
Next, we’ll add some accessors to expose Level’s members:
Level.cs
-----------
        public int getDifficulty()
        {
            return difficulty;
        }

        public bool isComplete()
        {
            return levelComplete;
        }

        public bool isCreated()
        {
            return levelCreated;
        }
Now for the fun stuff, we’ll add a helper method that will be used for creating the level, given a game:
Level.cs
-----------

        // returns false after the level is done being created
        public bool add(Game theGame)
        {
            // the following logic exists to turn off the switch after the level is created
            switch (lastQueued)
            {
                case ((int)GameSwitches.blue):
                    theGame.triggerOffBlue();
                    break;
                case ((int)GameSwitches.green):
                    theGame.triggerOffGreen();
                    break;
                case ((int)GameSwitches.red):
                    theGame.triggerOffRed();
                    break;
                case ((int)GameSwitches.yellow):
                    theGame.triggerOffYellow();
                    break;
                default:
                    // do nothing, we could do weird stuff for fun
                    break;
            }
            if (chimesAdded >= difficulty) levelCreated = true;
            if (isCreated())
            {
                return false;
            }
            // end weird logic

            // the following code adds the "challenge" to the level
            chimesAdded++;
            int trigger = randNum.Next(0, 4);
            if (prevTriggers.Count() != 0)
            {
                trigger = prevTriggers.Dequeue();
            }

            triggers.Enqueue(trigger);
            lastQueued = trigger;
            switch (trigger)
            {
                // TODO: does the implicit enum conversion really work?
                case ((int)GameSwitches.blue):
                    if (cheat) statusBlock.Text += "Blue ";
                    theGame.triggerOnBlue();
                    break;
                case ((int)GameSwitches.green):
                    if (cheat) statusBlock.Text += "Green ";
                    theGame.triggerOnGreen();
                    break;
                case ((int)GameSwitches.red):
                    if (cheat) statusBlock.Text += "Red ";
                    theGame.triggerOnRed();
                    break;
                case ((int)GameSwitches.yellow):
                    if (cheat) statusBlock.Text += "Yellow";
                    theGame.triggerOnYellow();
                    break;
                default:
                    // in case of glitch, mess up the player
                    //theGame.triggerAllSounds();
                    break;
            }
            return true;
        }
What this code is doing is a little bit tricky but it’s simpler if you understand that the “level” add code will be called for each tile that gets pressed when Simon creates the first memory pattern.
The following things happen:
  • Clean up any work that was left over from the last run – Note: This is done because the method is triggered through a timer
    • The last pressed button is “released” so that the lights don’t stay lit
    • If we’ve added enough items, return and the level is created
  • Add to the queue that will be used for testing the solution
    • Determine a random trigger by generating a number between 0 and 4
    • Save the number to the solution queue
    • Map the number to the switches and trigger the switch
  • Profit?
At this point, you should now be able to create levels, woot! Add a level to the Game class:
Game.cs:
-----------
        // UI from the mainpage.xaml
        Rectangle redRect, greenRect, blueRect, yellowRect, cheatRect;
        GradientBrush redBrush, greenBrush, blueBrush, yellowBrush;
        MediaElement yellowSound, greenSound, blueSound, redSound;
        TextBlock statusBox;
        Canvas gameCanvas;
        Level theLevel;

Game.cs:
-----------
        public void resetGame()
        {
            theState = GameState.notRunning;
            score = 0;
            //boardRotation = 0;
            //rotateBoard(0);
            if (!(theLevel == null))
            {
                theLevel.resetLevel();
            }
        }

Level.cs
-----------
        public void resetLevel()
        {
            chimesAdded = 0;
            levelComplete = false;
            levelCreated = false;
            difficulty = 0;
            triggers = new Queue();
            prevTriggers = new Queue();
            randNum = new Random(DateTime.Now.Millisecond);

            if (cheat)
            {
                statusBlock.Text = "Cheating: ";
            }
        }
Create a method for kicking off a new Level on the Game and on the level:
Game.cs:
------------
        public void addLevel()
        {
            theLevel.add(this);
        }

        public Level getLevel()
        {
            return theLevel;
        }

        public void setLevel(ref Level _theLevel)
        {
            theLevel = _theLevel;
        }

        public void setState(GameState _theState)
        {
            theState = _theState;
        }

        public GameState getState()
        {
            return theState;
        }

        public void LevelUp(ref TextBlock _statusBox){
            if (theLevel == null)
            {
                theLevel = new Level(1,ref _statusBox);
            }
            else
            {
                theLevel.nextLevel();
            }
            theState = GameState.challengeUser;
        }
Next, add another method for going “to the next level” to the Level class, we’ll also add a few methods to the Game class to simplify adding levels from the application.
Level.cs:
-------------
        public void nextLevel()
        {
            // up the difficulty and reseed
            difficulty++;
            randNum = new Random(DateTime.Now.Millisecond);

            if (levelRandom)
            {
                // just want all the next ones to be random
                prevTriggers.Clear();
            }

            chimesAdded   = 0;
            levelComplete = false;
            levelCreated  = false;
        }
Next, we’ll add “solve” logic to the Level class and will update the button presses in the Game class so that they will trigger the “solve” logic in the level class. The following code shows how the solve method works:
Level.cs:
------------
        public bool solve(GameSwitches trigger)
        {
            if (triggers.Count == 0)
            {
                levelComplete = true;
                return true;
            }

            int challenge = triggers.Dequeue();

            prevTriggers.Enqueue(challenge);

            // guilty until proven innocent
            bool correct = false;
            if (challenge == ((int)trigger))
            {
                correct = true;
            }

            if (triggers.Count == 0)
            {
                levelComplete = true;
            }

            return correct;
        }
The following code shows the logic that links the button pushes to Solve.
Game.cs:
------------

        void blueRect_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            if (theState != GameState.responseUser) return;
            triggerOffBlue();
        }

        void blueRect_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerEventArgs e)
        {
            if (theState != GameState.responseUser) return;
            triggerOnBlue();
            if (!theLevel.solve(GameSwitches.blue))
            {
                theState = GameState.levelFailed;
            }
            else
            {
                //addScore(theLevel.getDifficulty());
                if (theLevel.isComplete())
                {
                    //addScore(theLevel.getDifficulty() * 100);
                    doLevelComplete();
                }
            }
        }
We’ll also add a helper for when the level completes to Game.cs
Game.cs:
------------
        public void doLevelComplete()
        {
            triggerOffBlue();
            triggerOffGreen();
            triggerOffRed();
            triggerOffYellow();
            setState(GameState.levelComplete);
        }

        public void doLevelFail()
        {
            triggerOffBlue();
            triggerOffGreen();
            triggerOffRed();
            triggerOffYellow();
            setState(GameState.levelFailed);
        }
Next, we’ll be adding the “run” loop to the Application that will be used to make things happen with the Simon. First, we’ll add a handler for the game logic, Gameloop. What was a little tricky for me was that timers and loops in XAML/C# apps use a “Storyboard” for animation (or timer) logic. What you will need to do is setup a storyboard which we’ll call _gameLoop. We’ll also be adding some other variables that will be used for controlling game speed and turning on and off test features.
MainPage.xaml.cs:
-----------------------
using Windows.UI.Xaml.Media.Animation; // for storyboard object used for our game logic

(…)
partial  class MainPage
{
…
        Storyboard _gameLoop = new Storyboard();
        // constants
        //
        const int startCurrentSpeed = 90;

        // TODO: Move all this logic into game
        int initialWait = 60;                  // remove race condition for first trigger
        int currentSpeed = startCurrentSpeed;   // lower value = higher speed
        int minSpeedValue = 50;                  // the minimum speed "value" lower = faster, this is limited by UI

        // temp / debug / possible approaches variables
        //DispatcherTimer levelCreateTimer;
        int count = 0;
        bool enableTestFeature = false;
Next, you can create a method that will be triggered periodically by the Timer… err Storyboard logic.
MainPage.xaml.cs:
-----------------------
        void GameLoop(object sender, object e)
        {
            if (enableTestFeature)
            {
                // insert fun weird tweaks in here
                // I used to have the rotation code here...
            }

            // If we're Level 5+, start spinning 🙂
            //if (theGame.getLevel() != null && theGame.getLevel().getDifficulty() > 5)
            //{
            //    theGame.rotateBoard(.01 * theGame.getLevel().getDifficulty());
            //}

            // TODO, use a proper timer, wth is up with the new threading?
            switch (theGame.getState())
            {
                case GameState.challengeUser:
                    statusBox.Text = "Simon is telling you the secret code.";

                    if (theGame.getLevel().isCreated())
                    {
                        theGame.setState(GameState.responseUser);
                    }
                    else
                    {
                        // The following condition will ensure we don't pump too fast
                        if ((count > initialWait) && ((count % currentSpeed) == 0))
                        {
                            theGame.addLevel();
                        }
                    }
                    break;
                case GameState.levelComplete:
                    statusBox.Text = "Nice work homeslice!  Reward is harder level.";

                    //updateScore();
                    // TODO: using the status box reference is hacky
                    theGame.LevelUp(ref status2Box);
                    //updateLevel();

                    // TODO: move into game logic
                    if (currentSpeed > minSpeedValue) currentSpeed -= 5;
                    status2Box.Text = "";
                    break;
                case GameState.levelFailed:
                    statusBox.Text = "You fail. Game over man.";
                    _gameLoop.Stop();
                    //AppBar.IsOpen = true;
                    break;
                case GameState.responseUser:
                    statusBox.Text = "Simon is waiting for you to enter the code.";
                    //updateScore();
                    break;
                case GameState.notRunning:
                    statusBox.Text = "Shall we play a game?";
                    break;
                default:
                    break;
            }
            count++;          

            _gameLoop.Begin();
        }
You will also need to add the following XAML right above the element which will add a dummy object that will be “animated” at regular intervals:
MainPage.xaml:
-----------------------
    <UserControl.Resources>
        <!-- AppBar Button Style -->
        <Style x:Key="AppBarButtonStyle" TargetType="Button">
            <Setter Property="MinWidth" Value="40" />
            <Setter Property="Width" Value="40" />
            <Setter Property="Height" Value="40" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid x:Name="AppButton">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1"
                                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                                             Storyboard.TargetName="MouseOverEllipse" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1"
                                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                                             Storyboard.TargetName="PressedEllipse" />
                                            <ColorAnimation Duration="0" To="Black"
                                                            Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
                                                            Storyboard.TargetName="contentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="0.35"
                                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                                             Storyboard.TargetName="AppButton" />
                                            <ColorAnimation Duration="0" To="#7F8D8D8D"
                                                            Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
                                                            Storyboard.TargetName="contentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Ellipse x:Name="PressedEllipse" Fill="White" Opacity="0" Width="40" Height="40"/>
                            <Ellipse x:Name="MouseOverEllipse" Fill="#7F8D8D8D" Opacity="0" Width="40" Height="40"/>
                            <TextBlock x:Name="contentPresenter"
                                       FontWeight="{TemplateBinding FontWeight}"
                                       FontFamily="{TemplateBinding FontFamily}"
                                       FontSize="{TemplateBinding FontSize}"
                                       Text="{TemplateBinding Content}"
                                       Margin="{TemplateBinding Padding}"/>
                            <Path Data="F1M20.2168,40C31.2608,40,40.2168,31.045,40.2168,20C40.2168,8.958,31.2608,0,20.2168,0C9.1708,0,0.216799999999999,
                                  8.958,0.216799999999999,20C0.216799999999999,31.045,9.1708,40,20.2168,40 M20.2168,37.161C10.7548,37.161,3.0578,29.462,
                                  3.0578,20C3.0578,10.538,10.7548,2.839,20.2168,2.839C29.6788,2.839,37.3758,10.538,37.3758,20C37.3758,29.462,29.6788,37.161,20.2168,37.161"
                                  Fill="White" Height="40" Canvas.Left="0" Stretch="UniformToFill" Canvas.Top="0" Width="40"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>

 

Finally, we’ll have to add an App bar to create the controls for controlling the game state. The following XAML will build the grid and structure that we’ll use for the application bar:
MainPage.xaml
------------------------
        <ApplicationBar x:Name="AppBar" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Bottom" IsPersistent="False" IsOpen="True"
                        Height="Auto" DismissMode="EdgeSwipe" HorizontalAlignment="Stretch" Background="#548D8D8D">
            <ApplicationBar.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="FontFamily" Value="SegoeUI" />
                    <Setter Property="FontSize" Value="12" />
                    <Setter Property="Foreground" Value="White" />
                    <Setter Property="HorizontalAlignment" Value="Center" />
                </Style>
            </ApplicationBar.Resources>
            <Grid Margin="15,0,15,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="20" />
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="20" />
                </Grid.ColumnDefinitions>
                <!-- Left side navigation buttons -->
                <StackPanel Orientation="Vertical" Margin="0,14,0,5" Grid.Column="1">
                    <Button Style="{StaticResource AppBarButtonStyle}" FontFamily="Segoe UI Symbol" FontSize="18.667"
                            Padding="8,8,0,0" Margin="0,0,0,10" Content="
We’ll also add a few methods for when the user clicks the buttons on the App Bar.  I tried to separate the actions out from the button handlers (using the Facade pattern) so that if I want to trigger these actions elsewhere I could.
MainPage.xaml.cs
------------------------
        private void NewGameClick(object sender, RoutedEventArgs e)
        {
            // What to do if the game is running?
            if (theGame.getState() == GameState.levelFailed)
            {
                ResetAndPauseGame();
            }

            if (theGame.getState() == GameState.notRunning)
            {

                // level up the user!
                theGame.LevelUp(ref status2Box);

                AppBar.IsOpen = false;
                _gameLoop.Duration = Windows.UI.Xaml.DurationHelper.FromTimeSpan(TimeSpan.FromMilliseconds(0));
                _gameLoop.Completed += new Windows.UI.Xaml.EventHandler(GameLoop);
                _gameLoop.Begin();
            }
        }

        private void RandomClick(object sender, RoutedEventArgs e)
        {
            if (enableTestFeature) { enableTestFeature = false; } else { enableTestFeature = true; };
        }

        private void ResetAndPauseGame()
        {
            statusBox.Text = "Shall we play a game?";
            theGame.resetGame();
            //updateLevel();
            //updateScore();
            count = 0;
            currentSpeed = startCurrentSpeed;
            _gameLoop.Stop();
        }

        private void ResetGameClick(object sender, RoutedEventArgs e)
        {
            ResetAndPauseGame();
        }
Everything is now connected;if you build and run now, you should have a minimalist version of the game.  If you haven’t been following along, you can download the Metro Simon project up to this point.  For the next post, we’ll do my favorite part: refine the game to make it interesting. This is the third post in a series of posts, you can find Part 1: C#/XAML UI and Part 2: C# Input and Multimedia on earlier blog posts.