tags:

views:

320

answers:

1

Hi All,

I need to create at runtime a series of images on the screen, these images are all letters of the alphabet (PNG, 32x32), these images must look like they are "waving" up and down and rotating slightly too. (Almost like a Mexican wave)

The issue is that the images are NOT all added one after another at start up, but rather when the user hits keys on the keyboard.

For example, I might have the letter "A" (so A.png) on the screen, I would like to animate it so that it rotates from 0 to 20 after 1 second, and 20 to -20 after 2 seconds and back to 0 after 1 more second.

This I can do no worries.

But when the users hit another key on the keyboard ("L" for example), I want to add the "L" to the wave at the right offset and rotation to "A" so that it looks like a nice wave.

At the moment I have this animation, (which I know is not right, and also its defined in XAML which I cannot really do, because this is a runtime based thing)

<Storyboard x:Key="Storyboard1" AutoReverse="False" RepeatBehavior="Forever">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
         <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0" KeySpline="0,0,0.7,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
         <SplineDoubleKeyFrame KeyTime="00:00:01" Value="20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03" Value="-20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04" Value="0" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
         <SplineDoubleKeyFrame KeyTime="00:00:01" Value="-20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03" Value="20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04" Value="0" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image_Copy" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
         <SplineDoubleKeyFrame KeyTime="00:00:01.2600000" Value="20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03.2600000" Value="-20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04.2600000" Value="-5" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image_Copy" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
         <SplineDoubleKeyFrame KeyTime="00:00:01.2600000" Value="-20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03.2600000" Value="20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04.2600000" Value="5" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image_Copy1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
         <SplineDoubleKeyFrame KeyTime="00:00:01.5200000" Value="20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03.5200000" Value="-20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04.5200000" Value="-10" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image_Copy1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
         <SplineDoubleKeyFrame KeyTime="00:00:01.5200000" Value="-20" KeySpline="0,0,0.7,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:03.5200000" Value="20" KeySpline="0.17,0,0.6,1"/>
         <SplineDoubleKeyFrame KeyTime="00:00:04.5200000" Value="10" KeySpline="0.16,0,1,1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>

So any help here would be greatly appreciated!

Cheers, Mark

A: 

You do need to approach the problem in C#, rather than XAML. Animations are defined using the same named classes.

An approach you can consider is to place a StackPanel with Horizontal positioning. As the user types a letter, you need to take several steps:

  • Add an Image to the StackPanel containing the new letter.
  • Create a sequence of animations, a single Storyboard, that will perform one sequence of the wave.

Creating the animation will be a matter of looping through each control in StackPanel.Children, create the proper offset based on what element it is, and add it to the Storyboard.

When adding a new letter, you need to stop the previous animation. Save it to a local variable and stop it appropriately. For a smooth transition to the next letter, you could complete the current "pass", and then change the RepeatBehavior so it's no longer "Forever". Once it's complete, start your new storyboard that incorporates the new letter.

// ... Once you've added a new letter ...
storyboard.RepeatBehavior = new RepeatBehavior(0);
storyboard.Completed += storyboardCompleted;

private void storyboardCompleted(object o, EventArgs e)
{
  // Stop the storyboard, and start your new storyboard.
}
Will Eddins
thanks for the advice, so far one of the biggest issues I can see is that when I get the offset of the previous letter, how do I know if its moving up or down?
Mark
Also, would creating a new storyboard for each letter be out of the question in terms of performance? (ill be needing around 150 letters at its maximum)
Mark
I don't think it would necessarily matter... but remember, you have to start each storyboard one at a time. If you want a wave effect, it'll be easy to get them out of sync.
Will Eddins
yeah that is true, any thoughts on knowing which way one is moving? Perhaps have an event fire on each animation within the Storyboard, which tracks the previous and current positions?
Mark
I don't think you'd even need to. You could effectively make a loop where the loop makes 1 animation that bounces/rotates a letter. For each letter, offset all the times by few milliseconds/seconds, and they should go in order.
Will Eddins
I think I follow you, are you talking about beginning each new animation at an offset ahead of the last one?
Mark
Just doing some reading and I dont think you can tell an animation to start at a specific time in its life time. You can set the BeginTime but thats more of a delay time. I need it to play instantly and give it an offset time (ideally)
Mark