weilitao
Topic Author
Posts: 22
Joined: 23 Feb 2016, 10:43

What's the best way to do sprite sheet animation?

08 Aug 2017, 17:21

Hi,

I need to do much sprite sheet animation in NoesisGUI, so I'd like to find some way to do this more efficient.

From the official tutorial, I can use following code snippet to achieve this animation:
<Storyboard RepeatBehavior="Forever">
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="aladin_sprite_01"
        Storyboard.TargetProperty="Visibility">
        <DiscreteObjectKeyFrame KeyTime="0:0:0.00">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
        <DiscreteObjectKeyFrame KeyTime="0:0:0.05">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Hidden</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
...
</Storyboard>
...
<Grid>
    <Rectangle x:Name="aladin_sprite_01" Fill="{StaticResource aladin01}" Width="33" Height="54"
        HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Visible"/>
    <Rectangle x:Name="aladin_sprite_02" Fill="{StaticResource aladin02}" Width="33" Height="54"
        HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden"/>
...
</Grid>
But the method would draw bunch of Rectangles for each frame, maybe just draw one rectangle and animate its Fill property would be better?
<Storyboard RepeatBehavior="Forever">
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="aladin"
            Storyboard.TargetProperty="Fill">
        <DiscreteObjectKeyFrame KeyTime="0:0:0.00" Value="{Binding Source={StaticResource aladin01}}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.10" Value="{Binding Source={StaticResource aladin02}}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.20" Value="{Binding Source={StaticResource aladin03}}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.30" Value="{Binding Source={StaticResource aladin04}}" />
    </ObjectAnimationUsingKeyFrames>
</Storyboard>
...
<Grid>
    <Rectangle x:Name="aladin" Width="33" Height="54" />
</Grid>
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: What's the best way to do sprite sheet animation?

10 Aug 2017, 13:04

I think your approach will probably be more efficient, just a couple of suggestions:
Instead of using bindings in the discrete key frame, use the StaticResource directly:
<Storyboard RepeatBehavior="Forever">
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="aladin" Storyboard.TargetProperty="Fill">
        <DiscreteObjectKeyFrame KeyTime="0:0:0.00" Value="{StaticResource aladin01}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.10" Value="{StaticResource aladin02}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.20" Value="{StaticResource aladin03}" />
        <DiscreteObjectKeyFrame KeyTime="0:0:0.30" Value="{StaticResource aladin04}" />
    </ObjectAnimationUsingKeyFrames>
</Storyboard>
And make sure that rectangle's Width and Height correspond to the size of the sprite so image is not distorted. You can set these properties in the animation too.
 
weilitao
Topic Author
Posts: 22
Joined: 23 Feb 2016, 10:43

Re: What's the best way to do sprite sheet animation?

11 Aug 2017, 15:33

Thanks @sfernandez,

Another thing related to sprite sheet animation. Does it possible to combine Viewbox and Viewport in ImageBrush? I'd like to use "trim" function to remove the transparency around sprite inside TexturePacker to reduce texture size.

My sheet file just like this:
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ImageBrush x:Key="Burn_01" ImageSource="Burn.png" Viewbox="269,153,133,82" ViewboxUnits="Absolute" Viewport="10,118,133,82" ViewportUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_02" ImageSource="Burn.png" Viewbox="265,237,131,121" ViewboxUnits="Absolute" Viewport="8,79,131,121" ViewportUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_03" ImageSource="Burn.png" Viewbox="1,367,128,142" ViewboxUnits="Absolute" Viewport="11,58,128,142" ViewportUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_04" ImageSource="Burn.png" Viewbox="133,186,130,144" ViewboxUnits="Absolute" Viewport="11,56,130,144" ViewportUnits="Absolute" TileMode="None" Stretch="None"/>

</ResourceDictionary>
But not only the right sprite, but also the texture around being shown.
So does it possible to achieve this? My sample files is attached.
Burn.zip
(61.37 KiB) Downloaded 88 times
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: What's the best way to do sprite sheet animation?

11 Aug 2017, 17:44

