Framebased animation sequences
I've talked a lot about how to make things move, but haven't spent a lot of time dealing with actual frame-based animation. This is the kind of animation that comes to mind when you think of how classic animation is created. A series of frames is drawn, each one slightly different. As you flip through the frames, the slight changes from frame to frame create the illusion of motion. Depending upon your approach to using Silverlight, you have a few choices in how you decide to implement your own frame-based animations. Because of the flexibility, we will explore three different ways to create frame-based animations.
Let's begin by taking a look at the character we'll be animating. Figure 4-19 shows a series of poses for a duck. In the first pose, the wings are up. The second pose shows the wings in mid-flap, and the final pose shows the wings down. To make the flap animation, we'll create an animation that moves forward through the frames, then moves backward, and then repeats.
- Figure 4-19. The duck poses that will animate into a wing flap cycle
This is one of those situations where having an illustrator or animator handy is useful, because getting the motion to look right if an animation is longer than a few frames can be a little tricky.
The first method for creating frame-based animations is done entirely with a storyboard. This technique is great if you're a designer or just prefer to stick entirely to Blend to create your applications. In your project, you create a new user control that will be the animated item. In the user control, a Canvas container is created, into which the poses for the action you're creating are placed. Since most objects are made up of many paths, it makes organization easier to place each pose inside of its own descriptively named canvas.
Open the DiscreteFrameBasedAnimation project to build this example. The project contains the MainPage.xaml file, as well as a Duck user control that is in the Duck.xaml file. Open the Duck, xaml file and take a look at how the object is organized. There is a main container canvas named DuckFlyingPoses, inside of which are three more canvases, each of which contains a pose for the duck. The WingsUp canvas has the duck with its wings up—the leftmost pose shown in Figure 4-20. The WingsMid pose is shown in the center, and WingsDown is on the right. The poses are spaced equally horizontally.
1. Click the DuckFlyingPoses canvas. Notice how the canvas is just large enough to contain a single duck pose—in this case, the WingsUp pose.
2. Create a new storyboard named FlapWings, and move the play head to .3 seconds.
3. In the Objects and Timeline list, click WingsUp, and then Ctrl-click WingsMid and WingsDown. All three poses should be selected.
4. On the Transform pane of the Properties panel, type -300 into the X field. All three poses will slide to the left 300 pixels.
5. Move the play head to .6 seconds.
6. With all three poses still selected, enter -600 into the X field on the Transform pane.
7. Play the animation.
Not quite what you expected, right? All three duck poses simply slide to the left, and you're wondering if you missed something in the instructions. It's doing what it's supposed to—we're not quite done yet!
Currently, the animation is at a point where the duck's wings started in the up position, pushed through the mid position, and are now at the down position. To complete the flap cycle, we need to work back through the poses in the opposite direction.
8. Move the timeline play head to .9.
9. Enter -300 into the X field on the Transform pane.
10. Move the timeline play head to 1.2 seconds.
11. Enter 0 into the X transform field. The canvases will be back in their original positions at this point.
At this point, playing the timeline will continue to give you some unexpected results, as the duck poses simply slide back and forth along the x axis. In fact, it doesn't look much like the duck is flying at all.
What we need to finish off our animation is a tool that can help us change between poses only when a keyframe is reached, rather than smoothly interpolating the motion between the frames like we're currently seeing.
Are you with me here? The tool we need is the reliable discrete keyframe that we discussed earlier. Remember that discrete keyframes hold their position until the next keyframe is reached, at which time the object being animated jumps to the position in the next keyframe.
12. To change the type of keyframe being used to a discrete keyframe, hold down the Ctrl key, and click all 12 of the keyframe markers on the timeline.
13. With all the markers selected, right-click and select Hold In from the pop-up menu, as shown in Figure 4-20. Alternatively, you could switch to XAML mode and edit the storyboard by hand to use DiscreteDoubleKeyFrames rather than EasingDoubleKeyFrames. Either way, once the change has been made, playing the storyboard again has it looking a little more like what we were expecting—the poses jump from keyframe to keyframe rather than sliding. We're almost done!
- Figure 4-20. Change the keyframes in the animation so that they become DiscreteDoubleKeyFrames.
The last thing needed to finish off this particular animation is a clipping path applied to the DuckFlyingPoses Canvas in order to hide the poses that are positioned outside of the main canvas. Assuming the canvas was sized appropriately prior to having the poses added, this is easy to do.
14. Close the FlapWings storyboard.
15. Click the DuckFlyingPoses Canvas to select it.
16. The DuckFlyingPoses Canvas is 257X130. Double-click the Rectangle icon in the toolbox to add a rectangle to the project.
17. In the Width field on the Layout pane, enter 257. For Height, enter 130. The new rectangle now covers the canvas, as shown in Figure 4-21.
18. With the rectangle selected in the Objects and Timeline list, Ctrl-click the DuckFlyingPoses Canvas so that both are selected.
19. Right-click the selected group and choose Path > Make Clipping Path from the pop-up menu.
- Figure 4-21. Create a clipping region over the container canvas to hide the poses that are not in view. Now when the FlapWings storyboard is opened and played, there is a nice flapping animation.
20. The animation seems a little slow and needs to be sped up a bit. Switch to XAML view and scroll up to find the storyboard. Add a SpeedRatio property to the storyboard and set it to play the storyboard twice as fast as it does by default. You can go up or down with the SpeedRatio value depending upon what you need to do with your animation. For now, SpeedRatio="2" will do.
21. We also know that this will be a repeating animation, so add a RepeatBehavior property to the storyboard as well. At this point, the opening tag for the storyboard looks like the following:
<Storyboard x:Name="FlapWings" SpeedRatio="2" RepeatBehavior="Forever">
The duck is flying and looks pretty good in Blend, but how do we put it to work in our application? All that's necessary is to create an instance of the user control, add it to the root canvas, and start the animation. We'll start the storyboard in the Duck user control. Every time the duck is added to an application, it will begin flapping automatically.
22. Press Ctrl+S to save the project. On the Project panel in Blend, expand Duck.xaml so you can see the Duck.xaml.cs file. Right-click Duck.xaml.cs, and select Edit in Visual Studio.
23. Just after the InitializeComponentQ; line, add this.FlapWings.BeginQ;. This line tells Silverlight to start the FlapWings storyboard each time a Duck object is instanced. The this keyword always means "this object"—since we're calling FlapWings.Begin() from inside the Duck object, saying this.FlapWings.Begin() tells Silverlight to play the animation for this object.
24. Next, open the MainPage.xaml.es file for editing in Visual Studio.
25. Just before the MainPageQ constructor, create an instance of the Duck object called MyDuck. Duck MyDuck = new DuckQ;
26. Because this duck isn't moving relative to the underlying canvas, it needs to be positioned where we can get a good look at it—200,200 seems like as good a spot as any. Place the following three lines of code after the InitializeComponentQ; code. This will position the duck at 200,200, and add it to the LayoutRoot Canvas so that it is visible within the application.
MyDuck.SetValue(Canvas.LeftProperty, 200.00); MyDuck.SetValue(Canvas.TopProperty, 200.00); LayoutRoot.Children.Add(MyDuck);
Press F5 to compile and run the program. You should get a white canvas with the duck flapping away. Want another duck that's not working quite as hard? No problem! Keep working in the MainPage. xaml.es file.
27. Create a new instance of the Duck user control: Duck SlowDuck = new DuckQ;
28. To separate the ducks a bit, position this one at 300,300. Before adding it to the canvas, however, tell Silverlight you want the FlapWings animation of SlowDuck to have a SpeedRatio of l, meaning that this duck will flap one-half as fast as the first duck.
SlowDuck.SetValue(Canvas.LeftProperty, 300.00); SlowDuck.SetValue(Canvas.TopProperty, 300.00); SlowDuck.FlapWings.SpeedRatio = 1; LayoutRoot.Children.Add(SlowDuck);
Now when the project runs, there are two ducks: one is flapping frantically, while the other takes her sweet time.
What's that? Now you want a whole flock of ducks? No problem!
29. Start by declaring a random number generator above the MainPageQ constructor. Random Rng = new RandomQ;
30. Create a function that accepts an integer argument and uses it to generate the specified number of ducks. Here, the ducks are placed at random positions and given a random flap speed between 1 and 3.
private void MakeDucks(int NumDucks) {
Duck NewDuck = new Duck(); Point Position = new Point(Rng.NextDouble() * (LayoutRoot.Width - NewDuck.Width), Rng.NextDouble() * (LayoutRoot.Height -NewDuck.Height)); Canvas.SetLeft(NewDuckj Position.X); Canvas.SetTop(NewDuckj Position.Y); int Speed = Rng.Next(l,3); NewDuck.FlapWings.SpeedRatio = Speed; LayoutRoot.Children.Add(NewDuck);
31. To call this function and use it to create 20 ducks in addition to the 2 we already have, add the code MakeDucks(20); to the MainPage() constructor. Changing the number inside the parentheses will change the number of ducks that are added to the application.
The full code for this project is in the DiscreteFrameBasedCompleted project. There are some comments in the code that explain how to enable the MakeDucks() function shown previously so you can see it in action.
Post a comment