Using XAML to write Windows 8 Games – Part 3


Here’s something you might find a little odd if you’ve been working in iOS for a while – Windows 8 wants you to forget about where you put things on screen. Really: Windows 8 is all like “hey dude, just put the controls on the screen, and I’ll look after them for you. Chillax”.

Compared to other platforms, Windows 8 user interface stuff  is definitely more web-like in this respect, and when you are writing a utility app or similar, it’s great to not have to worry about where your controls go. So the user rotates their device? *Shrug* They’ve just plugged in a new monitor and suddenly their screen gets twice as large? Don’t care. If you have been using XAML’s grid and stackpanels to place things (approximately) in the right place (as indeed, you should be doing), then you really don’t need to worry: the controls will reposition themselves nicely when something changes. The XAML controls are smart too – you can quickly create fun stuff like linked text boxes that will reflow their content depending on screen size. That’s clever stuff right there.

However, if you’re writing a game then knowing where your objects are currently positioned on screen is vital. Extremely vital. Super-vital in fact.  If you’re shooting at some kind of carnivorous toaster and the user rotates the screen, you really don’t want everything to suddenly shift around allowing the toaster to escape, and your bread supplies to be decimated. Or, if you will, toast.

You might think “Oh, well that’s easy enough – I’ll just set the X,Y properties on the XAML controls I’m using to draw stuff,  and I’m done. No biggie.”

To which I would reply “Oh, you weren’t listening were you? Windows 8 wants you not to have to worry about where place things – and it’s more of a statement, than a request.”. In other words, there are no X, Y properties on a XAML control.

At which point you might think (as you quoted the whiny Hudson character from Aliens – the best of the Alien movies, BTW, sorry Prometheus)  “That’s it man! Game over man, game over!”.

Canvas

So here’s the good news: XAML, like HTML, has a Canvas control. And anything you place inside this canvas control CAN be positioned to pixel accuracy. And what’s more you can also have multiple canvas objects on screen at once, and place them inside grids, so really you have a huge amount of flexibility. You could, for example, create a square canvas for your game to take place inside. Around the canvas you have can have various buttons, status messages, and so on. In landscape mode, these controls are over to the left (or right), and in portrait mode they are at the top (or bottom) – and the content inside your canvas remains completely unaware that everything around it is moving, because as Einstein would appreciate, they are all in their own frame of reference.

Here’s an example of how you might write a game using an XAML canvas. In this game, you’re protecting Earth from the evil alien toasters. At the most basic level, it’ll look something like this:

The background is a little overpowering, but you should be able to make out our valiant ship towards the middle of the screen, and four circles at the bottom which will be the controls for left, right, thrust and fire.

Creating a canvas in your XAML, and populating it with all these goodies isn’t too tricky. In fact, here’s all the XAML it took to define it.

   

<Grid>     

 <Grid.Background>     

  <ImageBrush ImageSource=”Assets/EarthFromSpace.jpg”/>

 </Grid.Background>

 <Canvas>

  <Ellipse x:Name=”Left” Fill=”#CC808080″ Width=”100″ Height=”100″ VerticalAlignment=”Bottom” Canvas.Left=”10″ Canvas.Top=”658″ PointerPressed=”goLeft” PointerReleased=”stopLeft” PointerExited=”stopLeft”/>

  <Ellipse x:Name=”Right” Fill=”#cc808080″ Width=”100″ Height=”100″ VerticalAlignment=”Bottom” Canvas.Left=”147″ Canvas.Top=”658″ PointerPressed=”goRight” PointerReleased=”stopRight” PointerExited=”stopRight” />

  <Ellipse x:Name=”Shoot” Fill=”#cc808080″ Width=”100″ Height=”100″ VerticalAlignment=”Bottom” Canvas.Left=”1256″ Canvas.Top=”658″ PointerPressed=”goShoot” />

  <Ellipse x:Name=”Thrust” Fill=”#cc808080″ Width=”100″ Height=”100″ VerticalAlignment=”Bottom” Canvas.Left=”1120″ Canvas.Top=”658″ PointerPressed=”goThrust” PointerReleased=”stopThrust” PointerExited=”stopThrust”/>

 <Path x:Name=”ship”

   RenderTransformOrigin=”0.5,0.5″

   Fill=”Gray” Stroke=”LightGreen” StrokeThickness=”2″

   Data=”M 0,0 L 20,60 L 40,0 L 20,10 L 0,0″>

  <Path.RenderTransform>

   <RotateTransform x:Name=”shipRotateAngle” Angle=”180″ CenterX=”20″ CenterY=”30″/>

  </Path.RenderTransform>

 </Path>

 </Canvas>

 <TextBox Margin=”347,10,347,0″ TextWrapping=”Wrap” Text=”Score: 00000 Lives: 3 High: 00000″ VerticalAlignment=”Top” Foreground=”White” Width=”672″ TextAlignment=”Center” FontSize=”20″ Background=”Transparent” Height=”42″ BorderBrush=”Transparent” FontWeight=”Bold”/>

</Grid>

 