But not only the right sprite, but also the texture around being shown.
It is something we are aware of, it isn't correctly implemented in our renderer yet. Please create a ticket in our bugtracker and add this sample data.
So does it possible to achieve this? My sample files is attached.
Yes, it is possible by modifying the target surface size (the Rectangle) to the sprite size, as I suggested in the previous post. You have to do it in the animation as follows:
<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="./BurnSheet.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <Storyboard x:Key="Run" RepeatBehavior="Forever">
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Burn" Storyboard.TargetProperty="Fill">
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.0" Value="{StaticResource Burn_01}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.1" Value="{StaticResource Burn_02}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="{StaticResource Burn_03}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{StaticResource Burn_04}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{StaticResource Burn_05}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{StaticResource Burn_06}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.6" Value="{StaticResource Burn_07}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.7" Value="{StaticResource Burn_08}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{StaticResource Burn_09}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.9" Value="{StaticResource Burn_10}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:1.0" Value="{StaticResource Burn_11}" />
                    <DiscreteObjectKeyFrame KeyTime="0:0:1.1" Value="{StaticResource Burn_12}" />
                </ObjectAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Burn" Storyboard.TargetProperty="Width">
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.0" Value="133" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.1" Value="131" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.2" Value="128" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.3" Value="130" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.4" Value="133" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.5" Value="131" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.6" Value="130" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.7" Value="128" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.8" Value="120" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.9" Value="103" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.0" Value="93" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.1" Value="83" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Burn" Storyboard.TargetProperty="Height">
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.0" Value="82" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.1" Value="121" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.2" Value="142" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.3" Value="144" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.4" Value="170" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.5" Value="183" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.6" Value="179" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.7" Value="150" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.8" Value="142" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:0.9" Value="112" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.0" Value="95" />
                    <DiscreteDoubleKeyFrame KeyTime="0:0:1.1" Value="38" />
                </DoubleAnimationUsingKeyFrames>
                <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="Burn" Storyboard.TargetProperty="Margin">
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.0" Value="10,118,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.1" Value="8,79,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.2" Value="11,58,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.3" Value="11,56,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.4" Value="9,30,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.5" Value="10,17,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.6" Value="11,21,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.7" Value="12,35,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.8" Value="13,31,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:0.9" Value="24,30,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:1.0" Value="34,39,0,0" />
                    <DiscreteThicknessKeyFrame KeyTime="0:0:1.1" Value="42,80,0,0" />
                </ThicknessAnimationUsingKeyFrames>
            </Storyboard>
        </ResourceDictionary>
    </UserControl.Resources>
    <UserControl.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource Run}" />
        </EventTrigger>
    </UserControl.Triggers>
    <Viewbox>
        <Grid Width="150" Height="200">
            <Rectangle x:Name="Burn"/>
        </Grid>
    </Viewbox>
</UserControl>
And removing the Viewport info from the atlas:
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ImageBrush x:Key="Burn_01" ImageSource="Burn.png" Viewbox="269,153,133,82" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_02" ImageSource="Burn.png" Viewbox="265,237,131,121" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_03" ImageSource="Burn.png" Viewbox="1,367,128,142" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_04" ImageSource="Burn.png" Viewbox="133,186,130,144" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_05" ImageSource="Burn.png" Viewbox="134,1,133,170" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_06" ImageSource="Burn.png" Viewbox="1,1,131,183" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_07" ImageSource="Burn.png" Viewbox="1,186,130,179" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_08" ImageSource="Burn.png" Viewbox="269,1,128,150" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_09" ImageSource="Burn.png" Viewbox="131,367,120,142" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_10" ImageSource="Burn.png" Viewbox="253,360,103,112" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_11" ImageSource="Burn.png" Viewbox="358,360,93,95" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>
    <ImageBrush x:Key="Burn_12" ImageSource="Burn.png" Viewbox="358,457,83,38" ViewboxUnits="Absolute" TileMode="None" Stretch="None"/>

</ResourceDictionary>
 
weilitao
Topic Author
Posts: 22
Joined: 23 Feb 2016, 10:43

Re: What's the best way to do sprite sheet animation?

12 Aug 2017, 15:03

Thanks, I have submitted a bug here(https://bugs.noesisengine.com/view.php?id=1130). Hope this bug can be fixed then we can make TexturePacker to produce resource xaml more efficient.
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: What's the best way to do sprite sheet animation?

16 Aug 2017, 12:02

It is a bit complex due to shader complexity but it is something we have in mind.

Who is online

Users browsing this forum: Google [Bot] and 2 guests