Animation Primer

Before reading this primer, you should first browse through the rest of the material in the Microsoft® DirectAnimation® documentation, especially the Programmer's Guide and the Guide to Samples, to learn the basic concepts of DirectAnimation. Then come back to read this section.

As you have learned from the rest of the documentation, you can use DirectAnimation to create static images on Web pages or add new media types to HTML content, or just for the media integration and consistent programming model that help simplify application development. However, if you are using DirectAnimation only for that, you are missing out on many other features the DirectAnimation animation engine provides.

This primer discusses how to use animation features and addresses common issues and questions brought up by DirectAnimation developers. The purpose is to make sure you can exploit all that is made available to you through DirectAnimation. If you find that a topic is confusing or not covered in sufficient depth, you can contact us through through the newsgroup on the Microsoft Public News Server at microsoft.public.multimedia.directx.danimation.programming. Your comments and suggestions will be incorporated in the future.

This primer is intended to bring together the different concepts described throughout the DirectAnimation documentation. Many other topics and uses could be covered, but this should suffice to get you going in the right direction.

This primer contains the following sections. Because these topics build on each other, it helps to read them in order.

Time in DirectAnimation

As is evident from other articles in the documentation, DirectAnimation is a time-based API. All the behavior constructs have an inherent notion of time. This allows for animations that are scalable, because the content will be consistent in terms of a timeline, regardless of the performance of the playback platform.

If you are familiar with some of the authoring tools that expose a frame-based model, or if you are considering developing a tool or content that relies on this model, the DirectAnimation continuous-time model can accommodate your needs. One of the advantages of the DirectAnimation continuous-time model is that it enables you to build frame-based models on top of it (the same is not true if you wanted to build a continuous-time model on top of a frame-based system). So, given the key role that time plays in the DirectAnimation world, this primer starts by examining the role of timelines.

Timelines

A timeline, in DirectAnimation, refers to the progress of time for a behavior. When a behavior starts, its timeline starts at zero. As a result, each behavior has its own notion of time, which is its local time. A behavior's local time is exposed through a behavior called LocalTime, accessible through the DAStatics object. The LocalTime object enables you to use a behavior's time as part of its own animation. The concept of LocalTime enables you to take a behavior and move it to different points in the global timeline, without affecting how the behavior plays. This is traditionally the model presented by authoring tools.

But, when do behaviors, and their times, start? When you start one of the DirectAnimation controls through the Start method or a DAView object through its StartModel method, all behaviors that don't depend on events are started immediately, with their individual timelines starting at zero. You can delay when a behavior starts by using constructs such as Until or Sequence. Take a look at the following example.

stringImg1 =
   m.StringImageAnim(m.LocalTime.ToString(3),
   m.defaultfont.size(60).color(m.Red));
// This image behavior will play first.

stringImg2 =
   m.StringImageAnim(m.LocalTime.ToString(3),
   m.defaultfont.size(60).color(m.Green));
// This image behavior will play second.

changingString =
   m.Until(stringImg1, m.LeftButtonDown, stringImg2);
// The second image plays after the click event.

Click the Show Sample button to start the following sample. After the sample is running, when you click it you will see the red string behavior transition to the green string behavior, and time, displayed in green, will start at zero. This is because the LocalTime for the green behavior starts at zero, after that behavior gets started (which in this case is due to the mouse click). This primer will keep referring back to and modifying this example.

In this sample, the code relies on an event to control the transition and the start of a behavior, the green string. Events are discussed in more detail later. An alternative to using events is to use the Sequence construct. Sequence enables you to tie the start of one behavior to the end of another one. But, before sequences are discussed, the length or duration of behaviors needs to be examined, so that you can determine when behaviors end.

Duration of Behaviors

All behaviors have a duration, usually referred to as their natural duration. Most behaviors' natural durations are infinite, meaning that they never end. For example, an image behavior created from a SolidColorImage never ends. However, some behaviors do have a finite natural duration; for example, sound and movie behaviors have a length associated with them.

Many times, it is useful to give an infinite behavior a fixed duration. You can do this by using the Duration method, as seen in the following:

