Exploring the Microsoft Client Continuum

Procedural Animation

Most designers have their wake up moment with programming Flash when they finally understand the power of onEnterFrame() to be interactive in a way that is impossible with timeline based tweens. The Flash metaphor is one of a movie, with a master timeline that always run and every individual MovieClip being capable of having its own internal timeline running in parallel as well. In fact, you really can't get around it. A timeline is tightly coupled to every MovieClip, even if that timeline is only one frame long. But harnessing the constant and repetitive power of code attached to this onEnterFrame event gives you unprecedented and dynamic control that leaves sequential animations in the dust.

When using onEnterFrame() to control multiple animations on stage, you will usually first decide if you want one onEnterFrame() on the primary KeyFrame controlling all the "dumb" MovieClips, or if you want each MovieClip to be "smart" and calculate its own motion. Often, either solution would work so it may come down to developer preference. So let's look at both techniques and see how to duplicate them in Silverlight.

Duplicating a Single onEnterFrame() Manager

Here is a sample Flash movie that controls its particles with a single onEnterFrame() on the first KeyFrame.

As with our previous Flash examples, this single frame project has a dot movieClip exported for ActionScript in the Library and the following code on the main stage:

So to duplicate this in Silverlight, we prepare our environment the same way we did in the Animation Lesson. Create a Silverlight Project with Web Hosting option named Lesson03_a, and prepare Page.xaml.

The Page.xaml modifications include:

  1. Convert the default Grid tag to a Canvas tag with desired background color of #333333;
  2. Set the Width and Height of the User Control tag in Page.xaml to match the SWF: 600 x 300.
  3. Add a Loaded event handler to the User Control tag, automatically creating the function definition in the code behind file Page.xaml.cs

Page.xaml should now look like this:

Create a new User Control class for our Silverlight Project called Dot.xaml. It will be identical to the Dot.xaml we created in Lesson 02, only we don't need the Storyboard this time. After you remove the Width and Height values of Dot.xaml's User Control tag, don't forget to switch LayoutRoot to be a Canvas instead of the default Grid and remove its background color.

Adding the Ellipse shape for the particle, Dot.xaml should look like this:

Press F7 to get to the Dot.xaml.cs code behind file. As we learned in the Animation Lesson, we're going to add the X and Y public properties to our User Control to make positioning them easier. We also need some public variables for the velocity, but we can't just add new properties on the fly like we did with vx and vy in our ActionScript 1.0 code above (and like Silverlight's C#, ActionScript 3.0 frowns on this as well). So these variables should also be defined ahead of time in our code behind file.

Therefore, our modified Dot.xaml.cs file now looks like this:

Now that our visuals have been defined and the User Control prepared, we can get to the main chunk of code, duplicating the onEnterFrame() functionality in Silverlight. Open Page.xaml.cs and go to the Loaded() event handler we added from XAML when we first created this project.

We'll do this in two steps. First I'll show you the basic structure of a repeating Storyboard loop, and then we'll put in the animation logic specific to this project. To duplicate an onEnterFrame() type structure in Silverlight, you can do it like this:

Line 17 defines the Storyboard object and we can initialize it in our Loaded() handler as shown in Line 26. We add a Completed event which our Storyboard will call after this empty Storyboard is done. Since an empty Storyboard has no parameters or targets or duration defined, when we tell it to Begin() on Line 29, it will fire its Completed event one frame later. So to have this logic fire repeatedly, simply put another Begin() request inside the completed event. Also note, before we can use the Storyboard object, we need to add it to our current User Control's Resources collection. You can add the Storyboard and give it a resource name at the same time.

Now that we have an empty Storyboard acting as an onEnterFrame, let's add our dots in the Loaded event:

And put our animation logic in the Storyboard's Completed event like this:

And we're done. Notice that we can use a foreach command if we're sure that the only children in our parent canvas are of the correct type. That's why in the subsequent lessons in which we handle dynamic elements like this, we will create an empty Canvas tag in our XAML to act as a dedicated parent. Also, Silverlight operates at a default 60 fps versus the Flash default of 12 fps, so we reduced the amount of drift we added to our velocity variables in Line 47 and 48. Notice the notation for creating and using random numbers is also different, though the range principle is the same. In both Flash and Silverlight, if you subtract a random number up to a specific value (n) from another random number up to that same value (n), you create a negative n to positive n result set range. So in Line 47 and Line 48, we assign a decimal value from -1.0 to +1.0 for the vx and vy properties of each dot. These velocity values are added to their current position every frame. We slow down these particles gradually with some friction in Lines 61 and 62.

Here is the Silverlight result:

Having Each Element Control Its own Behavior

The above Flash example worked well because there was a predefined number of MovieClips we could reference in our single animation loop. But there are other times when we want each element to be added or removed independently over a longer period of time, making a single looping function harder to implement. For those types of animations, it's sometimes easier to put the onEnterFrame behavior on each movieClip directly.

So if we changed our first Flash example to act more like a particle emitter by replacing its current code with this:

We get a Flash movie that looks like this:

Instead of one onEnterFrame() event on the primary KeyFrame controlling all the movieClips, each movieClip has its onEnterFrame() event defined at the point of creation.

For our Silverlight rebuild, we no longer need the Storyboard object on Page.xaml.cs since we will move it directly into our Dot.xaml.cs User Control. But as we did in the Flash code above, we need to add a MouseMove event handler to Page.xaml.cs.

There are no changes in our Dot.xaml mark up, and Dot.xaml.cs has the same X, Y, vx, and vy properties as in the previous lesson. But we will add a Storyboard and count variable to the file so that each dot User Control can define its own animation behavior like so:

This makes it easier to see the biggest conceptual difference between using an onEnterFrame in Flash and a Storyboard Completed event in Silverlight. In Flash, the onEnterFrame event will loop indefinitely until you explicitly stop the behavior. On the other hand, the Storyboard Completed event fires only once, so you need to explicitly restart the storyboard if you want the handler to loop once per frame. By using a local count variable, though, we an programmatically monitor a kill condition once we want the User Control to remove itself.

Here is the Silverlight rebuild:

The choice to use a single function that loops through all animated elements on screen and adjusts them individually or to have each visual element update itself is a choice usually decided by weighing animation objectives and learned coding behavior. But regardless of how you like to solve the problem in Flash, using a Storyboard Completed event gives you a similar development framework to translate your animation logic into Silverlight.

I want to point out, though, that being able to easily and quickly iterate through a Canvas.Children collection and pull out strongly typed User Controls as shown above makes the difference between the two approaches more one of personal choice. Instead of using an eval() lookup or looping through an unpredictable list of unique names in Flash, pulling each child out strongly typed can make things much smoother.

Now that we have covered some of the basics of mouse events, adding User Controls dynamically, and creating animation code with Storyboard objects, lets start putting it all together and adding some images.

Have a question or comment on this article? Have a suggestion for new content?
Send your feedback.
Microsoft Communities