2

I'm trying to work out how to create an animation of a character walking across a screen using a WPF storyboard (similar to an animated gif).

I have multiple images of the character in different stages of the walking action and the best I have been able to do is use Blend to show and hide different images at different times. The resulting animation was not particularly smooth.

I could make it smoother by compressing the timeline but I was wondering if there is a better or more abstracted way to approach this? I have searched, but could not find a relevant tutorial or example.

I have seen the below SO questions, but it is still unclear to me how you would do this:

Community
  • 1
  • 1
user783836
  • 3,099
  • 2
  • 29
  • 34
  • Not an answer, but when I needed to make a character to walk a staight line I just made a .gif and set it moving across the screen. Very simple and fast solution. But if you need something more complex you can try to search sprite animation in WPF, this topic can be closely related. – icebat Jun 20 '14 at 07:38
  • Thanks, not a bad idea. But I was hoping to make the walking look natural which, as far as I understand, would require different images with the character's limbs in different positions. – user783836 Jun 20 '14 at 07:43

1 Answers1

4

Props to @icebat, sprite animation was the way to go.

Excellent example here: http://www.spottedzebrasoftware.com/blog/xaml-spritesheet-animation.html

Essentially, you get a sprite sheet with the character a different stages of the animation. Then put a WPF element that can be filled with an ImageBrush on the page and apply a TranslateTransform to the ImageBrush to show different images on the sprite sheet at regular intervals.

For posterity, the code from the example looks something like:

XAML

<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">
        <Rectangle Width="52" Height="40">
            <Rectangle.Fill>
                <ImageBrush ImageSource="/Assets/Images/animations/sprite_sheet.png"
                Stretch="None"
                AlignmentX="Left"
                AlignmentY="Top">
                    <ImageBrush.Transform>
                        <TranslateTransform x:Name="SpriteSheetOffset" X="0" Y="0" />
                    </ImageBrush.Transform>
                </ImageBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>

Code behind

private const int NumberOfColumns = 1;
private const int NumberOfFrames = 8;
private const int FrameWidth = 54;
private const int FrameHeight = 40;
public static readonly TimeSpan TimePerFrame = TimeSpan.FromSeconds(1 / 60f);
private int currentFrame;
private TimeSpan timeTillNextFrame;

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 row = this.currentFrame % NumberOfColumns;
        var column = this.currentFrame / NumberOfColumns;

        this.SpriteSheetOffset.X = -column * FrameWidth;
        this.SpriteSheetOffset.Y = -row * FrameHeight;
        this.timeTillNextFrame = TimeSpan.FromSeconds(0);
    }
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.navigationHelper.OnNavigatedTo(e);
    CompositionTarget.Rendering += this.OnUpdate;
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    this.navigationHelper.OnNavigatedFrom(e);
    CompositionTarget.Rendering -= this.OnUpdate;
}
user783836
  • 3,099
  • 2
  • 29
  • 34