myImg = m.SolidColorImage(m.Red).Duration(5.5);
// This image is now 5.5 seconds long.

You can also use Duration method to cut short or lengthen a behavior's duration.

shortImg = myImg.Duration(3);
// The image from the previous example now has a duration
// of 3 seconds.

longImg = myImg.Duration(10);
// The image from the previous example now lasts for
// 10 seconds.

When you lengthen a behavior's duration, you are holding that behavior's final value. For example, a movie's image transitions to black when the movie ends. Lengthening the duration of a movie results in a black image being displayed for the remainder of the duration. For sound behaviors, the end value is silence. These concepts apply to all behaviors, including number behaviors. In the following example, a number behavior interpolates from 0 to 3 linearly over 4 seconds. Its natural duration is 4 seconds.

myNumber = m.interpolate(0,3,4);
// interpolate from 0 to 3 over 4 seconds

You can make this number last longer, by specifying a new duration:

longerNumber = myNumber.Duration(10);
// longer duration number

The value of longerNumber after 4 seconds (the end of the interpolation) is going to hold at 3, its final value.

Sequencing Behaviors

Now that you understand behaviors' durations, consider the Sequence construct. The first example, dealing with images from strings, is rewritten here using Sequence instead of Until.

stringImg1 =
   m.StringImageAnim(m.LocalTimeToString(3),
   m.defaultfont.size(60).color(m.Red));
// This image behavior will play first.

stringImg2 =
   m.StringImageAnim(m.LocalTimeToString(3),
   m.defaultfont.size(60).color(m.Green));
// This image behavior will play second.

stringImgSeq = m.Sequence(stringImg1, stringImg2);
// This will not work as desired.

In the preceding example, given that the natural durations for both stringImg1 and stringImg2 are infinite, you would never see the second string appear, because the first one would never end. Here is a case where you would have to use the Duration method. Say that you want the first string to be displayed for 2.8 seconds and then transition to the second string. You could achieve this by setting the first string's duration to 2.8.

stringImg1Finite = stringImg1.Duration(2.8);

You can now use this behavior with a finite duration in the sequence and have it perform as expected.

stringImgSeq = m.Sequence(stringImg1Finite, stringImg2);
// Note that stringImg2 still lasts forever.

If you are dealing with objects that already have a finite duration (sounds and movies), you can just use them in a sequence without having to specify a duration.

soundTrack = m.sequence(sound1,sound2);
// Sound 1 will play, followed by sound 2, followed by silence.

Natural duration for sounds and movies did not work for versions prior to the version released as part of Microsoft® DirectX® media 6.x and Microsoft Internet Explorer 5. If you need to build content that is backward compatible, you should specify the duration even for objects that have a finite natural duration. Thus, the previous example using sound would be as follows:

soundTrack =
m.Sequence( sound1.DurationAnim(sound1Import.Duration), sound2);
//for backward compatibility with Internet Explorer 4.x run time

Changing the Content in an Animation

You have seen how to use either Until or Sequence constructs to change the content of an animation by relying on events or a behavior's duration. Another way to accomplish this is through the use of a ModifiableBehavior. You can think of a ModifiableBehavior as a placeholder for other behaviors of the same type. A ModifiableBehavior holds one behavior at a time, and its current behavior can be changed through the SwitchTo method. Note that you can only switch to a behavior of the same type as the original behavior used to create the ModifiableBehavior.

modifiableColor = m.ModifiableBehavior(m.Red);
// Given an initial color value, this modifiable behavior can
// hold only color behaviors from now on.

rectImg = m.Rect(100,100).Fill(m.DefaultLineStyle,modifiableColor);
// This creates a rectangle with an initial color of red.

At any time, you can cause the color to change, as shown in the following example.

modifiableColor.SwitchTo(m.Blue);
// This causes the color of the rectangle to change to blue.

How would you use this? A basic use is to rely on modifiable behaviors, instead of Until or Sequence, when you need to drive the animation from a change that happens outside the animation content. In general, if a change is triggered by another change in the animation itself or the change is time-dependent it is more efficient and better for synchronization to use the Until or Sequence constructs.

