Last time I showed you how to move images across the screen using the Canvas control. Just this technique allows you to create a lot of the elements in a game. That said you may want more dynamic, animated artwork in your game. In that case using spritesheets to animate your in-game elements is a good choice. By default Windows 8 and XAML do not provide any support for spritesheets, but with a little ingenuity it’s possible to create the desired effect.

A spritesheet is a collection of artwork, typically for the same character or in-game element, which has been organized into a series of columns and rows. Often, you will maintain some metadata about the spritesheet either explicitly in, say, a XML file or by convention. For example, how many columns and rows the spritesheet contains, where a given animation starts and ends, the frame rate, and so on. One compelling reason to use a spritesheet is it allows you to load multiple animations or states in a single file operation. This means you don’t have to create multiple Image controls and deal with latency when opening images for the first time. Here’s an example spritesheet from my game Adlib:

Owl spritesheet used in Adlib
Owl spritesheet used in Adlib

The principle behind a spritesheet is that you will only ever draw a subset of the larger image – a single frame. By offsetting the subset you draw over time you can flip through each image in the spritesheet. Using XAML you typically use the Image control to draw something to the screen. However the Image control does not support drawing a subset of the image with an offset, so it is not suitable for animations. Instead you must use the ImageBrush:

<Rectangle Width="100" Height="150">
    <Rectangle.Fill>
        <ImageBrush ImageSource="/Images/OwlSpritesheet.png" 
                    Stretch="None"
                    AlignmentX="Left" 
                    AlignmentY="Top">
            <ImageBrush.Transform>
                <TranslateTransform x:Name="SpriteSheetOffset" X="0" Y="0" />
            </ImageBrush.Transform>
        </ImageBrush>
    </Rectangle.Fill>
</Rectangle>

The ImageBrush draws an image across the background of other controls. In this case I’ve applied an image brush to a rectangle. Note that the rectangle’s width and height have been set to match the width and height of a frame in the spritesheet. Changing the TranslateTransform will update the image’s offset and draw a new frame. Let’s take a look at how to do this using code:

private void OnUpdate(object sender, object e)
{
    this.timeTillNextFrame += TimeSpan.FromSeconds(1 / 60f);
    if (this.timeTillNextFrame > TimePerFrame)
    {
        this.currentFrame = (this.currentFrame + 1 + NumberOfFrames) % NumberOfFrames;
        var column = this.currentFrame % NumberOfColumns;
        var row = this.currentFrame / NumberOfColumns;

        this.SpriteSheetOffset.X = -column * FrameWidth;
        this.SpriteSheetOffset.Y = -row * FrameHeight;
    }
}

For this animation I cycle through each frame spending looping back to the beginning after reaching the end. In lines 7 and 8 I calculate the offset column and row for the current frame. Then I multiply these values by the frame’s width and height, respectively. Notice that I use negative values for SpriteSheetOffset. This is because I am shifting the underlying image not the rectangle being used to crop it. Putting these two together we have our animation:

The owl animated using XAML and C# on Windows 8

Well there you have it. Using this technique it’s possible to create animations using spritesheets for Windows 8. It’s easy to imagine extending this solution to support atlases, too.

Source code for the examples in this post.

Continue reading my series on making games for Windows 8:
  1. Writing a Windows 8 Game Loop: Explores three ways to create a game loop
  2. XAML or MonoGame?: Examines the pros and cons for each option
  3. Storing Game Data in the Cloud: Azure Mobile Services or Cloud Storage?
  4. Animating Sprites with XAML: Cover the basics of animation for Windows 8
  5. Animating Spritesheets with XAML: Learn how to render a spritesheet using XAML and C#
  6. Persisting Game Data in Practice: One way to do it and some common pitfalls
  7. Keeping Game Data Consistent: How to maintain consistency in a NoSQL world