Here are a few things to point out in the XAML:

  • When defining the Ellipse buttons, I used PointerPressed to detect when the user was touching them, and PointerReleased to detect then they stopped. However, I also added PointerExited otherwise the user could slide their finger off the button and it would remain active.
  • A nice little Visual Studio trick: when you type the name of the method which is called in these PointerPressed definitions, you can right-click and select “Navigate to Event Handler” and Visual Studio will create the event handler method for you in the .cs file.
  • The ship is drawn using Path, which simply takes a list of co-ordinates to draw a shape. Because I want to rotate this ship later on, I use the <Path.RenderTransform> tag to set up a property I can access programmatically.
  • Although the lines that make up the ship have co-ordinates, there are still no co-ordinates that position the ship at this stage. We’ll do that programmatically.
  • It’s easy to add a text box on top of the canvas to make our Heads-up display for scores and so on.

Now for the C# side of things. First of all, the ‘game loop’. When you are writing a game in which things move by themselves, you need to call the code that draws these things often and regularly. Windows Store Apps in C# can use an event handler based on CompositionTarget.Rendering . Essentially, you tack on your gameloop method to this, and it gets called every frame.

Note: this is not a perfect approach. See this discussion from Spotted Zebra for more details. For the sake of this example, it works well enough.

The rest of the code doesn’t have much in the way of surprises: the position of the ship is updated depending on if it’s moving or spinning, and then its location on-screen is updated.

 

namespace ToasterAttack

{

public sealed partial class MainPage : Page

    {  

// Store the state of the ship

double shipX = 800;

double shipY = 400;

double shipAngle = 180;

double shipSpeed = 0;

double shipThrustAngle = 0;

bool goingLeft, goingRight, goingThrust;

 

public MainPage()

        {     

this.InitializeComponent();

CompositionTarget.Rendering += gameLoop;

           goingLeft =false; 

          goingRight =false;

           goingThrust = false;

        }

     

void gameLoop(object sender, object e)

        {

            updateShip();

            positionShip();

        }

 

private void updateShip()

        {

// Move the ship if it’s thrusting

 

if (goingThrust)

            {

                shipSpeed += 0.1;

         if (shipSpeed > 10) shipSpeed = 10;

            }

else

            {

          if (shipSpeed > 0.1)

                {

                    shipSpeed -= 0.05;

                }

         else     

                   shipSpeed = 0;

     }

 

    if (shipSpeed > 0)

            {

               // Those math classes came in handy

                shipY += Math.Cos(Deg2Rad*shipThrustAngle) * shipSpeed;

                shipX -= Math.Sin(Deg2Rad*shipThrustAngle) * shipSpeed;

            }

       

   // Rotate the ship if it’s spinning

 

    if (goingLeft) shipAngle -= 5;

    if (goingRight) shipAngle += 5;

   }

       

 

private void positionShip()

        {

           // The clever part that sets the position of the control inside the canvas, and handles rotation

            ship.SetValue(Canvas.LeftProperty,shipX);

            ship.SetValue(Canvas.TopProperty,shipY);

            shipRotateAngle.Angle = shipAngle;        

        }

       

private void goLeft(object sender, PointerRoutedEventArgs e)

        {

            goingLeft =true;

        }

       

private void stopLeft(object sender, PointerRoutedEventArgs e)

        {

            goingLeft =false;

        }

       

private void goRight(object sender, PointerRoutedEventArgs e)

        {

            goingRight =true;

        }

       

private void stopRight(object sender, PointerRoutedEventArgs e)

        {

            goingRight = false;

        }

       

private void goShoot(object sender, PointerRoutedEventArgs e)

        {

// TBD – Remember: short, controlled bursts

        }

       

private void goThrust(object sender, PointerRoutedEventArgs e)

        {

            shipThrustAngle = shipAngle;

            goingThrust =true;

        }

 

private void stopThrust(object sender, PointerRoutedEventArgs e)

        {

            goingThrust =false;

        }

    }

}

That’s enough code to support moving the ship around the screen. All you need to add now is the ability to shoot, some enemies, collision detection, scores, lives, attract mode and high score tables. That should be an enjoyable afternoon’s work for you!

 Summary

To be honest, I’ve not selected the best example of a game genre to demonstrate positions objects on-screen. It would fair to say that XAML is not really designed with games authoring in mind. Although you can use controls as sprites like I’ve done here, there are better solutions for writing games which move a lot of things around the screen. Also, the gameloop timing approach is not ideal as it stands. You might, for example, rather play with the HTML Canvas, especially if you have web experience. But again, you will have a lot of work to do before you have a working 2D games engine if you take this approach, and the timing is still a bit iffy.

Being lazy by nature, I prefer to let someone else do the work, and so I like using MonoGame, which provides good support for sprites, timing loops and all that good stuff. Even better, it’s a free download, so if you are thinking of writing simpler retro arcade games this is definitely where I would start.

On the other hand, if you are writing something more akin to  a word puzzle game then this approach might be ideal. Remember that XAML controls are smart, and can have Storyboard animations applied to them. This means, for example, you could create letter tiles, and then trigger cool animations on each of them when moved or touched, and creating these animations in Blend would be ridiculously easy. Styling buttons is kind of fun in fact..

 

 


Comments (0)

Skip to main content