If you think of an animation as a sequence of images or behaviors, with your code controlling the transition from one frame to another, modifiable behaviors should provide a good base to build upon. You can think of the animation's scene as a ModifiableBehavior, where each frame represents a new value for that ModifiableBehavior.

Every time a behavior is switched, the behavior is considered to start and its timeline starts from 0, as seen in the following example. Click the Show Sample button to start this sample. The upper red oval and the lower blue rectangle increase in size with time. Click the Switch To Oval button to change the lower object from a blue rectangle to a red oval and note that the size is maintained.

However, sometimes you don't want a behavior to restart when switched. This brings up the concept of RunOnce.

RunOnce Behaviors

Now look at an example where you are watching the progress of several behaviors over time. In the following example, every click on the green area causes a flower to grow. The example reuses the same flower, inserting it into the animation's graph at the location specified by the mouse click. In this case, you want each new flower object's timeline to restart at zero, so that you see the flower growing at each new location.

However, say that you have a sample with several objects changing over time, and you allow the end-user to hide some of the objects and focus on only one or a few. Furthermore, say that you show and hide the behaviors by switching to an EmptyImage, as shown in the following example.

interestingObject = m.ModifiableBehavior(timeChangingImg);

When you need to hide the object, call the following:

interestingObject.SwitchTo(m.EmptyImage);

When you need to show the object, call the following:

interestingObject.SwitchTo(timeChangingImg);

The preceding code above would almost work, except for the fact that the timeChangingImg behavior would start back from zero every time it was switched in. To avoid this, specify that the timeChangingImg should be started only once in the animation, as follows:

timeChangingImg = timeChangingImg.RunOnce();

From now on, when timeChangingImg is switched in, it continues with its timeline as if it had never gone away (or in other words, it follows the global timeline).

Events and Predicates

You saw previously how to use events to cause transitions for Until constructs. Events are very powerful tools, not only because they can bring user actions into the animation content, but also because they can be used to express relationships between behaviors. Events can be very simple, such as the event caused by the click of the mouse, or they can be triggered by complex statements (predicates), or even arbitrarily triggered by your application or content.

In the following example, the color of the objects change when the distance between their centers is less than 1 centimeter.

The key constructs in this example are the following two lines.

distanceCondition =
m.LT(m.abs(m.Sub(circlePosition,rectPosition)),m.DANumber(0.01));

changingColor = m.Cond(distanceCondition, m.Red, m.Blue);

Instead of using a predicate, you can also trigger an event from outside the animation through an application-triggered event. In this case, the changingColor line in the preceding example would change to the following:

colorBvr = m.Until(m.Red,changeColorEv,m.Blue);

The changeColorEv would be defined as:

changeColorEv = m.AppTriggeredEvent();

This example would need some external way to cause the event to fire, for example through some logic expressed in script:

m.TriggerEvent(changeColorEv, m.DANumber(0));

Playing with Time

You already know that a behavior's timeline starts at zero, and that every behavior has a duration. If you want to accelerate, slow down, stop, or revert a behavior, you can use the SubstituteTime method. SubstituteTime can take a constant value, which causes time to stop at that point, or it can take an expression that evaluates time.

For example, given a movie's image behavior, movieImg, you can stop the image at 12 seconds into the movie by doing the following:

movieImg = movieImport.Image;

stoppedImg = movieImg.SubstituteTime(12);

If you wanted to make the movie run at twice its original speed, you could express that as follows:

fasterImg = movieImg.SubstituteTime(
m.Mul( m.DANumber(2), m.LocalTime));

To make the movie go backward, you could do it as follows:

backwardsImg = movieImg.SubstituteTime(
m.Sub(movieImport.Duration,m.LocalTime));

Note that in the preceding example dealing with faster playback, you could have easily made the speed of playback dependent on an event, as shown in the following:

movieSpeed =
m.Until(m.DANumber(1),m.LeftButtonDown,m.DANumber(2));

fasterImg = movieImg.SubstituteTime(m.Integral(movieSpeed));


Top of Page Top of Page
© 2000 Microsoft and/or its suppliers. All rights reserved. Terms of Use.